@defra/forms-engine-plugin 5.0.0-alpha.2 → 5.0.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.public/javascripts/application.min.js +1 -1
- package/.public/javascripts/application.min.js.LICENSE.txt +7 -0
- package/.public/javascripts/application.min.js.map +1 -1
- package/.public/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.LICENSE.txt +7 -0
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/javascripts/file-upload.js +6 -3
- package/.server/client/javascripts/file-upload.js.map +1 -1
- package/.server/client/javascripts/geospatial-map.d.ts +153 -5
- package/.server/client/javascripts/geospatial-map.js +157 -77
- package/.server/client/javascripts/geospatial-map.js.map +1 -1
- package/.server/client/javascripts/govuk.js +2 -1
- package/.server/client/javascripts/govuk.js.map +1 -1
- package/.server/client/javascripts/location-map.d.ts +44 -0
- package/.server/client/javascripts/location-map.js +54 -5
- package/.server/client/javascripts/location-map.js.map +1 -1
- package/.server/client/javascripts/map-constants.d.ts +3 -0
- package/.server/client/javascripts/map-constants.js +4 -0
- package/.server/client/javascripts/map-constants.js.map +1 -0
- package/.server/client/javascripts/map.d.ts +10 -0
- package/.server/client/javascripts/map.js +42 -0
- package/.server/client/javascripts/map.js.map +1 -1
- package/.server/client/javascripts/maps.d.ts +5 -0
- package/.server/client/javascripts/maps.js +6 -0
- package/.server/client/javascripts/maps.js.map +1 -0
- package/.server/client/javascripts/shared.d.ts +1 -4
- package/.server/client/javascripts/shared.js +1 -4
- package/.server/client/javascripts/shared.js.map +1 -1
- package/.server/client/javascripts/sssi-dataset.d.ts +18 -20
- package/.server/client/javascripts/sssi-dataset.js +37 -39
- package/.server/client/javascripts/sssi-dataset.js.map +1 -1
- package/.server/client/stylesheets/maps.scss +4 -0
- package/.server/client/stylesheets/shared.scss +1 -5
- package/.server/server/constants.d.ts +2 -0
- package/.server/server/constants.js +2 -0
- package/.server/server/constants.js.map +1 -1
- package/.server/server/plugins/engine/__stubs__/definitions.d.ts +29 -0
- package/.server/server/plugins/engine/__stubs__/definitions.js +125 -0
- package/.server/server/plugins/engine/__stubs__/definitions.js.map +1 -0
- package/.server/server/plugins/engine/components/AutocompleteField.d.ts +9 -3
- package/.server/server/plugins/engine/components/AutocompleteField.js +12 -0
- package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
- package/.server/server/plugins/engine/components/CheckboxesField.d.ts +21 -0
- package/.server/server/plugins/engine/components/CheckboxesField.js +30 -5
- package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
- package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js +11 -6
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DatePartsField.d.ts +6 -3
- package/.server/server/plugins/engine/components/DatePartsField.js +12 -7
- package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.d.ts +5 -2
- package/.server/server/plugins/engine/components/DeclarationField.js +6 -4
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
- package/.server/server/plugins/engine/components/Details.d.ts +1 -0
- package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +33 -2
- package/.server/server/plugins/engine/components/EastingNorthingField.js +110 -54
- package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
- package/.server/server/plugins/engine/components/EmailAddressField.d.ts +4 -1
- package/.server/server/plugins/engine/components/EmailAddressField.js +2 -1
- package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/FileUploadField.d.ts +21 -0
- package/.server/server/plugins/engine/components/FileUploadField.js +35 -3
- package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
- package/.server/server/plugins/engine/components/FormComponent.d.ts +5 -1
- package/.server/server/plugins/engine/components/FormComponent.js +5 -2
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/GeospatialField.d.ts +23 -0
- package/.server/server/plugins/engine/components/GeospatialField.js +33 -9
- package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
- package/.server/server/plugins/engine/components/Html.d.ts +1 -0
- package/.server/server/plugins/engine/components/InsetText.d.ts +1 -0
- package/.server/server/plugins/engine/components/LatLongField.d.ts +32 -2
- package/.server/server/plugins/engine/components/LatLongField.js +85 -48
- package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
- package/.server/server/plugins/engine/components/List.d.ts +1 -0
- package/.server/server/plugins/engine/components/ListFormComponent.d.ts +1 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +8 -2
- package/.server/server/plugins/engine/components/LocationFieldBase.js +25 -6
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +12 -3
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js +21 -13
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
- package/.server/server/plugins/engine/components/Markdown.d.ts +1 -0
- package/.server/server/plugins/engine/components/Markdown.js +1 -1
- package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
- package/.server/server/plugins/engine/components/MonthYearField.d.ts +5 -2
- package/.server/server/plugins/engine/components/MonthYearField.js +13 -9
- package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
- package/.server/server/plugins/engine/components/MultilineTextField.d.ts +1 -0
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +4 -3
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/NotificationBanner.d.ts +1 -0
- package/.server/server/plugins/engine/components/NumberField.d.ts +5 -0
- package/.server/server/plugins/engine/components/NumberField.js +16 -0
- package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/OsGridRefField.d.ts +103 -1
- package/.server/server/plugins/engine/components/OsGridRefField.js +13 -3
- package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
- package/.server/server/plugins/engine/components/PaymentField.d.ts +3 -0
- package/.server/server/plugins/engine/components/PaymentField.js +17 -6
- package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
- package/.server/server/plugins/engine/components/SelectField.d.ts +1 -0
- package/.server/server/plugins/engine/components/SelectionControlField.d.ts +1 -0
- package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +1 -0
- package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -0
- package/.server/server/plugins/engine/components/UkAddressField.js +23 -8
- package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/YesNoField.d.ts +5 -2
- package/.server/server/plugins/engine/components/YesNoField.js +17 -8
- package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/components.js +3 -3
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +8 -1
- package/.server/server/plugins/engine/components/helpers/geospatial.js +56 -15
- package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/index.d.ts +7 -0
- package/.server/server/plugins/engine/components/helpers/index.js +13 -1
- package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
- package/.server/server/plugins/engine/components/types.d.ts +1 -0
- package/.server/server/plugins/engine/components/types.js.map +1 -1
- package/.server/server/plugins/engine/errors.d.ts +49 -0
- package/.server/server/plugins/engine/errors.js +75 -0
- package/.server/server/plugins/engine/errors.js.map +1 -0
- package/.server/server/plugins/engine/form-availability.d.ts +3 -2
- package/.server/server/plugins/engine/form-availability.js +3 -2
- package/.server/server/plugins/engine/form-availability.js.map +1 -1
- package/.server/server/plugins/engine/form-context.js +2 -2
- package/.server/server/plugins/engine/form-context.js.map +1 -1
- package/.server/server/plugins/engine/helpers.d.ts +22 -2
- package/.server/server/plugins/engine/helpers.js +44 -5
- package/.server/server/plugins/engine/helpers.js.map +1 -1
- package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +4 -1
- package/.server/server/plugins/engine/i18n/buildValidationMessages.js +31 -7
- package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -1
- package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +4 -4
- package/.server/server/plugins/engine/i18n/createFormTranslator.js +33 -4
- package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -1
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +1 -1
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +9 -0
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -1
- package/.server/server/plugins/engine/i18n/form.d.ts +13 -0
- package/.server/server/plugins/engine/i18n/form.js +35 -0
- package/.server/server/plugins/engine/i18n/form.js.map +1 -0
- package/.server/server/plugins/engine/i18n/languages.d.ts +10 -0
- package/.server/server/plugins/engine/i18n/languages.js +19 -0
- package/.server/server/plugins/engine/i18n/languages.js.map +1 -0
- package/.server/server/plugins/engine/i18n/translations/cy.json +192 -9
- package/.server/server/plugins/engine/i18n/translations/en-GB.json +125 -7
- package/.server/server/plugins/engine/i18n/types.d.ts +3 -0
- package/.server/server/plugins/engine/i18n/types.js.map +1 -1
- package/.server/server/plugins/engine/index.d.ts +4 -0
- package/.server/server/plugins/engine/index.js +4 -0
- package/.server/server/plugins/engine/index.js.map +1 -1
- package/.server/server/plugins/engine/models/FormModel.d.ts +0 -4
- package/.server/server/plugins/engine/models/FormModel.js +19 -17
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js +9 -4
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/models/unavailable-view-model.d.ts +11 -2
- package/.server/server/plugins/engine/models/unavailable-view-model.js +23 -4
- package/.server/server/plugins/engine/models/unavailable-view-model.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +3 -5
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +2 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js +2 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +7 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +56 -10
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +7 -3
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +10 -4
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js +2 -1
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js +3 -3
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +24 -3
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
- package/.server/server/plugins/engine/types/schema.js +1 -0
- package/.server/server/plugins/engine/types/schema.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +5 -0
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/unavailable-response.js +5 -2
- package/.server/server/plugins/engine/unavailable-response.js.map +1 -1
- package/.server/server/plugins/engine/views/components/_location-field-base.html +4 -2
- package/.server/server/plugins/engine/views/components/fileuploadfield.html +1 -1
- package/.server/server/plugins/engine/views/components/geospatialfield.html +1 -0
- package/.server/server/plugins/engine/views/components/multilinetextfield.html +12 -1
- package/.server/server/plugins/engine/views/components/osgridreffield.html +4 -1
- package/.server/server/plugins/engine/views/components/paymentfield.html +1 -1
- package/.server/server/plugins/engine/views/components/ukaddressfield.html +1 -1
- package/.server/server/plugins/engine/views/file-upload.html +1 -1
- package/.server/server/plugins/engine/views/partials/preview-banner.html +3 -1
- package/.server/server/plugins/engine/views/unavailable.html +14 -11
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.d.ts +9 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js +17 -0
- package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
- package/.server/server/plugins/payment/helper.d.ts +11 -1
- package/.server/server/plugins/payment/helper.js +18 -2
- package/.server/server/plugins/payment/helper.js.map +1 -1
- package/.server/server/plugins/payment/helper.test.js +2 -1
- package/.server/server/plugins/payment/helper.test.js.map +1 -1
- package/.server/server/plugins/payment/service.d.ts +2 -1
- package/.server/server/plugins/payment/service.js +5 -2
- package/.server/server/plugins/payment/service.js.map +1 -1
- package/.server/server/plugins/payment/service.test.js +7 -3
- package/.server/server/plugins/payment/service.test.js.map +1 -1
- package/.server/server/plugins/payment/types.d.ts +4 -0
- package/.server/server/plugins/payment/types.js +1 -0
- package/.server/server/plugins/payment/types.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/models/index.d.ts +249 -3
- package/.server/server/plugins/postcode-lookup/models/index.js +87 -33
- package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/routes/index.d.ts +15 -1
- package/.server/server/plugins/postcode-lookup/routes/index.js +47 -15
- package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/routes/index.test.js +84 -0
- package/.server/server/plugins/postcode-lookup/routes/index.test.js.map +1 -0
- package/.server/server/plugins/postcode-lookup/types.d.ts +12 -0
- package/.server/server/plugins/postcode-lookup/types.js +6 -1
- package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
- package/.server/server/utils/type-utils.d.ts +1 -2
- package/.server/server/utils/type-utils.js +0 -3
- package/.server/server/utils/type-utils.js.map +1 -1
- package/.server/server/utils/utils.d.ts +6 -0
- package/.server/server/utils/utils.js +18 -1
- package/.server/server/utils/utils.js.map +1 -1
- package/.server/server/utils/utils.test.js +21 -1
- package/.server/server/utils/utils.test.js.map +1 -1
- package/package.json +20 -5
- package/src/client/javascripts/file-upload.js +11 -3
- package/src/client/javascripts/geospatial-map.js +176 -81
- package/src/client/javascripts/govuk.js +2 -0
- package/src/client/javascripts/location-map.js +60 -4
- package/src/client/javascripts/map-constants.js +3 -0
- package/src/client/javascripts/map.js +47 -0
- package/src/client/javascripts/maps.js +5 -0
- package/src/client/javascripts/shared.js +1 -4
- package/src/client/javascripts/sssi-dataset.js +39 -41
- package/src/client/stylesheets/maps.scss +4 -0
- package/src/client/stylesheets/shared.scss +1 -5
- package/src/server/constants.js +2 -0
- package/src/server/plugins/engine/__stubs__/definitions.ts +155 -0
- package/src/server/plugins/engine/components/AutocompleteField.ts +13 -0
- package/src/server/plugins/engine/components/CheckboxesField.ts +38 -5
- package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
- package/src/server/plugins/engine/components/ComponentCollection.ts +16 -11
- package/src/server/plugins/engine/components/DatePartsField.ts +20 -9
- package/src/server/plugins/engine/components/DeclarationField.ts +7 -6
- package/src/server/plugins/engine/components/EastingNorthingField.ts +185 -89
- package/src/server/plugins/engine/components/EmailAddressField.ts +2 -1
- package/src/server/plugins/engine/components/FileUploadField.ts +44 -3
- package/src/server/plugins/engine/components/FormComponent.ts +6 -5
- package/src/server/plugins/engine/components/GeospatialField.ts +47 -9
- package/src/server/plugins/engine/components/LatLongField.ts +128 -58
- package/src/server/plugins/engine/components/LocationFieldBase.ts +30 -7
- package/src/server/plugins/engine/components/LocationFieldHelpers.ts +28 -14
- package/src/server/plugins/engine/components/Markdown.ts +2 -3
- package/src/server/plugins/engine/components/MonthYearField.ts +20 -15
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -3
- package/src/server/plugins/engine/components/NumberField.ts +21 -1
- package/src/server/plugins/engine/components/OsGridRefField.ts +22 -3
- package/src/server/plugins/engine/components/PaymentField.ts +15 -5
- package/src/server/plugins/engine/components/UkAddressField.ts +30 -7
- package/src/server/plugins/engine/components/YesNoField.ts +17 -9
- package/src/server/plugins/engine/components/helpers/components.ts +3 -3
- package/src/server/plugins/engine/components/helpers/geospatial.ts +84 -21
- package/src/server/plugins/engine/components/helpers/index.ts +19 -0
- package/src/server/plugins/engine/components/types.ts +1 -0
- package/src/server/plugins/engine/errors.ts +78 -0
- package/src/server/plugins/engine/form-availability.ts +8 -2
- package/src/server/plugins/engine/form-context.ts +4 -2
- package/src/server/plugins/engine/helpers.ts +52 -5
- package/src/server/plugins/engine/i18n/buildValidationMessages.ts +16 -8
- package/src/server/plugins/engine/i18n/createFormTranslator.ts +62 -11
- package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +7 -1
- package/src/server/plugins/engine/i18n/form.ts +54 -0
- package/src/server/plugins/engine/i18n/languages.ts +19 -0
- package/src/server/plugins/engine/i18n/translations/cy.json +192 -9
- package/src/server/plugins/engine/i18n/translations/en-GB.json +125 -7
- package/src/server/plugins/engine/i18n/types.ts +3 -0
- package/src/server/plugins/engine/index.ts +7 -0
- package/src/server/plugins/engine/models/FormModel.ts +21 -17
- package/src/server/plugins/engine/models/SummaryViewModel.ts +6 -5
- package/src/server/plugins/engine/models/unavailable-view-model.ts +26 -5
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +3 -6
- package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -1
- package/src/server/plugins/engine/outputFormatters/machine/v2.ts +3 -0
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +60 -9
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +10 -5
- package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -4
- package/src/server/plugins/engine/pageControllers/helpers/pages.ts +2 -1
- package/src/server/plugins/engine/pageControllers/helpers/submission.ts +6 -3
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +29 -4
- package/src/server/plugins/engine/types/schema.ts +1 -0
- package/src/server/plugins/engine/types.ts +5 -0
- package/src/server/plugins/engine/unavailable-response.ts +6 -2
- package/src/server/plugins/engine/views/components/_location-field-base.html +4 -2
- package/src/server/plugins/engine/views/components/fileuploadfield.html +1 -1
- package/src/server/plugins/engine/views/components/geospatialfield.html +1 -0
- package/src/server/plugins/engine/views/components/multilinetextfield.html +12 -1
- package/src/server/plugins/engine/views/components/osgridreffield.html +4 -1
- package/src/server/plugins/engine/views/components/paymentfield.html +1 -1
- package/src/server/plugins/engine/views/components/ukaddressfield.html +1 -1
- package/src/server/plugins/engine/views/file-upload.html +1 -1
- package/src/server/plugins/engine/views/partials/preview-banner.html +3 -1
- package/src/server/plugins/engine/views/unavailable.html +14 -11
- package/src/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
- package/src/server/plugins/nunjucks/filters/index.js +1 -0
- package/src/server/plugins/payment/helper.js +22 -2
- package/src/server/plugins/payment/service.js +6 -2
- package/src/server/plugins/payment/types.js +1 -0
- package/src/server/plugins/postcode-lookup/models/index.js +75 -43
- package/src/server/plugins/postcode-lookup/routes/index.js +73 -16
- package/src/server/plugins/postcode-lookup/types.js +6 -1
- package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
- package/src/server/utils/type-utils.ts +1 -11
- package/src/server/utils/utils.js +19 -1
|
@@ -13,11 +13,13 @@ export class PaymentField extends FormComponent {
|
|
|
13
13
|
constructor(def, props) {
|
|
14
14
|
super(def, props);
|
|
15
15
|
this.options = def.options;
|
|
16
|
+
this.def = def;
|
|
16
17
|
const paymentStateSchema = joi.object({
|
|
17
18
|
paymentId: joi.string().required(),
|
|
18
19
|
reference: joi.string().required(),
|
|
19
20
|
amount: joi.number().required(),
|
|
20
21
|
description: joi.string().required(),
|
|
22
|
+
descriptionInEng: joi.string().optional(),
|
|
21
23
|
uuid: joi.string().uuid().required(),
|
|
22
24
|
formId: joi.string().required(),
|
|
23
25
|
isLivePayment: joi.boolean().required(),
|
|
@@ -52,6 +54,12 @@ export class PaymentField extends FormComponent {
|
|
|
52
54
|
payload
|
|
53
55
|
} = context;
|
|
54
56
|
const viewModel = super.getViewModel(context);
|
|
57
|
+
const {
|
|
58
|
+
translator
|
|
59
|
+
} = context;
|
|
60
|
+
const {
|
|
61
|
+
tComponent
|
|
62
|
+
} = translator;
|
|
55
63
|
|
|
56
64
|
// Payload is pre-populated from state if a payment has already been made
|
|
57
65
|
const paymentState = this.isPaymentState(payload[this.name]) ? payload[this.name] : undefined;
|
|
@@ -63,7 +71,7 @@ export class PaymentField extends FormComponent {
|
|
|
63
71
|
return {
|
|
64
72
|
...viewModel,
|
|
65
73
|
amount: formatCurrency(amount),
|
|
66
|
-
description: this.options.description,
|
|
74
|
+
description: tComponent(this.def, 'paymentDescription') || this.options.description,
|
|
67
75
|
paymentState
|
|
68
76
|
};
|
|
69
77
|
}
|
|
@@ -157,10 +165,11 @@ export class PaymentField extends FormComponent {
|
|
|
157
165
|
const {
|
|
158
166
|
model
|
|
159
167
|
} = args.controller;
|
|
160
|
-
const language = resolveLanguage(request);
|
|
161
168
|
const {
|
|
162
|
-
|
|
163
|
-
|
|
169
|
+
language,
|
|
170
|
+
t,
|
|
171
|
+
tComponent
|
|
172
|
+
} = model.createTranslator(resolveLanguage(request));
|
|
164
173
|
const state = await args.controller.getState(request);
|
|
165
174
|
const {
|
|
166
175
|
baseUrl
|
|
@@ -182,7 +191,7 @@ export class PaymentField extends FormComponent {
|
|
|
182
191
|
if (resolvedAmount === 0) {
|
|
183
192
|
return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER);
|
|
184
193
|
}
|
|
185
|
-
const description = options.description;
|
|
194
|
+
const description = tComponent(args.component, 'paymentDescription') || options.description;
|
|
186
195
|
const slug = `/${model.basePath}`;
|
|
187
196
|
const payCallbackUrl = `${baseUrl}/payment-callback?uuid=${uuid}`;
|
|
188
197
|
const paymentPageUrl = args.sourceUrl;
|
|
@@ -194,7 +203,8 @@ export class PaymentField extends FormComponent {
|
|
|
194
203
|
const amountInPence = Math.round(resolvedAmount * 100);
|
|
195
204
|
const payment = await paymentService.createPayment(amountInPence, description, payCallbackUrl, reference, isLivePayment, {
|
|
196
205
|
formId,
|
|
197
|
-
slug
|
|
206
|
+
slug,
|
|
207
|
+
language
|
|
198
208
|
}, prefilledEmail);
|
|
199
209
|
if (!payment) {
|
|
200
210
|
const message = isLivePayment ? t('components.paymentField.cannotTakePayment') : t('components.paymentField.testApiKey');
|
|
@@ -208,6 +218,7 @@ export class PaymentField extends FormComponent {
|
|
|
208
218
|
reference,
|
|
209
219
|
amount: resolvedAmount,
|
|
210
220
|
description,
|
|
221
|
+
descriptionInEng: options.description,
|
|
211
222
|
paymentId: payment.paymentId,
|
|
212
223
|
componentName,
|
|
213
224
|
returnUrl: summaryUrl,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaymentField.js","names":["randomUUID","StatusCodes","joi","logger","COMPONENT_STATE_ERROR","FormComponent","createError","getPluginOptions","PaymentErrorTypes","PaymentPreAuthError","PaymentSubmissionError","createPaymentService","formatCurrency","resolveLanguage","PaymentField","isAppendageStateSingleObject","constructor","def","props","options","paymentStateSchema","object","paymentId","string","required","reference","amount","number","description","uuid","formId","isLivePayment","boolean","preAuth","status","valid","createdAt","isoDate","unknown","label","formSchema","stateSchema","getPaymentStateFromState","state","value","name","isPaymentState","undefined","getDisplayStringFromState","_translator","getViewModel","context","payload","viewModel","paymentState","Array","isArray","isState","getFormValue","getContextValueFromState","getAllPossibleErrors","baseErrors","type","template","advancedSettingsErrors","resolveAmount","model","conditionalAmounts","length","condition","conditions","warn","fn","dispatcher","request","h","args","componentName","component","controller","language","t","createTranslator","getState","baseUrl","server","summaryUrl","basePath","existingPaymentState","redirect","code","SEE_OTHER","isLive","isPreview","formsService","services","paymentService","$$__referenceNumber","resolvedAmount","slug","payCallbackUrl","paymentPageUrl","sourceUrl","prefilledEmail","userConfirmationEmail","userConfirmationEmailAddress","amountInPence","Math","round","payment","createPayment","message","govukError","yar","flash","url","pathname","search","sessionData","returnUrl","failureUrl","set","paymentUrl","onSubmit","_metadata","PaymentIncomplete","capture","getPaymentStatus","checkPaymentAmount","markPaymentCaptured","PaymentExpired","captured","capturePayment","updatedState","Date","toISOString","page","currentState","mergeState"],"sources":["../../../../../src/server/plugins/engine/components/PaymentField.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\n\nimport {\n type FormMetadata,\n type PaymentFieldComponent\n} from '@defra/forms-model'\nimport { StatusCodes } from 'http-status-codes'\nimport joi, { type ObjectSchema } from 'joi'\n\nimport { logger } from '~/src/server/common/helpers/logging/logger.js'\nimport { COMPONENT_STATE_ERROR } from '~/src/server/constants.js'\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport {\n createError,\n getPluginOptions\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport {\n PaymentErrorTypes,\n PaymentPreAuthError,\n PaymentSubmissionError\n} from '~/src/server/plugins/engine/pageControllers/errors.js'\nimport {\n type FormContext,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type FormState,\n type FormStateValue,\n type FormSubmissionState,\n type PaymentExternalArgs\n} from '~/src/server/plugins/engine/types.js'\nimport {\n createPaymentService,\n formatCurrency\n} from '~/src/server/plugins/payment/helper.js'\nimport { resolveLanguage } from '~/src/server/utils/utils.js'\n\nexport class PaymentField extends FormComponent {\n declare options: PaymentFieldComponent['options']\n declare formSchema: ObjectSchema\n declare stateSchema: ObjectSchema\n isAppendageStateSingleObject = true\n\n constructor(\n def: PaymentFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n this.options = def.options\n\n const paymentStateSchema = joi\n .object({\n paymentId: joi.string().required(),\n reference: joi.string().required(),\n amount: joi.number().required(),\n description: joi.string().required(),\n uuid: joi.string().uuid().required(),\n formId: joi.string().required(),\n isLivePayment: joi.boolean().required(),\n preAuth: joi\n .object({\n status: joi\n .string()\n .valid('success', 'failed', 'started')\n .required(),\n createdAt: joi.string().isoDate().required()\n })\n .required()\n })\n .unknown(true)\n .label(this.label)\n\n this.formSchema = paymentStateSchema\n // 'required()' forces the payment page to be invalid until we have valid payment state\n // i.e. the user will automatically be directed back to the payment page\n // if they attempt to access future pages when no payment entered yet\n this.stateSchema = paymentStateSchema.required()\n }\n\n /**\n * Gets the PaymentState from form submission state\n */\n getPaymentStateFromState(\n state: FormSubmissionState\n ): PaymentState | undefined {\n const value = state[this.name]\n return this.isPaymentState(value) ? value : undefined\n }\n\n getDisplayStringFromState(\n state: FormSubmissionState,\n _translator: Translator\n ): string {\n const value = this.getPaymentStateFromState(state)\n\n if (!value) {\n return ''\n }\n\n return `${formatCurrency(value.amount)} - ${value.description}`\n }\n\n getViewModel(context: RenderContext) {\n const { payload } = context\n const viewModel = super.getViewModel(context)\n\n // Payload is pre-populated from state if a payment has already been made\n const paymentState = this.isPaymentState(payload[this.name] as unknown)\n ? (payload[this.name] as unknown as PaymentState)\n : undefined\n\n // Use payment state amount if pre-authorized, otherwise use default.\n // The page controller overrides this with the resolved conditional amount\n // using the full form state (which getViewModel doesn't have access to).\n const amount = paymentState?.amount ?? this.options.amount\n\n return {\n ...viewModel,\n amount: formatCurrency(amount),\n description: this.options.description,\n paymentState\n }\n }\n\n /**\n * Type guard to check if value is PaymentState\n */\n isPaymentState(value: unknown): value is PaymentState {\n return PaymentField.isPaymentState(value)\n }\n\n /**\n * Static type guard to check if value is PaymentState\n */\n static isPaymentState(value: unknown): value is PaymentState {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n const state = value as PaymentState\n return (\n typeof state.paymentId === 'string' &&\n typeof state.amount === 'number' &&\n typeof state.description === 'string'\n )\n }\n\n /**\n * Override base isState to validate PaymentState\n */\n isState(value?: FormStateValue | FormState): value is FormState {\n return this.isPaymentState(value)\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isPaymentState(value)\n ? (value as unknown as NonNullable<FormStateValue>)\n : undefined\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n return this.isPaymentState(state)\n ? `Reference: ${state.reference}\\nAmount: ${formatCurrency(state.amount)}`\n : ''\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return PaymentField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n {\n type: 'paymentRequired',\n template: 'Complete the payment to continue'\n }\n ],\n advancedSettingsErrors: []\n }\n }\n\n /**\n * Resolves the payment amount from conditional amounts configuration.\n * Evaluates conditions in order; first true condition wins.\n * Falls back to the default options.amount.\n */\n static resolveAmount(\n options: PaymentFieldComponent['options'],\n model: FormModel,\n state: FormState\n ): number {\n const { conditionalAmounts } = options\n\n if (!conditionalAmounts?.length) {\n return options.amount\n }\n\n for (const { condition, amount } of conditionalAmounts) {\n if (!model.conditions[condition]) {\n logger.warn(\n `[payment] Condition '${condition}' not found in form conditions. Skipping.`\n )\n continue\n }\n if (model.conditions[condition].fn(state)) {\n return amount\n }\n }\n\n return options.amount\n }\n\n /**\n * Dispatcher for external redirect to GOV.UK Pay\n */\n static async dispatcher(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n args: PaymentExternalArgs\n ): Promise<unknown> {\n const { options, name: componentName } = args.component\n const { model } = args.controller\n const language = resolveLanguage(request)\n const { t } = model.createTranslator(language)\n const state = await args.controller.getState(request)\n const { baseUrl } = getPluginOptions(request.server)\n const summaryUrl = `${baseUrl}/${model.basePath}/summary`\n\n const existingPaymentState = state[componentName]\n if (\n PaymentField.isPaymentState(existingPaymentState) &&\n existingPaymentState.preAuth?.status === 'success'\n ) {\n return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER)\n }\n\n const isLivePayment = args.isLive && !args.isPreview\n const formId = args.controller.model.formId\n const formsService = model.services.formsService\n const paymentService = await createPaymentService(\n isLivePayment,\n formId,\n formsService\n )\n\n const uuid = randomUUID()\n\n const reference = state.$$__referenceNumber as string\n const resolvedAmount = PaymentField.resolveAmount(options, model, state)\n\n // Zero-amount safety net (page skip should prevent this, but defensive)\n if (resolvedAmount === 0) {\n return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER)\n }\n\n const description = options.description\n\n const slug = `/${model.basePath}`\n\n const payCallbackUrl = `${baseUrl}/payment-callback?uuid=${uuid}`\n const paymentPageUrl = args.sourceUrl\n\n let prefilledEmail: string | undefined\n const userConfirmationEmail = state.userConfirmationEmailAddress\n if (typeof userConfirmationEmail === 'string' && userConfirmationEmail) {\n prefilledEmail = userConfirmationEmail\n }\n\n const amountInPence = Math.round(resolvedAmount * 100)\n const payment = await paymentService.createPayment(\n amountInPence,\n description,\n payCallbackUrl,\n reference,\n isLivePayment,\n { formId, slug },\n prefilledEmail\n )\n\n if (!payment) {\n const message = isLivePayment\n ? t('components.paymentField.cannotTakePayment')\n : t('components.paymentField.testApiKey')\n const govukError = createError(componentName, message)\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n return h\n .redirect(`${request.url.pathname}${request.url.search}`)\n .code(StatusCodes.SEE_OTHER)\n }\n\n const sessionData: PaymentSessionData = {\n uuid,\n formId,\n reference,\n amount: resolvedAmount,\n description,\n paymentId: payment.paymentId,\n componentName,\n returnUrl: summaryUrl,\n failureUrl: paymentPageUrl,\n isLivePayment\n }\n\n request.yar.set(`payment-${uuid}`, sessionData)\n\n return h.redirect(payment.paymentUrl).code(StatusCodes.SEE_OTHER)\n }\n\n /**\n * Called on form submission to capture the payment\n * @see https://docs.payments.service.gov.uk/delayed_capture/#delay-taking-a-payment\n */\n async onSubmit(\n request: FormRequestPayload,\n _metadata: FormMetadata,\n context: FormContext\n ): Promise<void> {\n const language = resolveLanguage(request)\n const { t } = this.model.createTranslator(language)\n\n // Zero-amount bypass — no capture needed\n const resolvedAmount = PaymentField.resolveAmount(\n this.options,\n this.model,\n context.state\n )\n if (resolvedAmount === 0) {\n return\n }\n\n const paymentState = this.getPaymentStateFromState(context.state)\n\n if (!paymentState) {\n throw new PaymentPreAuthError(\n this,\n t('components.paymentField.completePayment'),\n true,\n PaymentErrorTypes.PaymentIncomplete\n )\n }\n\n if (paymentState.capture?.status === 'success') {\n return\n }\n\n const { paymentId, isLivePayment, formId } = paymentState\n const formsService = this.model.services.formsService\n const paymentService = await createPaymentService(\n isLivePayment,\n formId,\n formsService\n )\n\n /**\n * @see https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle\n */\n const status = await paymentService.getPaymentStatus(\n paymentId,\n isLivePayment\n )\n\n PaymentSubmissionError.checkPaymentAmount(\n status.amount,\n resolvedAmount,\n this,\n t\n )\n\n if (status.state.status === 'success') {\n await this.markPaymentCaptured(request, paymentState)\n return\n }\n\n if (status.state.status !== 'capturable') {\n throw new PaymentPreAuthError(\n this,\n t('components.paymentField.paymentExpired'),\n true,\n PaymentErrorTypes.PaymentExpired\n )\n }\n\n const captured = await paymentService.capturePayment(\n paymentId,\n status.amount\n )\n\n if (!captured) {\n throw new PaymentPreAuthError(\n this,\n t('components.paymentField.submissionFailed'),\n false\n )\n }\n\n await this.markPaymentCaptured(request, paymentState)\n }\n\n /**\n * Updates payment state to mark capture as successful\n * This ensures we don't try to re-capture on submission retry\n */\n private async markPaymentCaptured(\n request: FormRequestPayload,\n paymentState: PaymentState\n ): Promise<void> {\n const updatedState: PaymentState = {\n ...paymentState,\n capture: {\n status: 'success',\n createdAt: new Date().toISOString()\n }\n }\n\n if (this.page) {\n const currentState = await this.page.getState(request)\n await this.page.mergeState(request, currentState, {\n [this.name]: updatedState\n })\n }\n }\n}\n\n/**\n * Session data stored when dispatching to GOV.UK Pay\n */\nexport interface PaymentSessionData {\n uuid: string\n formId: string\n reference: string\n amount: number\n description: string\n paymentId: string\n componentName: string\n returnUrl: string\n failureUrl: string\n isLivePayment: boolean\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"PaymentField.js","names":["randomUUID","StatusCodes","joi","logger","COMPONENT_STATE_ERROR","FormComponent","createError","getPluginOptions","PaymentErrorTypes","PaymentPreAuthError","PaymentSubmissionError","createPaymentService","formatCurrency","resolveLanguage","PaymentField","isAppendageStateSingleObject","constructor","def","props","options","paymentStateSchema","object","paymentId","string","required","reference","amount","number","description","descriptionInEng","optional","uuid","formId","isLivePayment","boolean","preAuth","status","valid","createdAt","isoDate","unknown","label","formSchema","stateSchema","getPaymentStateFromState","state","value","name","isPaymentState","undefined","getDisplayStringFromState","_translator","getViewModel","context","payload","viewModel","translator","tComponent","paymentState","Array","isArray","isState","getFormValue","getContextValueFromState","getAllPossibleErrors","baseErrors","type","template","advancedSettingsErrors","resolveAmount","model","conditionalAmounts","length","condition","conditions","warn","fn","dispatcher","request","h","args","componentName","component","controller","language","t","createTranslator","getState","baseUrl","server","summaryUrl","basePath","existingPaymentState","redirect","code","SEE_OTHER","isLive","isPreview","formsService","services","paymentService","$$__referenceNumber","resolvedAmount","slug","payCallbackUrl","paymentPageUrl","sourceUrl","prefilledEmail","userConfirmationEmail","userConfirmationEmailAddress","amountInPence","Math","round","payment","createPayment","message","govukError","yar","flash","url","pathname","search","sessionData","returnUrl","failureUrl","set","paymentUrl","onSubmit","_metadata","PaymentIncomplete","capture","getPaymentStatus","checkPaymentAmount","markPaymentCaptured","PaymentExpired","captured","capturePayment","updatedState","Date","toISOString","page","currentState","mergeState"],"sources":["../../../../../src/server/plugins/engine/components/PaymentField.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\n\nimport {\n type FormMetadata,\n type PaymentFieldComponent\n} from '@defra/forms-model'\nimport { StatusCodes } from 'http-status-codes'\nimport joi, { type ObjectSchema } from 'joi'\n\nimport { logger } from '~/src/server/common/helpers/logging/logger.js'\nimport { COMPONENT_STATE_ERROR } from '~/src/server/constants.js'\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport {\n createError,\n getPluginOptions\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport {\n PaymentErrorTypes,\n PaymentPreAuthError,\n PaymentSubmissionError\n} from '~/src/server/plugins/engine/pageControllers/errors.js'\nimport {\n type FormContext,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type FormState,\n type FormStateValue,\n type FormSubmissionState,\n type PaymentExternalArgs\n} from '~/src/server/plugins/engine/types.js'\nimport {\n createPaymentService,\n formatCurrency\n} from '~/src/server/plugins/payment/helper.js'\nimport { resolveLanguage } from '~/src/server/utils/utils.js'\n\nexport class PaymentField extends FormComponent {\n declare options: PaymentFieldComponent['options']\n declare formSchema: ObjectSchema\n declare stateSchema: ObjectSchema\n declare def: PaymentFieldComponent\n isAppendageStateSingleObject = true\n\n constructor(\n def: PaymentFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n this.options = def.options\n this.def = def\n\n const paymentStateSchema = joi\n .object({\n paymentId: joi.string().required(),\n reference: joi.string().required(),\n amount: joi.number().required(),\n description: joi.string().required(),\n descriptionInEng: joi.string().optional(),\n uuid: joi.string().uuid().required(),\n formId: joi.string().required(),\n isLivePayment: joi.boolean().required(),\n preAuth: joi\n .object({\n status: joi\n .string()\n .valid('success', 'failed', 'started')\n .required(),\n createdAt: joi.string().isoDate().required()\n })\n .required()\n })\n .unknown(true)\n .label(this.label)\n\n this.formSchema = paymentStateSchema\n // 'required()' forces the payment page to be invalid until we have valid payment state\n // i.e. the user will automatically be directed back to the payment page\n // if they attempt to access future pages when no payment entered yet\n this.stateSchema = paymentStateSchema.required()\n }\n\n /**\n * Gets the PaymentState from form submission state\n */\n getPaymentStateFromState(\n state: FormSubmissionState\n ): PaymentState | undefined {\n const value = state[this.name]\n return this.isPaymentState(value) ? value : undefined\n }\n\n getDisplayStringFromState(\n state: FormSubmissionState,\n _translator: Translator\n ): string {\n const value = this.getPaymentStateFromState(state)\n\n if (!value) {\n return ''\n }\n\n return `${formatCurrency(value.amount)} - ${value.description}`\n }\n\n getViewModel(context: RenderContext) {\n const { payload } = context\n const viewModel = super.getViewModel(context)\n const { translator } = context\n const { tComponent } = translator\n\n // Payload is pre-populated from state if a payment has already been made\n const paymentState = this.isPaymentState(payload[this.name] as unknown)\n ? (payload[this.name] as unknown as PaymentState)\n : undefined\n\n // Use payment state amount if pre-authorized, otherwise use default.\n // The page controller overrides this with the resolved conditional amount\n // using the full form state (which getViewModel doesn't have access to).\n const amount = paymentState?.amount ?? this.options.amount\n\n return {\n ...viewModel,\n amount: formatCurrency(amount),\n description:\n tComponent(this.def, 'paymentDescription') || this.options.description,\n paymentState\n }\n }\n\n /**\n * Type guard to check if value is PaymentState\n */\n isPaymentState(value: unknown): value is PaymentState {\n return PaymentField.isPaymentState(value)\n }\n\n /**\n * Static type guard to check if value is PaymentState\n */\n static isPaymentState(value: unknown): value is PaymentState {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n const state = value as PaymentState\n return (\n typeof state.paymentId === 'string' &&\n typeof state.amount === 'number' &&\n typeof state.description === 'string'\n )\n }\n\n /**\n * Override base isState to validate PaymentState\n */\n isState(value?: FormStateValue | FormState): value is FormState {\n return this.isPaymentState(value)\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isPaymentState(value)\n ? (value as unknown as NonNullable<FormStateValue>)\n : undefined\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n return this.isPaymentState(state)\n ? `Reference: ${state.reference}\\nAmount: ${formatCurrency(state.amount)}`\n : ''\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return PaymentField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n {\n type: 'paymentRequired',\n template: 'Complete the payment to continue'\n }\n ],\n advancedSettingsErrors: []\n }\n }\n\n /**\n * Resolves the payment amount from conditional amounts configuration.\n * Evaluates conditions in order; first true condition wins.\n * Falls back to the default options.amount.\n */\n static resolveAmount(\n options: PaymentFieldComponent['options'],\n model: FormModel,\n state: FormState\n ): number {\n const { conditionalAmounts } = options\n\n if (!conditionalAmounts?.length) {\n return options.amount\n }\n\n for (const { condition, amount } of conditionalAmounts) {\n if (!model.conditions[condition]) {\n logger.warn(\n `[payment] Condition '${condition}' not found in form conditions. Skipping.`\n )\n continue\n }\n if (model.conditions[condition].fn(state)) {\n return amount\n }\n }\n\n return options.amount\n }\n\n /**\n * Dispatcher for external redirect to GOV.UK Pay\n */\n static async dispatcher(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n args: PaymentExternalArgs\n ): Promise<unknown> {\n const { options, name: componentName } = args.component\n const { model } = args.controller\n const { language, t, tComponent } = model.createTranslator(\n resolveLanguage(request)\n )\n const state = await args.controller.getState(request)\n const { baseUrl } = getPluginOptions(request.server)\n const summaryUrl = `${baseUrl}/${model.basePath}/summary`\n\n const existingPaymentState = state[componentName]\n if (\n PaymentField.isPaymentState(existingPaymentState) &&\n existingPaymentState.preAuth?.status === 'success'\n ) {\n return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER)\n }\n\n const isLivePayment = args.isLive && !args.isPreview\n const formId = args.controller.model.formId\n const formsService = model.services.formsService\n const paymentService = await createPaymentService(\n isLivePayment,\n formId,\n formsService\n )\n\n const uuid = randomUUID()\n\n const reference = state.$$__referenceNumber as string\n const resolvedAmount = PaymentField.resolveAmount(options, model, state)\n\n // Zero-amount safety net (page skip should prevent this, but defensive)\n if (resolvedAmount === 0) {\n return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER)\n }\n\n const description =\n tComponent(args.component, 'paymentDescription') || options.description\n\n const slug = `/${model.basePath}`\n\n const payCallbackUrl = `${baseUrl}/payment-callback?uuid=${uuid}`\n const paymentPageUrl = args.sourceUrl\n\n let prefilledEmail: string | undefined\n const userConfirmationEmail = state.userConfirmationEmailAddress\n if (typeof userConfirmationEmail === 'string' && userConfirmationEmail) {\n prefilledEmail = userConfirmationEmail\n }\n\n const amountInPence = Math.round(resolvedAmount * 100)\n const payment = await paymentService.createPayment(\n amountInPence,\n description,\n payCallbackUrl,\n reference,\n isLivePayment,\n { formId, slug, language },\n prefilledEmail\n )\n\n if (!payment) {\n const message = isLivePayment\n ? t('components.paymentField.cannotTakePayment')\n : t('components.paymentField.testApiKey')\n const govukError = createError(componentName, message)\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n return h\n .redirect(`${request.url.pathname}${request.url.search}`)\n .code(StatusCodes.SEE_OTHER)\n }\n\n const sessionData: PaymentSessionData = {\n uuid,\n formId,\n reference,\n amount: resolvedAmount,\n description,\n descriptionInEng: options.description,\n paymentId: payment.paymentId,\n componentName,\n returnUrl: summaryUrl,\n failureUrl: paymentPageUrl,\n isLivePayment\n }\n\n request.yar.set(`payment-${uuid}`, sessionData)\n\n return h.redirect(payment.paymentUrl).code(StatusCodes.SEE_OTHER)\n }\n\n /**\n * Called on form submission to capture the payment\n * @see https://docs.payments.service.gov.uk/delayed_capture/#delay-taking-a-payment\n */\n async onSubmit(\n request: FormRequestPayload,\n _metadata: FormMetadata,\n context: FormContext\n ): Promise<void> {\n const language = resolveLanguage(request)\n const { t } = this.model.createTranslator(language)\n\n // Zero-amount bypass — no capture needed\n const resolvedAmount = PaymentField.resolveAmount(\n this.options,\n this.model,\n context.state\n )\n if (resolvedAmount === 0) {\n return\n }\n\n const paymentState = this.getPaymentStateFromState(context.state)\n\n if (!paymentState) {\n throw new PaymentPreAuthError(\n this,\n t('components.paymentField.completePayment'),\n true,\n PaymentErrorTypes.PaymentIncomplete\n )\n }\n\n if (paymentState.capture?.status === 'success') {\n return\n }\n\n const { paymentId, isLivePayment, formId } = paymentState\n const formsService = this.model.services.formsService\n const paymentService = await createPaymentService(\n isLivePayment,\n formId,\n formsService\n )\n\n /**\n * @see https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle\n */\n const status = await paymentService.getPaymentStatus(\n paymentId,\n isLivePayment\n )\n\n PaymentSubmissionError.checkPaymentAmount(\n status.amount,\n resolvedAmount,\n this,\n t\n )\n\n if (status.state.status === 'success') {\n await this.markPaymentCaptured(request, paymentState)\n return\n }\n\n if (status.state.status !== 'capturable') {\n throw new PaymentPreAuthError(\n this,\n t('components.paymentField.paymentExpired'),\n true,\n PaymentErrorTypes.PaymentExpired\n )\n }\n\n const captured = await paymentService.capturePayment(\n paymentId,\n status.amount\n )\n\n if (!captured) {\n throw new PaymentPreAuthError(\n this,\n t('components.paymentField.submissionFailed'),\n false\n )\n }\n\n await this.markPaymentCaptured(request, paymentState)\n }\n\n /**\n * Updates payment state to mark capture as successful\n * This ensures we don't try to re-capture on submission retry\n */\n private async markPaymentCaptured(\n request: FormRequestPayload,\n paymentState: PaymentState\n ): Promise<void> {\n const updatedState: PaymentState = {\n ...paymentState,\n capture: {\n status: 'success',\n createdAt: new Date().toISOString()\n }\n }\n\n if (this.page) {\n const currentState = await this.page.getState(request)\n await this.page.mergeState(request, currentState, {\n [this.name]: updatedState\n })\n }\n }\n}\n\n/**\n * Session data stored when dispatching to GOV.UK Pay\n */\nexport interface PaymentSessionData {\n uuid: string\n formId: string\n reference: string\n amount: number\n description: string\n descriptionInEng?: string\n paymentId: string\n componentName: string\n returnUrl: string\n failureUrl: string\n isLivePayment: boolean\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -69,6 +69,7 @@ export declare class UkAddressField extends FormComponent {
|
|
|
69
69
|
upload?: {
|
|
70
70
|
count: number;
|
|
71
71
|
summaryList: import("../../../../server/plugins/engine/types.js").SummaryList;
|
|
72
|
+
uploadingLabel?: string;
|
|
72
73
|
};
|
|
73
74
|
};
|
|
74
75
|
isState(value?: FormStateValue | FormState): value is UkAddressState;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { ComponentType } from '@defra/forms-model';
|
|
1
|
+
import { ComponentType, FormStatus } from '@defra/forms-model';
|
|
2
2
|
import lowerFirst from 'lodash/lowerFirst.js';
|
|
3
3
|
import { ComponentCollection } from "./ComponentCollection.js";
|
|
4
4
|
import { FormComponent, isFormState } from "./FormComponent.js";
|
|
5
5
|
import { TextField } from "./TextField.js";
|
|
6
|
+
import { getCachedPluginTranslator } from "../i18n/form.js";
|
|
7
|
+
import { getAvailableLanguages } from "../i18n/languages.js";
|
|
6
8
|
import { dispatch } from "../../postcode-lookup/routes/index.js";
|
|
7
9
|
import { resolveLanguage } from "../../../utils/utils.js";
|
|
8
10
|
export class UkAddressField extends FormComponent {
|
|
@@ -164,7 +166,7 @@ export class UkAddressField extends FormComponent {
|
|
|
164
166
|
text: label.text,
|
|
165
167
|
/**
|
|
166
168
|
* For screen readers, only hide legend visually. This can be overridden
|
|
167
|
-
* by single component
|
|
169
|
+
* by single component (see QuestionPageController and showTitle handling)
|
|
168
170
|
*/
|
|
169
171
|
classes: options.hideTitle ? 'govuk-visually-hidden' : 'govuk-fieldset__legend--m'
|
|
170
172
|
}
|
|
@@ -235,22 +237,35 @@ export class UkAddressField extends FormComponent {
|
|
|
235
237
|
static isUkAddress(value) {
|
|
236
238
|
return isFormState(value) && TextField.isText(value.addressLine1) && TextField.isText(value.town) && TextField.isText(value.postcode);
|
|
237
239
|
}
|
|
238
|
-
|
|
239
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
240
240
|
static async dispatcher(request, h, args) {
|
|
241
241
|
const {
|
|
242
242
|
controller,
|
|
243
243
|
component
|
|
244
244
|
} = args;
|
|
245
245
|
const language = resolveLanguage(request);
|
|
246
|
+
const availableLanguages = getAvailableLanguages(controller.model.def);
|
|
247
|
+
const languages = availableLanguages.length ? {
|
|
248
|
+
languages: availableLanguages
|
|
249
|
+
} : {};
|
|
250
|
+
const translator = await getCachedPluginTranslator(request, {
|
|
251
|
+
id: controller.model.formId
|
|
252
|
+
}, args.isLive ? FormStatus.Live : FormStatus.Draft, language);
|
|
253
|
+
const {
|
|
254
|
+
tComponent,
|
|
255
|
+
tForm
|
|
256
|
+
} = translator;
|
|
246
257
|
return dispatch(request, h, {
|
|
247
|
-
formName:
|
|
258
|
+
formName: tForm('title'),
|
|
259
|
+
formId: controller.model.formId,
|
|
260
|
+
formStatus: args.isLive ? FormStatus.Live : FormStatus.Draft,
|
|
261
|
+
componentId: component.id ?? 'unknown',
|
|
248
262
|
componentName: component.name,
|
|
249
|
-
componentHint: component
|
|
250
|
-
componentTitle: component
|
|
263
|
+
componentHint: tComponent(component, 'hint'),
|
|
264
|
+
componentTitle: tComponent(component, 'title') || controller.title,
|
|
251
265
|
step: args.actionArgs.step,
|
|
252
266
|
sourceUrl: args.sourceUrl,
|
|
253
|
-
language
|
|
267
|
+
language,
|
|
268
|
+
...languages
|
|
254
269
|
});
|
|
255
270
|
}
|
|
256
271
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UkAddressField.js","names":["ComponentType","lowerFirst","ComponentCollection","FormComponent","isFormState","TextField","dispatch","resolveLanguage","UkAddressField","constructor","def","props","name","options","isRequired","required","hideOptional","optionalText","hideTitle","collection","type","title","schema","classes","max","autocomplete","regex","parent","formSchema","stateSchema","getFormValueFromState","state","value","isState","undefined","getContextValueFromFormValue","Object","entries","filter","key","Boolean","map","getContextValueFromState","getDisplayStringFromFormValue","_translator","join","getDisplayStringFromState","translator","getViewErrors","errors","t","uniqueErrors","getErrors","error","index","self","findIndex","err","shouldUsePostcodeLookup","length","label","path","href","text","shortDescription","getViewModel","context","payload","viewModel","fieldset","hint","legend","id","attributes","components","uprn","at","Error","model","formGroup","usePostcodeLookup","isUkAddress","getAllPossibleErrors","ordnanceSurveyApiKey","baseErrors","template","advancedSettingsErrors","isText","addressLine1","town","postcode","dispatcher","request","h","args","controller","component","language","formName","componentName","componentHint","componentTitle","step","actionArgs","sourceUrl"],"sources":["../../../../../src/server/plugins/engine/components/UkAddressField.ts"],"sourcesContent":["import { ComponentType, type UkAddressFieldComponent } from '@defra/forms-model'\nimport { type ObjectSchema } from 'joi'\nimport lowerFirst from 'lodash/lowerFirst.js'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { TextField } from '~/src/server/plugins/engine/components/TextField.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type PostcodeLookupExternalArgs\n} from '~/src/server/plugins/engine/types.js'\nimport { dispatch } from '~/src/server/plugins/postcode-lookup/routes/index.js'\nimport { resolveLanguage } from '~/src/server/utils/utils.js'\n\nexport class UkAddressField extends FormComponent {\n declare options: UkAddressFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: UkAddressFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options } = def\n\n const isRequired = options.required !== false\n const hideOptional = !!options.optionalText\n const hideTitle = !!options.hideTitle\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.TextField,\n name: `${name}__uprn`,\n title: 'components.addressField.uprn',\n schema: {},\n options: {\n required: false,\n classes: 'hidden'\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__addressLine1`,\n title: 'components.addressField.line1',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-line1',\n required: isRequired,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__addressLine2`,\n title: 'components.addressField.line2',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-line2',\n required: false,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__town`,\n title: 'components.addressField.town',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-level2',\n classes: 'govuk-!-width-two-thirds',\n required: isRequired,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__county`,\n title: 'components.addressField.county',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-level1',\n required: false,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__postcode`,\n title: 'components.addressField.postcode',\n schema: {\n regex: '^[a-zA-Z]{1,2}\\\\d[a-zA-Z\\\\d]?\\\\s?\\\\d[a-zA-Z]{2}$'\n },\n options: {\n autocomplete: 'postal-code',\n classes: 'govuk-input--width-10',\n required: isRequired,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n }\n ],\n { ...props, parent: this }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return this.isState(value) ? value : undefined\n }\n\n getContextValueFromFormValue(value: UkAddressState | undefined) {\n if (!value) {\n return null\n }\n\n return Object.entries(value)\n .filter(([key, value]) => key !== 'uprn' && Boolean(value))\n .map(([, value]) => value)\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n getDisplayStringFromFormValue(\n value: UkAddressState | undefined,\n _translator: Translator\n ): string {\n return this.getContextValueFromFormValue(value)?.join(', ') ?? ''\n }\n\n getDisplayStringFromState(\n state: FormSubmissionState,\n translator: Translator\n ) {\n const value = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(value, translator)\n }\n\n /**\n * Returns one error per child field\n */\n getViewErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const { t } = translator\n\n const uniqueErrors = this.getErrors(translator, errors)?.filter(\n (error, index, self) =>\n index === self.findIndex((err) => err.name === error.name)\n )\n\n // When using postcode lookup, the address fields are hidden\n // so we replace any individual validation messages with a single one\n if (this.shouldUsePostcodeLookup() && uniqueErrors?.length) {\n const { name, label } = this\n\n return [\n {\n name,\n path: [name],\n href: `#${name}`,\n text: t('components.addressField.enterAddress', {\n shortDescription: lowerFirst(label)\n })\n }\n ]\n }\n\n return uniqueErrors\n }\n\n getViewModel(context: RenderContext) {\n const { payload, translator } = context\n const { collection, name, options } = this\n\n const viewModel = super.getViewModel(context)\n let { fieldset, hint, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n\n /**\n * For screen readers, only hide legend visually. This can be overridden\n * by single component {@link QuestionPageController | `showTitle` handling}\n */\n classes: options.hideTitle\n ? 'govuk-visually-hidden'\n : 'govuk-fieldset__legend--m'\n }\n }\n\n if (hint) {\n hint.id ??= `${name}-hint`\n fieldset.attributes ??= {\n 'aria-describedby': hint.id\n }\n }\n\n const components = collection.getViewModel(context)\n\n // Hide UPRN\n const uprn = components.at(0)\n\n if (!uprn) {\n throw new Error('No UPRN')\n }\n\n uprn.model.formGroup = { classes: 'app-hidden' }\n\n // Postcode lookup\n const usePostcodeLookup = this.shouldUsePostcodeLookup()\n\n const value = usePostcodeLookup\n ? this.getDisplayStringFromState(payload, translator)\n : undefined\n\n return {\n ...viewModel,\n value,\n fieldset,\n components,\n usePostcodeLookup\n }\n }\n\n isState(value?: FormStateValue | FormState): value is UkAddressState {\n return UkAddressField.isUkAddress(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return UkAddressField.getAllPossibleErrors()\n }\n\n private shouldUsePostcodeLookup() {\n return !!(this.options.usePostcodeLookup && this.model.ordnanceSurveyApiKey)\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: 'Enter address line 1' },\n { type: 'required', template: 'Enter town or city' },\n { type: 'required', template: 'Enter postcode' },\n { type: 'format', template: 'Enter valid postcode' }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isUkAddress(\n value?: FormStateValue | FormState\n ): value is UkAddressState {\n return (\n isFormState(value) &&\n TextField.isText(value.addressLine1) &&\n TextField.isText(value.town) &&\n TextField.isText(value.postcode)\n )\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n static async dispatcher(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n args: PostcodeLookupExternalArgs\n ) {\n const { controller, component } = args\n const language = resolveLanguage(request)\n\n return dispatch(request, h, {\n formName: controller.model.name,\n componentName: component.name,\n componentHint: component.hint,\n componentTitle: component.title || controller.title,\n step: args.actionArgs.step,\n sourceUrl: args.sourceUrl,\n language\n })\n }\n}\n\nexport interface UkAddressState extends Record<string, string> {\n uprn: string\n addressLine1: string\n addressLine2: string\n town: string\n county: string\n postcode: string\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"UkAddressField.js","names":["ComponentType","FormStatus","lowerFirst","ComponentCollection","FormComponent","isFormState","TextField","getCachedPluginTranslator","getAvailableLanguages","dispatch","resolveLanguage","UkAddressField","constructor","def","props","name","options","isRequired","required","hideOptional","optionalText","hideTitle","collection","type","title","schema","classes","max","autocomplete","regex","parent","formSchema","stateSchema","getFormValueFromState","state","value","isState","undefined","getContextValueFromFormValue","Object","entries","filter","key","Boolean","map","getContextValueFromState","getDisplayStringFromFormValue","_translator","join","getDisplayStringFromState","translator","getViewErrors","errors","t","uniqueErrors","getErrors","error","index","self","findIndex","err","shouldUsePostcodeLookup","length","label","path","href","text","shortDescription","getViewModel","context","payload","viewModel","fieldset","hint","legend","id","attributes","components","uprn","at","Error","model","formGroup","usePostcodeLookup","isUkAddress","getAllPossibleErrors","ordnanceSurveyApiKey","baseErrors","template","advancedSettingsErrors","isText","addressLine1","town","postcode","dispatcher","request","h","args","controller","component","language","availableLanguages","languages","formId","isLive","Live","Draft","tComponent","tForm","formName","formStatus","componentId","componentName","componentHint","componentTitle","step","actionArgs","sourceUrl"],"sources":["../../../../../src/server/plugins/engine/components/UkAddressField.ts"],"sourcesContent":["import {\n ComponentType,\n FormStatus,\n type FormMetadata,\n type UkAddressFieldComponent\n} from '@defra/forms-model'\nimport { type ObjectSchema } from 'joi'\nimport lowerFirst from 'lodash/lowerFirst.js'\n\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { TextField } from '~/src/server/plugins/engine/components/TextField.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport { getCachedPluginTranslator } from '~/src/server/plugins/engine/i18n/form.js'\nimport { getAvailableLanguages } from '~/src/server/plugins/engine/i18n/languages.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type PostcodeLookupExternalArgs\n} from '~/src/server/plugins/engine/types.js'\nimport { dispatch } from '~/src/server/plugins/postcode-lookup/routes/index.js'\nimport { resolveLanguage } from '~/src/server/utils/utils.js'\n\nexport class UkAddressField extends FormComponent {\n declare options: UkAddressFieldComponent['options']\n declare formSchema: ObjectSchema<FormPayload>\n declare stateSchema: ObjectSchema<FormState>\n declare collection: ComponentCollection\n\n constructor(\n def: UkAddressFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const { name, options } = def\n\n const isRequired = options.required !== false\n const hideOptional = !!options.optionalText\n const hideTitle = !!options.hideTitle\n this.collection = new ComponentCollection(\n [\n {\n type: ComponentType.TextField,\n name: `${name}__uprn`,\n title: 'components.addressField.uprn',\n schema: {},\n options: {\n required: false,\n classes: 'hidden'\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__addressLine1`,\n title: 'components.addressField.line1',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-line1',\n required: isRequired,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__addressLine2`,\n title: 'components.addressField.line2',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-line2',\n required: false,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__town`,\n title: 'components.addressField.town',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-level2',\n classes: 'govuk-!-width-two-thirds',\n required: isRequired,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__county`,\n title: 'components.addressField.county',\n schema: { max: 100 },\n options: {\n autocomplete: 'address-level1',\n required: false,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n },\n {\n type: ComponentType.TextField,\n name: `${name}__postcode`,\n title: 'components.addressField.postcode',\n schema: {\n regex: '^[a-zA-Z]{1,2}\\\\d[a-zA-Z\\\\d]?\\\\s?\\\\d[a-zA-Z]{2}$'\n },\n options: {\n autocomplete: 'postal-code',\n classes: 'govuk-input--width-10',\n required: isRequired,\n optionalText: !isRequired && (hideOptional || !hideTitle)\n }\n }\n ],\n { ...props, parent: this }\n )\n\n this.options = options\n this.formSchema = this.collection.formSchema\n this.stateSchema = this.collection.stateSchema\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const value = super.getFormValueFromState(state)\n return this.isState(value) ? value : undefined\n }\n\n getContextValueFromFormValue(value: UkAddressState | undefined) {\n if (!value) {\n return null\n }\n\n return Object.entries(value)\n .filter(([key, value]) => key !== 'uprn' && Boolean(value))\n .map(([, value]) => value)\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n getDisplayStringFromFormValue(\n value: UkAddressState | undefined,\n _translator: Translator\n ): string {\n return this.getContextValueFromFormValue(value)?.join(', ') ?? ''\n }\n\n getDisplayStringFromState(\n state: FormSubmissionState,\n translator: Translator\n ) {\n const value = this.getFormValueFromState(state)\n\n return this.getDisplayStringFromFormValue(value, translator)\n }\n\n /**\n * Returns one error per child field\n */\n getViewErrors(\n translator: Translator,\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const { t } = translator\n\n const uniqueErrors = this.getErrors(translator, errors)?.filter(\n (error, index, self) =>\n index === self.findIndex((err) => err.name === error.name)\n )\n\n // When using postcode lookup, the address fields are hidden\n // so we replace any individual validation messages with a single one\n if (this.shouldUsePostcodeLookup() && uniqueErrors?.length) {\n const { name, label } = this\n\n return [\n {\n name,\n path: [name],\n href: `#${name}`,\n text: t('components.addressField.enterAddress', {\n shortDescription: lowerFirst(label)\n })\n }\n ]\n }\n\n return uniqueErrors\n }\n\n getViewModel(context: RenderContext) {\n const { payload, translator } = context\n const { collection, name, options } = this\n\n const viewModel = super.getViewModel(context)\n let { fieldset, hint, label } = viewModel\n\n fieldset ??= {\n legend: {\n text: label.text,\n\n /**\n * For screen readers, only hide legend visually. This can be overridden\n * by single component (see QuestionPageController and showTitle handling)\n */\n classes: options.hideTitle\n ? 'govuk-visually-hidden'\n : 'govuk-fieldset__legend--m'\n }\n }\n\n if (hint) {\n hint.id ??= `${name}-hint`\n fieldset.attributes ??= {\n 'aria-describedby': hint.id\n }\n }\n\n const components = collection.getViewModel(context)\n\n // Hide UPRN\n const uprn = components.at(0)\n\n if (!uprn) {\n throw new Error('No UPRN')\n }\n\n uprn.model.formGroup = { classes: 'app-hidden' }\n\n // Postcode lookup\n const usePostcodeLookup = this.shouldUsePostcodeLookup()\n\n const value = usePostcodeLookup\n ? this.getDisplayStringFromState(payload, translator)\n : undefined\n\n return {\n ...viewModel,\n value,\n fieldset,\n components,\n usePostcodeLookup\n }\n }\n\n isState(value?: FormStateValue | FormState): value is UkAddressState {\n return UkAddressField.isUkAddress(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return UkAddressField.getAllPossibleErrors()\n }\n\n private shouldUsePostcodeLookup() {\n return !!(this.options.usePostcodeLookup && this.model.ordnanceSurveyApiKey)\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n { type: 'required', template: 'Enter address line 1' },\n { type: 'required', template: 'Enter town or city' },\n { type: 'required', template: 'Enter postcode' },\n { type: 'format', template: 'Enter valid postcode' }\n ],\n advancedSettingsErrors: []\n }\n }\n\n static isUkAddress(\n value?: FormStateValue | FormState\n ): value is UkAddressState {\n return (\n isFormState(value) &&\n TextField.isText(value.addressLine1) &&\n TextField.isText(value.town) &&\n TextField.isText(value.postcode)\n )\n }\n\n static async dispatcher(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n args: PostcodeLookupExternalArgs\n ) {\n const { controller, component } = args\n const language = resolveLanguage(request)\n\n const availableLanguages = getAvailableLanguages(controller.model.def)\n const languages = availableLanguages.length\n ? { languages: availableLanguages }\n : {}\n\n const translator = await getCachedPluginTranslator(\n request,\n { id: controller.model.formId } as unknown as FormMetadata,\n args.isLive ? FormStatus.Live : FormStatus.Draft,\n language\n )\n const { tComponent, tForm } = translator\n\n return dispatch(request, h, {\n formName: tForm('title'),\n formId: controller.model.formId,\n formStatus: args.isLive ? FormStatus.Live : FormStatus.Draft,\n componentId: component.id ?? 'unknown',\n componentName: component.name,\n componentHint: tComponent(component, 'hint'),\n componentTitle: tComponent(component, 'title') || controller.title,\n step: args.actionArgs.step,\n sourceUrl: args.sourceUrl,\n language,\n ...languages\n })\n }\n}\n\nexport interface UkAddressState extends Record<string, string> {\n uprn: string\n addressLine1: string\n addressLine2: string\n town: string\n county: string\n postcode: string\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type YesNoFieldComponent } from '@defra/forms-model';
|
|
2
|
-
import { type LanguageMessages } from 'joi';
|
|
3
2
|
import { SelectionControlField } from '../../../../server/plugins/engine/components/SelectionControlField.js';
|
|
4
3
|
import { type Translator } from '../../../../server/plugins/engine/i18n/types.js';
|
|
5
4
|
import { type ErrorMessageTemplateList } from '../../../../server/plugins/engine/types.js';
|
|
@@ -10,7 +9,11 @@ import { type ErrorMessageTemplateList } from '../../../../server/plugins/engine
|
|
|
10
9
|
export declare class YesNoField extends SelectionControlField {
|
|
11
10
|
options: YesNoFieldComponent['options'];
|
|
12
11
|
constructor(def: YesNoFieldComponent, props: ConstructorParameters<typeof SelectionControlField>[1]);
|
|
13
|
-
getValidationMessagesOverride(translator: Translator):
|
|
12
|
+
getValidationMessagesOverride(translator: Translator): {
|
|
13
|
+
[x: string]: {
|
|
14
|
+
'any.required': string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
14
17
|
/**
|
|
15
18
|
* For error preview page that shows all possible errors on a component
|
|
16
19
|
*/
|
|
@@ -3,8 +3,6 @@ import { SelectionControlField } from "./SelectionControlField.js";
|
|
|
3
3
|
import { addClassOptionIfNone } from "./helpers/index.js";
|
|
4
4
|
import { buildValidationMessages } from "../i18n/buildValidationMessages.js";
|
|
5
5
|
import { messageTemplate } from "../pageControllers/validationOptions.js";
|
|
6
|
-
import { convertToLanguageMessages } from "../../../utils/type-utils.js";
|
|
7
|
-
|
|
8
6
|
/**
|
|
9
7
|
* @description
|
|
10
8
|
* YesNoField is a radiosField with predefined values.
|
|
@@ -25,9 +23,18 @@ export class YesNoField extends SelectionControlField {
|
|
|
25
23
|
if (options.required === false) {
|
|
26
24
|
formSchema = formSchema.optional();
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
if (options.customValidationMessage) {
|
|
27
|
+
const message = options.customValidationMessage;
|
|
28
|
+
formSchema = formSchema.messages({
|
|
29
|
+
'any.required': message
|
|
30
|
+
});
|
|
31
|
+
} else if (options.customValidationMessages) {
|
|
32
|
+
formSchema = formSchema.messages(options.customValidationMessages);
|
|
33
|
+
} else {
|
|
34
|
+
formSchema = formSchema.messages({
|
|
35
|
+
'any.required': messageTemplate.selectYesNoRequired
|
|
36
|
+
});
|
|
37
|
+
}
|
|
31
38
|
this.formSchema = formSchema;
|
|
32
39
|
this.options = options;
|
|
33
40
|
}
|
|
@@ -35,9 +42,11 @@ export class YesNoField extends SelectionControlField {
|
|
|
35
42
|
const {
|
|
36
43
|
selectYesNoRequired
|
|
37
44
|
} = buildValidationMessages(translator.t);
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
return {
|
|
46
|
+
[this.name]: {
|
|
47
|
+
'any.required': selectYesNoRequired
|
|
48
|
+
}
|
|
49
|
+
};
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"YesNoField.js","names":["SchemaVersion","yesNoListId","yesNoListName","SelectionControlField","addClassOptionIfNone","buildValidationMessages","messageTemplate","
|
|
1
|
+
{"version":3,"file":"YesNoField.js","names":["SchemaVersion","yesNoListId","yesNoListName","SelectionControlField","addClassOptionIfNone","buildValidationMessages","messageTemplate","YesNoField","constructor","def","props","list","model","schemaVersion","V1","options","formSchema","required","optional","customValidationMessage","message","messages","customValidationMessages","selectYesNoRequired","getValidationMessagesOverride","translator","t","name","getAllPossibleErrors","baseErrors","type","template","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/YesNoField.ts"],"sourcesContent":["import {\n SchemaVersion,\n yesNoListId,\n yesNoListName,\n type YesNoFieldComponent\n} from '@defra/forms-model'\n\nimport { SelectionControlField } from '~/src/server/plugins/engine/components/SelectionControlField.js'\nimport { addClassOptionIfNone } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport { buildValidationMessages } from '~/src/server/plugins/engine/i18n/buildValidationMessages.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport { type ErrorMessageTemplateList } from '~/src/server/plugins/engine/types.js'\n\n/**\n * @description\n * YesNoField is a radiosField with predefined values.\n */\nexport class YesNoField extends SelectionControlField {\n declare options: YesNoFieldComponent['options']\n\n constructor(\n def: YesNoFieldComponent,\n props: ConstructorParameters<typeof SelectionControlField>[1]\n ) {\n super(\n {\n ...def,\n list:\n props.model.schemaVersion === SchemaVersion.V1\n ? yesNoListName\n : yesNoListId\n },\n props\n )\n\n const { options } = def\n let { formSchema } = this\n\n addClassOptionIfNone(options, 'govuk-radios--inline')\n\n if (options.required === false) {\n formSchema = formSchema.optional()\n }\n\n if (options.customValidationMessage) {\n const message = options.customValidationMessage\n\n formSchema = formSchema.messages({\n 'any.required': message\n })\n } else if (options.customValidationMessages) {\n formSchema = formSchema.messages(options.customValidationMessages)\n } else {\n formSchema = formSchema.messages({\n 'any.required': messageTemplate.selectYesNoRequired\n })\n }\n\n this.formSchema = formSchema\n this.options = options\n }\n\n getValidationMessagesOverride(translator: Translator) {\n const { selectYesNoRequired } = buildValidationMessages(translator.t)\n return {\n [this.name]: {\n 'any.required': selectYesNoRequired\n }\n }\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return YesNoField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n {\n type: 'selectYesNoRequired',\n template: messageTemplate.selectYesNoRequired\n }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AAAA,SACEA,aAAa,EACbC,WAAW,EACXC,aAAa,QAER,oBAAoB;AAE3B,SAASC,qBAAqB;AAC9B,SAASC,oBAAoB;AAC7B,SAASC,uBAAuB;AAEhC,SAASC,eAAe;AAGxB;AACA;AACA;AACA;AACA,OAAO,MAAMC,UAAU,SAASJ,qBAAqB,CAAC;EAGpDK,WAAWA,CACTC,GAAwB,EACxBC,KAA6D,EAC7D;IACA,KAAK,CACH;MACE,GAAGD,GAAG;MACNE,IAAI,EACFD,KAAK,CAACE,KAAK,CAACC,aAAa,KAAKb,aAAa,CAACc,EAAE,GAC1CZ,aAAa,GACbD;IACR,CAAC,EACDS,KACF,CAAC;IAED,MAAM;MAAEK;IAAQ,CAAC,GAAGN,GAAG;IACvB,IAAI;MAAEO;IAAW,CAAC,GAAG,IAAI;IAEzBZ,oBAAoB,CAACW,OAAO,EAAE,sBAAsB,CAAC;IAErD,IAAIA,OAAO,CAACE,QAAQ,KAAK,KAAK,EAAE;MAC9BD,UAAU,GAAGA,UAAU,CAACE,QAAQ,CAAC,CAAC;IACpC;IAEA,IAAIH,OAAO,CAACI,uBAAuB,EAAE;MACnC,MAAMC,OAAO,GAAGL,OAAO,CAACI,uBAAuB;MAE/CH,UAAU,GAAGA,UAAU,CAACK,QAAQ,CAAC;QAC/B,cAAc,EAAED;MAClB,CAAC,CAAC;IACJ,CAAC,MAAM,IAAIL,OAAO,CAACO,wBAAwB,EAAE;MAC3CN,UAAU,GAAGA,UAAU,CAACK,QAAQ,CAACN,OAAO,CAACO,wBAAwB,CAAC;IACpE,CAAC,MAAM;MACLN,UAAU,GAAGA,UAAU,CAACK,QAAQ,CAAC;QAC/B,cAAc,EAAEf,eAAe,CAACiB;MAClC,CAAC,CAAC;IACJ;IAEA,IAAI,CAACP,UAAU,GAAGA,UAAU;IAC5B,IAAI,CAACD,OAAO,GAAGA,OAAO;EACxB;EAEAS,6BAA6BA,CAACC,UAAsB,EAAE;IACpD,MAAM;MAAEF;IAAoB,CAAC,GAAGlB,uBAAuB,CAACoB,UAAU,CAACC,CAAC,CAAC;IACrE,OAAO;MACL,CAAC,IAAI,CAACC,IAAI,GAAG;QACX,cAAc,EAAEJ;MAClB;IACF,CAAC;EACH;;EAEA;AACF;AACA;EACEK,oBAAoBA,CAAA,EAA6B;IAC/C,OAAOrB,UAAU,CAACqB,oBAAoB,CAAC,CAAC;EAC1C;;EAEA;AACF;AACA;EACE,OAAOA,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CACV;QACEC,IAAI,EAAE,qBAAqB;QAC3BC,QAAQ,EAAEzB,eAAe,CAACiB;MAC5B,CAAC,CACF;MACDS,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -4,6 +4,7 @@ import { ListFormComponent } from "../ListFormComponent.js";
|
|
|
4
4
|
import { escapeMarkdown } from "./index.js";
|
|
5
5
|
import * as Components from "../index.js";
|
|
6
6
|
import { markdown } from "../markdownParser.js";
|
|
7
|
+
import { UnknownComponentTypeError } from "../../errors.js";
|
|
7
8
|
|
|
8
9
|
// All component instances
|
|
9
10
|
|
|
@@ -121,7 +122,7 @@ export function createComponent(def, options) {
|
|
|
121
122
|
break;
|
|
122
123
|
}
|
|
123
124
|
if (typeof component === 'undefined') {
|
|
124
|
-
throw new
|
|
125
|
+
throw new UnknownComponentTypeError(def.type);
|
|
125
126
|
}
|
|
126
127
|
return component;
|
|
127
128
|
}
|
|
@@ -222,8 +223,7 @@ export function getAnswerMarkdown(field, state, translator, options = {
|
|
|
222
223
|
// Format UK addresses into new lines
|
|
223
224
|
answerEscaped = (field.getContextValueFromState(state) ?? []).map(escapeMarkdown).join('\n').concat('\n');
|
|
224
225
|
} else if (field instanceof Components.EastingNorthingField || field instanceof Components.LatLongField) {
|
|
225
|
-
|
|
226
|
-
answerEscaped = contextValue ? `${contextValue}\n` : '';
|
|
226
|
+
answerEscaped = answer ? `${answer}\n` : '';
|
|
227
227
|
} else if (field instanceof Components.GeospatialField) {
|
|
228
228
|
const features = field.getFormValueFromState(state);
|
|
229
229
|
const value = field.getDisplayStringFromFormValue(features, translator);
|