@defra/forms-engine-plugin 5.0.0-alpha.3 → 5.0.0-alpha.30

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.
Files changed (406) hide show
  1. package/.public/37c964ca545c240f010a.mjs +2 -0
  2. package/.public/37c964ca545c240f010a.mjs.LICENSE.txt +4 -0
  3. package/.public/assets-manifest.json +3 -0
  4. package/.public/javascripts/application.min.js +1 -1
  5. package/.public/javascripts/application.min.js.LICENSE.txt +7 -0
  6. package/.public/javascripts/application.min.js.map +1 -1
  7. package/.public/javascripts/shared.min.js +1 -1
  8. package/.public/javascripts/shared.min.js.LICENSE.txt +9 -0
  9. package/.public/javascripts/shared.min.js.map +1 -1
  10. package/.public/javascripts/vendor/@defra.min.js +1 -1
  11. package/.public/javascripts/vendor/@defra.min.js.map +1 -1
  12. package/.public/javascripts/vendor/maplibre-gl.min.js +1 -1
  13. package/.public/javascripts/vendor/maplibre-gl.min.js.LICENSE.txt +3 -3
  14. package/.public/javascripts/vendor/maplibre-gl.min.js.map +1 -1
  15. package/.public/stylesheets/application.min.css +1 -1
  16. package/.public/stylesheets/application.min.css.map +1 -1
  17. package/.server/client/javascripts/file-upload.js +6 -3
  18. package/.server/client/javascripts/file-upload.js.map +1 -1
  19. package/.server/client/javascripts/geospatial-map.d.ts +159 -5
  20. package/.server/client/javascripts/geospatial-map.js +161 -81
  21. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  22. package/.server/client/javascripts/geospatial-map.test.js +152 -0
  23. package/.server/client/javascripts/geospatial-map.test.js.map +1 -0
  24. package/.server/client/javascripts/govuk.js +2 -1
  25. package/.server/client/javascripts/govuk.js.map +1 -1
  26. package/.server/client/javascripts/location-map.d.ts +44 -0
  27. package/.server/client/javascripts/location-map.js +55 -6
  28. package/.server/client/javascripts/location-map.js.map +1 -1
  29. package/.server/client/javascripts/map-constants.d.ts +3 -0
  30. package/.server/client/javascripts/map-constants.js +4 -0
  31. package/.server/client/javascripts/map-constants.js.map +1 -0
  32. package/.server/client/javascripts/map.d.ts +17 -4
  33. package/.server/client/javascripts/map.js +59 -6
  34. package/.server/client/javascripts/map.js.map +1 -1
  35. package/.server/client/javascripts/maps.d.ts +5 -0
  36. package/.server/client/javascripts/maps.js +6 -0
  37. package/.server/client/javascripts/maps.js.map +1 -0
  38. package/.server/client/javascripts/shared.d.ts +1 -4
  39. package/.server/client/javascripts/shared.js +1 -4
  40. package/.server/client/javascripts/shared.js.map +1 -1
  41. package/.server/client/javascripts/sssi-dataset.d.ts +18 -20
  42. package/.server/client/javascripts/sssi-dataset.js +37 -39
  43. package/.server/client/javascripts/sssi-dataset.js.map +1 -1
  44. package/.server/client/stylesheets/maps.scss +4 -0
  45. package/.server/client/stylesheets/shared.scss +1 -5
  46. package/.server/server/constants.d.ts +2 -0
  47. package/.server/server/constants.js +2 -0
  48. package/.server/server/constants.js.map +1 -1
  49. package/.server/server/forms/components.json +8 -0
  50. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +4 -0
  51. package/.server/server/plugins/engine/__stubs__/definitions.d.ts +29 -0
  52. package/.server/server/plugins/engine/__stubs__/definitions.js +125 -0
  53. package/.server/server/plugins/engine/__stubs__/definitions.js.map +1 -0
  54. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +8 -3
  55. package/.server/server/plugins/engine/components/AutocompleteField.js +17 -0
  56. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  57. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +23 -2
  58. package/.server/server/plugins/engine/components/CheckboxesField.js +30 -5
  59. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  60. package/.server/server/plugins/engine/components/ComponentBase.d.ts +2 -1
  61. package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
  62. package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
  63. package/.server/server/plugins/engine/components/ComponentCollection.js +12 -7
  64. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  65. package/.server/server/plugins/engine/components/DatePartsField.d.ts +6 -3
  66. package/.server/server/plugins/engine/components/DatePartsField.js +12 -7
  67. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  68. package/.server/server/plugins/engine/components/DeclarationField.d.ts +6 -3
  69. package/.server/server/plugins/engine/components/DeclarationField.js +6 -4
  70. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  71. package/.server/server/plugins/engine/components/Details.d.ts +1 -0
  72. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +33 -2
  73. package/.server/server/plugins/engine/components/EastingNorthingField.js +110 -54
  74. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  75. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +4 -1
  76. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -1
  77. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  78. package/.server/server/plugins/engine/components/FileUploadField.d.ts +23 -2
  79. package/.server/server/plugins/engine/components/FileUploadField.js +35 -3
  80. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  81. package/.server/server/plugins/engine/components/FormComponent.d.ts +5 -1
  82. package/.server/server/plugins/engine/components/FormComponent.js +5 -2
  83. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  84. package/.server/server/plugins/engine/components/GeospatialField.d.ts +23 -0
  85. package/.server/server/plugins/engine/components/GeospatialField.js +33 -9
  86. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  87. package/.server/server/plugins/engine/components/Html.d.ts +1 -0
  88. package/.server/server/plugins/engine/components/InsetText.d.ts +1 -0
  89. package/.server/server/plugins/engine/components/LatLongField.d.ts +32 -2
  90. package/.server/server/plugins/engine/components/LatLongField.js +85 -48
  91. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  92. package/.server/server/plugins/engine/components/List.d.ts +1 -0
  93. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +3 -2
  94. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
  95. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +8 -2
  96. package/.server/server/plugins/engine/components/LocationFieldBase.js +31 -7
  97. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  98. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +12 -3
  99. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +21 -13
  100. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  101. package/.server/server/plugins/engine/components/Markdown.d.ts +1 -0
  102. package/.server/server/plugins/engine/components/Markdown.js +1 -1
  103. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  104. package/.server/server/plugins/engine/components/MonthYearField.d.ts +5 -2
  105. package/.server/server/plugins/engine/components/MonthYearField.js +13 -9
  106. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  107. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +1 -0
  108. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  109. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +4 -3
  110. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  111. package/.server/server/plugins/engine/components/NotificationBanner.d.ts +1 -0
  112. package/.server/server/plugins/engine/components/NumberField.d.ts +5 -0
  113. package/.server/server/plugins/engine/components/NumberField.js +22 -0
  114. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  115. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +103 -1
  116. package/.server/server/plugins/engine/components/OsGridRefField.js +13 -3
  117. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  118. package/.server/server/plugins/engine/components/PaymentField.d.ts +2 -0
  119. package/.server/server/plugins/engine/components/PaymentField.js +9 -5
  120. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  121. package/.server/server/plugins/engine/components/SelectField.d.ts +1 -0
  122. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +1 -0
  123. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +1 -0
  124. package/.server/server/plugins/engine/components/TrackingField.d.ts +21 -0
  125. package/.server/server/plugins/engine/components/TrackingField.js +46 -0
  126. package/.server/server/plugins/engine/components/TrackingField.js.map +1 -0
  127. package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -0
  128. package/.server/server/plugins/engine/components/UkAddressField.js +23 -8
  129. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  130. package/.server/server/plugins/engine/components/YesNoField.d.ts +3 -2
  131. package/.server/server/plugins/engine/components/YesNoField.js +22 -8
  132. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  133. package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
  134. package/.server/server/plugins/engine/components/helpers/components.js +6 -3
  135. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  136. package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +8 -1
  137. package/.server/server/plugins/engine/components/helpers/geospatial.js +58 -17
  138. package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -1
  139. package/.server/server/plugins/engine/components/helpers/index.d.ts +21 -1
  140. package/.server/server/plugins/engine/components/helpers/index.js +45 -1
  141. package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
  142. package/.server/server/plugins/engine/components/index.d.ts +1 -0
  143. package/.server/server/plugins/engine/components/index.js +1 -0
  144. package/.server/server/plugins/engine/components/index.js.map +1 -1
  145. package/.server/server/plugins/engine/components/types.d.ts +1 -0
  146. package/.server/server/plugins/engine/components/types.js.map +1 -1
  147. package/.server/server/plugins/engine/errors.d.ts +49 -0
  148. package/.server/server/plugins/engine/errors.js +75 -0
  149. package/.server/server/plugins/engine/errors.js.map +1 -0
  150. package/.server/server/plugins/engine/form-availability.d.ts +3 -2
  151. package/.server/server/plugins/engine/form-availability.js +3 -2
  152. package/.server/server/plugins/engine/form-availability.js.map +1 -1
  153. package/.server/server/plugins/engine/form-context.js +2 -2
  154. package/.server/server/plugins/engine/form-context.js.map +1 -1
  155. package/.server/server/plugins/engine/helpers.d.ts +23 -2
  156. package/.server/server/plugins/engine/helpers.js +44 -5
  157. package/.server/server/plugins/engine/helpers.js.map +1 -1
  158. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +4 -1
  159. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +31 -7
  160. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -1
  161. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +4 -4
  162. package/.server/server/plugins/engine/i18n/createFormTranslator.js +27 -5
  163. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -1
  164. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +1 -1
  165. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +9 -0
  166. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -1
  167. package/.server/server/plugins/engine/i18n/form.d.ts +13 -0
  168. package/.server/server/plugins/engine/i18n/form.js +35 -0
  169. package/.server/server/plugins/engine/i18n/form.js.map +1 -0
  170. package/.server/server/plugins/engine/i18n/languages.d.ts +10 -0
  171. package/.server/server/plugins/engine/i18n/languages.js +19 -0
  172. package/.server/server/plugins/engine/i18n/languages.js.map +1 -0
  173. package/.server/server/plugins/engine/i18n/translations/cy.json +176 -7
  174. package/.server/server/plugins/engine/i18n/translations/en-GB.json +110 -6
  175. package/.server/server/plugins/engine/i18n/types.d.ts +2 -0
  176. package/.server/server/plugins/engine/i18n/types.js.map +1 -1
  177. package/.server/server/plugins/engine/index.d.ts +4 -0
  178. package/.server/server/plugins/engine/index.js +4 -0
  179. package/.server/server/plugins/engine/index.js.map +1 -1
  180. package/.server/server/plugins/engine/models/FormModel.d.ts +0 -4
  181. package/.server/server/plugins/engine/models/FormModel.js +35 -23
  182. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  183. package/.server/server/plugins/engine/models/SummaryViewModel.js +9 -4
  184. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  185. package/.server/server/plugins/engine/models/types.d.ts +28 -1
  186. package/.server/server/plugins/engine/models/types.js.map +1 -1
  187. package/.server/server/plugins/engine/models/unavailable-view-model.d.ts +11 -2
  188. package/.server/server/plugins/engine/models/unavailable-view-model.js +23 -4
  189. package/.server/server/plugins/engine/models/unavailable-view-model.js.map +1 -1
  190. package/.server/server/plugins/engine/options.js +2 -1
  191. package/.server/server/plugins/engine/options.js.map +1 -1
  192. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +14 -6
  193. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  194. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  195. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  196. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +2 -0
  197. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +2 -0
  198. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  199. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +7 -1
  200. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +56 -10
  201. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  202. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -1
  203. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +2 -2
  204. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  205. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
  206. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  207. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +10 -4
  208. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  209. package/.server/server/plugins/engine/pageControllers/helpers/pages.js +2 -1
  210. package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -1
  211. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +35 -2
  212. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +100 -3
  213. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  214. package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +1 -1
  215. package/.server/server/plugins/engine/pageControllers/validationOptions.js +24 -3
  216. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  217. package/.server/server/plugins/engine/plugin.js +3 -0
  218. package/.server/server/plugins/engine/plugin.js.map +1 -1
  219. package/.server/server/plugins/engine/referenceNumbers.d.ts +1 -0
  220. package/.server/server/plugins/engine/referenceNumbers.js +1 -0
  221. package/.server/server/plugins/engine/referenceNumbers.js.map +1 -1
  222. package/.server/server/plugins/engine/routes/index.js +9 -4
  223. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  224. package/.server/server/plugins/engine/types/enums.d.ts +3 -3
  225. package/.server/server/plugins/engine/types/enums.js +5 -4
  226. package/.server/server/plugins/engine/types/enums.js.map +1 -1
  227. package/.server/server/plugins/engine/types/schema.js +15 -4
  228. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  229. package/.server/server/plugins/engine/types.d.ts +24 -2
  230. package/.server/server/plugins/engine/types.js.map +1 -1
  231. package/.server/server/plugins/engine/unavailable-response.js +5 -2
  232. package/.server/server/plugins/engine/unavailable-response.js.map +1 -1
  233. package/.server/server/plugins/engine/views/components/_location-field-base.html +4 -2
  234. package/.server/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  235. package/.server/server/plugins/engine/views/components/geospatialfield.html +1 -0
  236. package/.server/server/plugins/engine/views/components/osgridreffield.html +4 -1
  237. package/.server/server/plugins/engine/views/components/trackingfield.html +3 -0
  238. package/.server/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  239. package/.server/server/plugins/engine/views/file-upload.html +1 -1
  240. package/.server/server/plugins/engine/views/summary.html +1 -0
  241. package/.server/server/plugins/engine/views/unavailable.html +14 -11
  242. package/.server/server/plugins/map/routes/index.d.ts +4 -0
  243. package/.server/server/plugins/map/routes/index.js +12 -4
  244. package/.server/server/plugins/map/routes/index.js.map +1 -1
  245. package/.server/server/plugins/map/routes/index.test.js +7 -0
  246. package/.server/server/plugins/map/routes/index.test.js.map +1 -0
  247. package/.server/server/plugins/map/routes/vts/README.md +38 -0
  248. package/.server/server/plugins/map/routes/vts/countries-5dp.geojson +4 -0
  249. package/.server/server/plugins/map/routes/vts/countries.geojson +10 -39283
  250. package/.server/server/plugins/map/types.d.ts +24 -2
  251. package/.server/server/plugins/map/types.js +9 -2
  252. package/.server/server/plugins/map/types.js.map +1 -1
  253. package/.server/server/plugins/nunjucks/enviroment.test.js +11 -4
  254. package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
  255. package/.server/server/plugins/nunjucks/filters/applyUrlParam.d.ts +9 -0
  256. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  257. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js.map +1 -0
  258. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js +17 -0
  259. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js.map +1 -0
  260. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  261. package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
  262. package/.server/server/plugins/nunjucks/filters/index.js +1 -0
  263. package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
  264. package/.server/server/plugins/payment/helper.d.ts +11 -1
  265. package/.server/server/plugins/payment/helper.js +18 -2
  266. package/.server/server/plugins/payment/helper.js.map +1 -1
  267. package/.server/server/plugins/payment/helper.test.js +2 -1
  268. package/.server/server/plugins/payment/helper.test.js.map +1 -1
  269. package/.server/server/plugins/payment/service.d.ts +2 -1
  270. package/.server/server/plugins/payment/service.js +5 -2
  271. package/.server/server/plugins/payment/service.js.map +1 -1
  272. package/.server/server/plugins/payment/service.test.js +7 -3
  273. package/.server/server/plugins/payment/service.test.js.map +1 -1
  274. package/.server/server/plugins/payment/types.d.ts +4 -0
  275. package/.server/server/plugins/payment/types.js +1 -0
  276. package/.server/server/plugins/payment/types.js.map +1 -1
  277. package/.server/server/plugins/postcode-lookup/models/index.d.ts +249 -3
  278. package/.server/server/plugins/postcode-lookup/models/index.js +103 -36
  279. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  280. package/.server/server/plugins/postcode-lookup/routes/index.d.ts +15 -1
  281. package/.server/server/plugins/postcode-lookup/routes/index.js +64 -18
  282. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  283. package/.server/server/plugins/postcode-lookup/routes/index.test.js +84 -0
  284. package/.server/server/plugins/postcode-lookup/routes/index.test.js.map +1 -0
  285. package/.server/server/plugins/postcode-lookup/types.d.ts +12 -0
  286. package/.server/server/plugins/postcode-lookup/types.js +6 -1
  287. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  288. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  289. package/.server/server/utils/type-utils.d.ts +1 -2
  290. package/.server/server/utils/type-utils.js +0 -3
  291. package/.server/server/utils/type-utils.js.map +1 -1
  292. package/.server/server/utils/utils.d.ts +6 -0
  293. package/.server/server/utils/utils.js +18 -1
  294. package/.server/server/utils/utils.js.map +1 -1
  295. package/.server/server/utils/utils.test.js +21 -1
  296. package/.server/server/utils/utils.test.js.map +1 -1
  297. package/.server/typings/geodesy/index.d.js +2 -0
  298. package/.server/typings/geodesy/index.d.js.map +1 -0
  299. package/.server/typings/hapi/index.d.js.map +1 -1
  300. package/package.json +24 -9
  301. package/src/client/javascripts/file-upload.js +11 -3
  302. package/src/client/javascripts/geospatial-map.js +181 -86
  303. package/src/client/javascripts/govuk.js +2 -0
  304. package/src/client/javascripts/location-map.js +62 -6
  305. package/src/client/javascripts/map-constants.js +3 -0
  306. package/src/client/javascripts/map.js +66 -9
  307. package/src/client/javascripts/maps.js +5 -0
  308. package/src/client/javascripts/shared.js +1 -4
  309. package/src/client/javascripts/sssi-dataset.js +39 -41
  310. package/src/client/stylesheets/maps.scss +4 -0
  311. package/src/client/stylesheets/shared.scss +1 -5
  312. package/src/server/constants.js +2 -0
  313. package/src/server/forms/components.json +8 -0
  314. package/src/server/forms/register-as-a-unicorn-breeder.yaml +4 -0
  315. package/src/server/plugins/engine/__stubs__/definitions.ts +155 -0
  316. package/src/server/plugins/engine/components/AutocompleteField.ts +20 -0
  317. package/src/server/plugins/engine/components/CheckboxesField.ts +41 -8
  318. package/src/server/plugins/engine/components/ComponentBase.ts +6 -4
  319. package/src/server/plugins/engine/components/ComponentCollection.ts +17 -15
  320. package/src/server/plugins/engine/components/DatePartsField.ts +20 -9
  321. package/src/server/plugins/engine/components/DeclarationField.ts +10 -10
  322. package/src/server/plugins/engine/components/EastingNorthingField.ts +185 -89
  323. package/src/server/plugins/engine/components/EmailAddressField.ts +2 -1
  324. package/src/server/plugins/engine/components/FileUploadField.ts +46 -5
  325. package/src/server/plugins/engine/components/FormComponent.ts +6 -5
  326. package/src/server/plugins/engine/components/GeospatialField.ts +47 -9
  327. package/src/server/plugins/engine/components/LatLongField.ts +128 -58
  328. package/src/server/plugins/engine/components/ListFormComponent.ts +4 -4
  329. package/src/server/plugins/engine/components/LocationFieldBase.ts +41 -8
  330. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +28 -14
  331. package/src/server/plugins/engine/components/Markdown.ts +2 -3
  332. package/src/server/plugins/engine/components/MonthYearField.ts +20 -15
  333. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -3
  334. package/src/server/plugins/engine/components/NumberField.ts +24 -0
  335. package/src/server/plugins/engine/components/OsGridRefField.ts +22 -3
  336. package/src/server/plugins/engine/components/PaymentField.ts +9 -4
  337. package/src/server/plugins/engine/components/TrackingField.ts +64 -0
  338. package/src/server/plugins/engine/components/UkAddressField.ts +30 -7
  339. package/src/server/plugins/engine/components/YesNoField.ts +27 -9
  340. package/src/server/plugins/engine/components/helpers/components.ts +8 -3
  341. package/src/server/plugins/engine/components/helpers/geospatial.ts +87 -24
  342. package/src/server/plugins/engine/components/helpers/index.ts +64 -1
  343. package/src/server/plugins/engine/components/index.ts +1 -0
  344. package/src/server/plugins/engine/components/types.ts +1 -0
  345. package/src/server/plugins/engine/errors.ts +78 -0
  346. package/src/server/plugins/engine/form-availability.ts +8 -2
  347. package/src/server/plugins/engine/form-context.ts +4 -2
  348. package/src/server/plugins/engine/helpers.ts +52 -5
  349. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +16 -8
  350. package/src/server/plugins/engine/i18n/createFormTranslator.ts +43 -12
  351. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +7 -1
  352. package/src/server/plugins/engine/i18n/form.ts +54 -0
  353. package/src/server/plugins/engine/i18n/languages.ts +19 -0
  354. package/src/server/plugins/engine/i18n/translations/cy.json +176 -7
  355. package/src/server/plugins/engine/i18n/translations/en-GB.json +110 -6
  356. package/src/server/plugins/engine/i18n/types.ts +2 -0
  357. package/src/server/plugins/engine/index.ts +7 -0
  358. package/src/server/plugins/engine/models/FormModel.ts +46 -23
  359. package/src/server/plugins/engine/models/SummaryViewModel.ts +6 -5
  360. package/src/server/plugins/engine/models/types.ts +31 -0
  361. package/src/server/plugins/engine/models/unavailable-view-model.ts +26 -5
  362. package/src/server/plugins/engine/options.js +2 -1
  363. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +18 -7
  364. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -1
  365. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +3 -0
  366. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +60 -9
  367. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +2 -2
  368. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
  369. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -4
  370. package/src/server/plugins/engine/pageControllers/helpers/pages.ts +2 -1
  371. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +143 -4
  372. package/src/server/plugins/engine/pageControllers/validationOptions.ts +29 -4
  373. package/src/server/plugins/engine/plugin.ts +6 -0
  374. package/src/server/plugins/engine/referenceNumbers.ts +2 -0
  375. package/src/server/plugins/engine/routes/index.ts +9 -3
  376. package/src/server/plugins/engine/types/enums.ts +4 -3
  377. package/src/server/plugins/engine/types/schema.ts +22 -5
  378. package/src/server/plugins/engine/types.ts +28 -1
  379. package/src/server/plugins/engine/unavailable-response.ts +6 -2
  380. package/src/server/plugins/engine/views/components/_location-field-base.html +4 -2
  381. package/src/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  382. package/src/server/plugins/engine/views/components/geospatialfield.html +1 -0
  383. package/src/server/plugins/engine/views/components/osgridreffield.html +4 -1
  384. package/src/server/plugins/engine/views/components/trackingfield.html +3 -0
  385. package/src/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  386. package/src/server/plugins/engine/views/file-upload.html +1 -1
  387. package/src/server/plugins/engine/views/summary.html +1 -0
  388. package/src/server/plugins/engine/views/unavailable.html +14 -11
  389. package/src/server/plugins/map/routes/index.js +29 -4
  390. package/src/server/plugins/map/routes/vts/README.md +38 -0
  391. package/src/server/plugins/map/routes/vts/countries-5dp.geojson +4 -0
  392. package/src/server/plugins/map/routes/vts/countries.geojson +10 -39283
  393. package/src/server/plugins/map/types.js +9 -2
  394. package/src/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  395. package/src/server/plugins/nunjucks/filters/index.js +1 -0
  396. package/src/server/plugins/payment/helper.js +22 -2
  397. package/src/server/plugins/payment/service.js +6 -2
  398. package/src/server/plugins/payment/types.js +1 -0
  399. package/src/server/plugins/postcode-lookup/models/index.js +91 -46
  400. package/src/server/plugins/postcode-lookup/routes/index.js +96 -24
  401. package/src/server/plugins/postcode-lookup/types.js +6 -1
  402. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  403. package/src/server/utils/type-utils.ts +1 -11
  404. package/src/server/utils/utils.js +19 -1
  405. package/src/typings/geodesy/index.d.ts +18 -0
  406. package/src/typings/hapi/index.d.ts +2 -0
@@ -1,8 +1,18 @@
1
+ import { EN_GB } from "../../../constants.js";
1
2
  import { LocationFieldBase } from "./LocationFieldBase.js";
3
+ import { getMapLayers } from "./LocationFieldHelpers.js";
2
4
  import { createLowerFirstExpression } from "./helpers/index.js";
3
5
  import { t } from "../i18n/index.js";
4
6
  export class OsGridRefField extends LocationFieldBase {
5
- getValidationConfig() {
7
+ getViewModel(context) {
8
+ const viewModel = super.getViewModel(context);
9
+ Object.assign(viewModel, {
10
+ lang: context.translator.language,
11
+ mapLayers: getMapLayers(this)
12
+ });
13
+ return viewModel;
14
+ }
15
+ getValidationConfig(translator) {
6
16
  // Regex for OS national grid references (NGR)
7
17
  // Validates specific valid OS grid letter combinations with:
8
18
  // - 2 letters & 6 digits in 2 blocks of 3 e.g. ST 678 678
@@ -12,8 +22,8 @@ export class OsGridRefField extends LocationFieldBase {
12
22
  const pattern = /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?(([0-9]{3})\s?([0-9]{3})|([0-9]{4})\s?([0-9]{4})|([0-9]{5})\s?([0-9]{5}))$/;
13
23
  return {
14
24
  pattern,
15
- patternErrorMessage: createLowerFirstExpression(t('components.osGridRefField.pattern', 'en-GB')),
16
- requiredMessage: createLowerFirstExpression(t('components.osGridRefField.required', 'en-GB'))
25
+ patternErrorMessage: createLowerFirstExpression(translator ? translator.t('components.osGridRefField.pattern') : t('components.osGridRefField.pattern', EN_GB)),
26
+ requiredMessage: createLowerFirstExpression(translator ? translator.t('components.osGridRefField.required') : t('components.osGridRefField.required', EN_GB))
17
27
  };
18
28
  }
19
29
  getErrorTemplates() {
@@ -1 +1 @@
1
- {"version":3,"file":"OsGridRefField.js","names":["LocationFieldBase","createLowerFirstExpression","t","OsGridRefField","getValidationConfig","pattern","patternErrorMessage","requiredMessage","getErrorTemplates","type","template","getAllPossibleErrors","baseErrors","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/OsGridRefField.ts"],"sourcesContent":["import { type OsGridRefFieldComponent } from '@defra/forms-model'\n\nimport { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'\nimport { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport { t } from '~/src/server/plugins/engine/i18n/index.js'\nimport { type ErrorMessageTemplateList } from '~/src/server/plugins/engine/types.js'\n\nexport class OsGridRefField extends LocationFieldBase {\n declare options: OsGridRefFieldComponent['options']\n\n protected getValidationConfig() {\n // Regex for OS national grid references (NGR)\n // Validates specific valid OS grid letter combinations with:\n // - 2 letters & 6 digits in 2 blocks of 3 e.g. ST 678 678\n // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789\n // - 2 letters & 10 digits in 2 blocks of 5 e.g. SO 12345 12345\n // Optional spaces between each block\n const pattern =\n /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\\s?(([0-9]{3})\\s?([0-9]{3})|([0-9]{4})\\s?([0-9]{4})|([0-9]{5})\\s?([0-9]{5}))$/\n\n return {\n pattern,\n patternErrorMessage: createLowerFirstExpression(\n t('components.osGridRefField.pattern', 'en-GB')\n ),\n requiredMessage: createLowerFirstExpression(\n t('components.osGridRefField.required', 'en-GB')\n )\n }\n }\n\n protected getErrorTemplates() {\n return [\n {\n type: 'pattern',\n template: createLowerFirstExpression(\n t('components.osGridRefField.pattern', 'en-GB')\n )\n }\n ]\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: 'required',\n template: createLowerFirstExpression(\n t('components.osGridRefField.required', 'en-GB')\n )\n },\n {\n type: 'pattern',\n template: createLowerFirstExpression(\n t('components.osGridRefField.pattern', 'en-GB')\n )\n }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AAEA,SAASA,iBAAiB;AAC1B,SAASC,0BAA0B;AACnC,SAASC,CAAC;AAGV,OAAO,MAAMC,cAAc,SAASH,iBAAiB,CAAC;EAG1CI,mBAAmBA,CAAA,EAAG;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA,MAAMC,OAAO,GACX,qLAAqL;IAEvL,OAAO;MACLA,OAAO;MACPC,mBAAmB,EAAEL,0BAA0B,CAC7CC,CAAC,CAAC,mCAAmC,EAAE,OAAO,CAChD,CAAC;MACDK,eAAe,EAAEN,0BAA0B,CACzCC,CAAC,CAAC,oCAAoC,EAAE,OAAO,CACjD;IACF,CAAC;EACH;EAEUM,iBAAiBA,CAAA,EAAG;IAC5B,OAAO,CACL;MACEC,IAAI,EAAE,SAAS;MACfC,QAAQ,EAAET,0BAA0B,CAClCC,CAAC,CAAC,mCAAmC,EAAE,OAAO,CAChD;IACF,CAAC,CACF;EACH;;EAEA;AACF;AACA;EACE,OAAOS,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CACV;QACEH,IAAI,EAAE,UAAU;QAChBC,QAAQ,EAAET,0BAA0B,CAClCC,CAAC,CAAC,oCAAoC,EAAE,OAAO,CACjD;MACF,CAAC,EACD;QACEO,IAAI,EAAE,SAAS;QACfC,QAAQ,EAAET,0BAA0B,CAClCC,CAAC,CAAC,mCAAmC,EAAE,OAAO,CAChD;MACF,CAAC,CACF;MACDW,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","ignoreList":[]}
1
+ {"version":3,"file":"OsGridRefField.js","names":["EN_GB","LocationFieldBase","getMapLayers","createLowerFirstExpression","t","OsGridRefField","getViewModel","context","viewModel","Object","assign","lang","translator","language","mapLayers","getValidationConfig","pattern","patternErrorMessage","requiredMessage","getErrorTemplates","type","template","getAllPossibleErrors","baseErrors","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/OsGridRefField.ts"],"sourcesContent":["import { type OsGridRefFieldComponent } from '@defra/forms-model'\n\nimport { EN_GB } from '~/src/server/constants.js'\nimport { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js'\nimport { getMapLayers } from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'\nimport { createLowerFirstExpression } from '~/src/server/plugins/engine/components/helpers/index.js'\nimport { type RenderContext } from '~/src/server/plugins/engine/components/types.js'\nimport { t } from '~/src/server/plugins/engine/i18n/index.js'\nimport { type Translator } from '~/src/server/plugins/engine/types/index.js'\nimport { type ErrorMessageTemplateList } from '~/src/server/plugins/engine/types.js'\n\nexport class OsGridRefField extends LocationFieldBase {\n declare options: OsGridRefFieldComponent['options']\n\n getViewModel(context: RenderContext) {\n const viewModel = super.getViewModel(context)\n\n Object.assign(viewModel, {\n lang: context.translator.language,\n mapLayers: getMapLayers(this)\n })\n\n return viewModel\n }\n\n protected getValidationConfig(translator: Translator | undefined) {\n // Regex for OS national grid references (NGR)\n // Validates specific valid OS grid letter combinations with:\n // - 2 letters & 6 digits in 2 blocks of 3 e.g. ST 678 678\n // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789\n // - 2 letters & 10 digits in 2 blocks of 5 e.g. SO 12345 12345\n // Optional spaces between each block\n const pattern =\n /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\\s?(([0-9]{3})\\s?([0-9]{3})|([0-9]{4})\\s?([0-9]{4})|([0-9]{5})\\s?([0-9]{5}))$/\n\n return {\n pattern,\n patternErrorMessage: createLowerFirstExpression(\n translator\n ? translator.t('components.osGridRefField.pattern')\n : t('components.osGridRefField.pattern', EN_GB)\n ),\n requiredMessage: createLowerFirstExpression(\n translator\n ? translator.t('components.osGridRefField.required')\n : t('components.osGridRefField.required', EN_GB)\n )\n }\n }\n\n protected getErrorTemplates() {\n return [\n {\n type: 'pattern',\n template: createLowerFirstExpression(\n t('components.osGridRefField.pattern', 'en-GB')\n )\n }\n ]\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: 'required',\n template: createLowerFirstExpression(\n t('components.osGridRefField.required', 'en-GB')\n )\n },\n {\n type: 'pattern',\n template: createLowerFirstExpression(\n t('components.osGridRefField.pattern', 'en-GB')\n )\n }\n ],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AAEA,SAASA,KAAK;AACd,SAASC,iBAAiB;AAC1B,SAASC,YAAY;AACrB,SAASC,0BAA0B;AAEnC,SAASC,CAAC;AAIV,OAAO,MAAMC,cAAc,SAASJ,iBAAiB,CAAC;EAGpDK,YAAYA,CAACC,OAAsB,EAAE;IACnC,MAAMC,SAAS,GAAG,KAAK,CAACF,YAAY,CAACC,OAAO,CAAC;IAE7CE,MAAM,CAACC,MAAM,CAACF,SAAS,EAAE;MACvBG,IAAI,EAAEJ,OAAO,CAACK,UAAU,CAACC,QAAQ;MACjCC,SAAS,EAAEZ,YAAY,CAAC,IAAI;IAC9B,CAAC,CAAC;IAEF,OAAOM,SAAS;EAClB;EAEUO,mBAAmBA,CAACH,UAAkC,EAAE;IAChE;IACA;IACA;IACA;IACA;IACA;IACA,MAAMI,OAAO,GACX,qLAAqL;IAEvL,OAAO;MACLA,OAAO;MACPC,mBAAmB,EAAEd,0BAA0B,CAC7CS,UAAU,GACNA,UAAU,CAACR,CAAC,CAAC,mCAAmC,CAAC,GACjDA,CAAC,CAAC,mCAAmC,EAAEJ,KAAK,CAClD,CAAC;MACDkB,eAAe,EAAEf,0BAA0B,CACzCS,UAAU,GACNA,UAAU,CAACR,CAAC,CAAC,oCAAoC,CAAC,GAClDA,CAAC,CAAC,oCAAoC,EAAEJ,KAAK,CACnD;IACF,CAAC;EACH;EAEUmB,iBAAiBA,CAAA,EAAG;IAC5B,OAAO,CACL;MACEC,IAAI,EAAE,SAAS;MACfC,QAAQ,EAAElB,0BAA0B,CAClCC,CAAC,CAAC,mCAAmC,EAAE,OAAO,CAChD;IACF,CAAC,CACF;EACH;;EAEA;AACF;AACA;EACE,OAAOkB,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CACV;QACEH,IAAI,EAAE,UAAU;QAChBC,QAAQ,EAAElB,0BAA0B,CAClCC,CAAC,CAAC,oCAAoC,EAAE,OAAO,CACjD;MACF,CAAC,EACD;QACEgB,IAAI,EAAE,SAAS;QACfC,QAAQ,EAAElB,0BAA0B,CAClCC,CAAC,CAAC,mCAAmC,EAAE,OAAO,CAChD;MACF,CAAC,CACF;MACDoB,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","ignoreList":[]}
@@ -69,6 +69,7 @@ export declare class PaymentField 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
  /**
@@ -123,6 +124,7 @@ export interface PaymentSessionData {
123
124
  reference: string;
124
125
  amount: number;
125
126
  description: string;
127
+ descriptionInEng?: string;
126
128
  paymentId: string;
127
129
  componentName: string;
128
130
  returnUrl: string;
@@ -19,6 +19,7 @@ export class PaymentField extends FormComponent {
19
19
  reference: joi.string().required(),
20
20
  amount: joi.number().required(),
21
21
  description: joi.string().required(),
22
+ descriptionInEng: joi.string().optional(),
22
23
  uuid: joi.string().uuid().required(),
23
24
  formId: joi.string().required(),
24
25
  isLivePayment: joi.boolean().required(),
@@ -164,10 +165,11 @@ export class PaymentField extends FormComponent {
164
165
  const {
165
166
  model
166
167
  } = args.controller;
167
- const language = resolveLanguage(request);
168
168
  const {
169
- t
170
- } = model.createTranslator(language);
169
+ language,
170
+ t,
171
+ tComponent
172
+ } = model.createTranslator(resolveLanguage(request));
171
173
  const state = await args.controller.getState(request);
172
174
  const {
173
175
  baseUrl
@@ -189,7 +191,7 @@ export class PaymentField extends FormComponent {
189
191
  if (resolvedAmount === 0) {
190
192
  return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER);
191
193
  }
192
- const description = options.description;
194
+ const description = tComponent(args.component, 'paymentDescription') || options.description;
193
195
  const slug = `/${model.basePath}`;
194
196
  const payCallbackUrl = `${baseUrl}/payment-callback?uuid=${uuid}`;
195
197
  const paymentPageUrl = args.sourceUrl;
@@ -201,7 +203,8 @@ export class PaymentField extends FormComponent {
201
203
  const amountInPence = Math.round(resolvedAmount * 100);
202
204
  const payment = await paymentService.createPayment(amountInPence, description, payCallbackUrl, reference, isLivePayment, {
203
205
  formId,
204
- slug
206
+ slug,
207
+ language
205
208
  }, prefilledEmail);
206
209
  if (!payment) {
207
210
  const message = isLivePayment ? t('components.paymentField.cannotTakePayment') : t('components.paymentField.testApiKey');
@@ -215,6 +218,7 @@ export class PaymentField extends FormComponent {
215
218
  reference,
216
219
  amount: resolvedAmount,
217
220
  description,
221
+ descriptionInEng: options.description,
218
222
  paymentId: payment.paymentId,
219
223
  componentName,
220
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","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 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 = 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":"AAAA,SAASA,UAAU,QAAQ,aAAa;AAMxC,SAASC,WAAW,QAAQ,mBAAmB;AAC/C,OAAOC,GAAG,MAA6B,KAAK;AAE5C,SAASC,MAAM;AACf,SAASC,qBAAqB;AAC9B,SAASC,aAAa;AAGtB,SACEC,WAAW,EACXC,gBAAgB;AAIlB,SACEC,iBAAiB,EACjBC,mBAAmB,EACnBC,sBAAsB;AAcxB,SACEC,oBAAoB,EACpBC,cAAc;AAEhB,SAASC,eAAe;AAExB,OAAO,MAAMC,YAAY,SAAST,aAAa,CAAC;EAK9CU,4BAA4B,GAAG,IAAI;EAEnCC,WAAWA,CACTC,GAA0B,EAC1BC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,IAAI,CAACC,OAAO,GAAGF,GAAG,CAACE,OAAO;IAC1B,IAAI,CAACF,GAAG,GAAGA,GAAG;IAEd,MAAMG,kBAAkB,GAAGlB,GAAG,CAC3BmB,MAAM,CAAC;MACNC,SAAS,EAAEpB,GAAG,CAACqB,MAAM,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;MAClCC,SAAS,EAAEvB,GAAG,CAACqB,MAAM,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;MAClCE,MAAM,EAAExB,GAAG,CAACyB,MAAM,CAAC,CAAC,CAACH,QAAQ,CAAC,CAAC;MAC/BI,WAAW,EAAE1B,GAAG,CAACqB,MAAM,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;MACpCK,gBAAgB,EAAE3B,GAAG,CAACqB,MAAM,CAAC,CAAC,CAACO,QAAQ,CAAC,CAAC;MACzCC,IAAI,EAAE7B,GAAG,CAACqB,MAAM,CAAC,CAAC,CAACQ,IAAI,CAAC,CAAC,CAACP,QAAQ,CAAC,CAAC;MACpCQ,MAAM,EAAE9B,GAAG,CAACqB,MAAM,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;MAC/BS,aAAa,EAAE/B,GAAG,CAACgC,OAAO,CAAC,CAAC,CAACV,QAAQ,CAAC,CAAC;MACvCW,OAAO,EAAEjC,GAAG,CACTmB,MAAM,CAAC;QACNe,MAAM,EAAElC,GAAG,CACRqB,MAAM,CAAC,CAAC,CACRc,KAAK,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CACrCb,QAAQ,CAAC,CAAC;QACbc,SAAS,EAAEpC,GAAG,CAACqB,MAAM,CAAC,CAAC,CAACgB,OAAO,CAAC,CAAC,CAACf,QAAQ,CAAC;MAC7C,CAAC,CAAC,CACDA,QAAQ,CAAC;IACd,CAAC,CAAC,CACDgB,OAAO,CAAC,IAAI,CAAC,CACbC,KAAK,CAAC,IAAI,CAACA,KAAK,CAAC;IAEpB,IAAI,CAACC,UAAU,GAAGtB,kBAAkB;IACpC;IACA;IACA;IACA,IAAI,CAACuB,WAAW,GAAGvB,kBAAkB,CAACI,QAAQ,CAAC,CAAC;EAClD;;EAEA;AACF;AACA;EACEoB,wBAAwBA,CACtBC,KAA0B,EACA;IAC1B,MAAMC,KAAK,GAAGD,KAAK,CAAC,IAAI,CAACE,IAAI,CAAC;IAC9B,OAAO,IAAI,CAACC,cAAc,CAACF,KAAK,CAAC,GAAGA,KAAK,GAAGG,SAAS;EACvD;EAEAC,yBAAyBA,CACvBL,KAA0B,EAC1BM,WAAuB,EACf;IACR,MAAML,KAAK,GAAG,IAAI,CAACF,wBAAwB,CAACC,KAAK,CAAC;IAElD,IAAI,CAACC,KAAK,EAAE;MACV,OAAO,EAAE;IACX;IAEA,OAAO,GAAGlC,cAAc,CAACkC,KAAK,CAACpB,MAAM,CAAC,MAAMoB,KAAK,CAAClB,WAAW,EAAE;EACjE;EAEAwB,YAAYA,CAACC,OAAsB,EAAE;IACnC,MAAM;MAAEC;IAAQ,CAAC,GAAGD,OAAO;IAC3B,MAAME,SAAS,GAAG,KAAK,CAACH,YAAY,CAACC,OAAO,CAAC;IAC7C,MAAM;MAAEG;IAAW,CAAC,GAAGH,OAAO;IAC9B,MAAM;MAAEI;IAAW,CAAC,GAAGD,UAAU;;IAEjC;IACA,MAAME,YAAY,GAAG,IAAI,CAACV,cAAc,CAACM,OAAO,CAAC,IAAI,CAACP,IAAI,CAAY,CAAC,GAClEO,OAAO,CAAC,IAAI,CAACP,IAAI,CAAC,GACnBE,SAAS;;IAEb;IACA;IACA;IACA,MAAMvB,MAAM,GAAGgC,YAAY,EAAEhC,MAAM,IAAI,IAAI,CAACP,OAAO,CAACO,MAAM;IAE1D,OAAO;MACL,GAAG6B,SAAS;MACZ7B,MAAM,EAAEd,cAAc,CAACc,MAAM,CAAC;MAC9BE,WAAW,EACT6B,UAAU,CAAC,IAAI,CAACxC,GAAG,EAAE,oBAAoB,CAAC,IAAI,IAAI,CAACE,OAAO,CAACS,WAAW;MACxE8B;IACF,CAAC;EACH;;EAEA;AACF;AACA;EACEV,cAAcA,CAACF,KAAc,EAAyB;IACpD,OAAOhC,YAAY,CAACkC,cAAc,CAACF,KAAK,CAAC;EAC3C;;EAEA;AACF;AACA;EACE,OAAOE,cAAcA,CAACF,KAAc,EAAyB;IAC3D,IAAI,CAACA,KAAK,IAAI,OAAOA,KAAK,KAAK,QAAQ,IAAIa,KAAK,CAACC,OAAO,CAACd,KAAK,CAAC,EAAE;MAC/D,OAAO,KAAK;IACd;IAEA,MAAMD,KAAK,GAAGC,KAAqB;IACnC,OACE,OAAOD,KAAK,CAACvB,SAAS,KAAK,QAAQ,IACnC,OAAOuB,KAAK,CAACnB,MAAM,KAAK,QAAQ,IAChC,OAAOmB,KAAK,CAACjB,WAAW,KAAK,QAAQ;EAEzC;;EAEA;AACF;AACA;EACEiC,OAAOA,CAACf,KAAkC,EAAsB;IAC9D,OAAO,IAAI,CAACE,cAAc,CAACF,KAAK,CAAC;EACnC;EAEAgB,YAAYA,CAAChB,KAAkC,EAAE;IAC/C,OAAO,IAAI,CAACE,cAAc,CAACF,KAAK,CAAC,GAC5BA,KAAK,GACNG,SAAS;EACf;EAEAc,wBAAwBA,CAAClB,KAA0B,EAAE;IACnD,OAAO,IAAI,CAACG,cAAc,CAACH,KAAK,CAAC,GAC7B,cAAcA,KAAK,CAACpB,SAAS,aAAab,cAAc,CAACiC,KAAK,CAACnB,MAAM,CAAC,EAAE,GACxE,EAAE;EACR;;EAEA;AACF;AACA;EACEsC,oBAAoBA,CAAA,EAA6B;IAC/C,OAAOlD,YAAY,CAACkD,oBAAoB,CAAC,CAAC;EAC5C;;EAEA;AACF;AACA;EACE,OAAOA,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CACV;QACEC,IAAI,EAAE,iBAAiB;QACvBC,QAAQ,EAAE;MACZ,CAAC,CACF;MACDC,sBAAsB,EAAE;IAC1B,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;EACE,OAAOC,aAAaA,CAClBlD,OAAyC,EACzCmD,KAAgB,EAChBzB,KAAgB,EACR;IACR,MAAM;MAAE0B;IAAmB,CAAC,GAAGpD,OAAO;IAEtC,IAAI,CAACoD,kBAAkB,EAAEC,MAAM,EAAE;MAC/B,OAAOrD,OAAO,CAACO,MAAM;IACvB;IAEA,KAAK,MAAM;MAAE+C,SAAS;MAAE/C;IAAO,CAAC,IAAI6C,kBAAkB,EAAE;MACtD,IAAI,CAACD,KAAK,CAACI,UAAU,CAACD,SAAS,CAAC,EAAE;QAChCtE,MAAM,CAACwE,IAAI,CACT,wBAAwBF,SAAS,2CACnC,CAAC;QACD;MACF;MACA,IAAIH,KAAK,CAACI,UAAU,CAACD,SAAS,CAAC,CAACG,EAAE,CAAC/B,KAAK,CAAC,EAAE;QACzC,OAAOnB,MAAM;MACf;IACF;IAEA,OAAOP,OAAO,CAACO,MAAM;EACvB;;EAEA;AACF;AACA;EACE,aAAamD,UAAUA,CACrBC,OAA2B,EAC3BC,CAAsB,EACtBC,IAAyB,EACP;IAClB,MAAM;MAAE7D,OAAO;MAAE4B,IAAI,EAAEkC;IAAc,CAAC,GAAGD,IAAI,CAACE,SAAS;IACvD,MAAM;MAAEZ;IAAM,CAAC,GAAGU,IAAI,CAACG,UAAU;IACjC,MAAM;MAAEC,QAAQ;MAAEC,CAAC;MAAE5B;IAAW,CAAC,GAAGa,KAAK,CAACgB,gBAAgB,CACxDzE,eAAe,CAACiE,OAAO,CACzB,CAAC;IACD,MAAMjC,KAAK,GAAG,MAAMmC,IAAI,CAACG,UAAU,CAACI,QAAQ,CAACT,OAAO,CAAC;IACrD,MAAM;MAAEU;IAAQ,CAAC,GAAGjF,gBAAgB,CAACuE,OAAO,CAACW,MAAM,CAAC;IACpD,MAAMC,UAAU,GAAG,GAAGF,OAAO,IAAIlB,KAAK,CAACqB,QAAQ,UAAU;IAEzD,MAAMC,oBAAoB,GAAG/C,KAAK,CAACoC,aAAa,CAAC;IACjD,IACEnE,YAAY,CAACkC,cAAc,CAAC4C,oBAAoB,CAAC,IACjDA,oBAAoB,CAACzD,OAAO,EAAEC,MAAM,KAAK,SAAS,EAClD;MACA,OAAO2C,CAAC,CAACc,QAAQ,CAACH,UAAU,CAAC,CAACI,IAAI,CAAC7F,WAAW,CAAC8F,SAAS,CAAC;IAC3D;IAEA,MAAM9D,aAAa,GAAG+C,IAAI,CAACgB,MAAM,IAAI,CAAChB,IAAI,CAACiB,SAAS;IACpD,MAAMjE,MAAM,GAAGgD,IAAI,CAACG,UAAU,CAACb,KAAK,CAACtC,MAAM;IAC3C,MAAMkE,YAAY,GAAG5B,KAAK,CAAC6B,QAAQ,CAACD,YAAY;IAChD,MAAME,cAAc,GAAG,MAAMzF,oBAAoB,CAC/CsB,aAAa,EACbD,MAAM,EACNkE,YACF,CAAC;IAED,MAAMnE,IAAI,GAAG/B,UAAU,CAAC,CAAC;IAEzB,MAAMyB,SAAS,GAAGoB,KAAK,CAACwD,mBAA6B;IACrD,MAAMC,cAAc,GAAGxF,YAAY,CAACuD,aAAa,CAAClD,OAAO,EAAEmD,KAAK,EAAEzB,KAAK,CAAC;;IAExE;IACA,IAAIyD,cAAc,KAAK,CAAC,EAAE;MACxB,OAAOvB,CAAC,CAACc,QAAQ,CAACH,UAAU,CAAC,CAACI,IAAI,CAAC7F,WAAW,CAAC8F,SAAS,CAAC;IAC3D;IAEA,MAAMnE,WAAW,GACf6B,UAAU,CAACuB,IAAI,CAACE,SAAS,EAAE,oBAAoB,CAAC,IAAI/D,OAAO,CAACS,WAAW;IAEzE,MAAM2E,IAAI,GAAG,IAAIjC,KAAK,CAACqB,QAAQ,EAAE;IAEjC,MAAMa,cAAc,GAAG,GAAGhB,OAAO,0BAA0BzD,IAAI,EAAE;IACjE,MAAM0E,cAAc,GAAGzB,IAAI,CAAC0B,SAAS;IAErC,IAAIC,cAAkC;IACtC,MAAMC,qBAAqB,GAAG/D,KAAK,CAACgE,4BAA4B;IAChE,IAAI,OAAOD,qBAAqB,KAAK,QAAQ,IAAIA,qBAAqB,EAAE;MACtED,cAAc,GAAGC,qBAAqB;IACxC;IAEA,MAAME,aAAa,GAAGC,IAAI,CAACC,KAAK,CAACV,cAAc,GAAG,GAAG,CAAC;IACtD,MAAMW,OAAO,GAAG,MAAMb,cAAc,CAACc,aAAa,CAChDJ,aAAa,EACblF,WAAW,EACX4E,cAAc,EACd/E,SAAS,EACTQ,aAAa,EACb;MAAED,MAAM;MAAEuE,IAAI;MAAEnB;IAAS,CAAC,EAC1BuB,cACF,CAAC;IAED,IAAI,CAACM,OAAO,EAAE;MACZ,MAAME,OAAO,GAAGlF,aAAa,GACzBoD,CAAC,CAAC,2CAA2C,CAAC,GAC9CA,CAAC,CAAC,oCAAoC,CAAC;MAC3C,MAAM+B,UAAU,GAAG9G,WAAW,CAAC2E,aAAa,EAAEkC,OAAO,CAAC;MACtDrC,OAAO,CAACuC,GAAG,CAACC,KAAK,CAAClH,qBAAqB,EAAEgH,UAAU,EAAE,IAAI,CAAC;MAC1D,OAAOrC,CAAC,CACLc,QAAQ,CAAC,GAAGf,OAAO,CAACyC,GAAG,CAACC,QAAQ,GAAG1C,OAAO,CAACyC,GAAG,CAACE,MAAM,EAAE,CAAC,CACxD3B,IAAI,CAAC7F,WAAW,CAAC8F,SAAS,CAAC;IAChC;IAEA,MAAM2B,WAA+B,GAAG;MACtC3F,IAAI;MACJC,MAAM;MACNP,SAAS;MACTC,MAAM,EAAE4E,cAAc;MACtB1E,WAAW;MACXC,gBAAgB,EAAEV,OAAO,CAACS,WAAW;MACrCN,SAAS,EAAE2F,OAAO,CAAC3F,SAAS;MAC5B2D,aAAa;MACb0C,SAAS,EAAEjC,UAAU;MACrBkC,UAAU,EAAEnB,cAAc;MAC1BxE;IACF,CAAC;IAED6C,OAAO,CAACuC,GAAG,CAACQ,GAAG,CAAC,WAAW9F,IAAI,EAAE,EAAE2F,WAAW,CAAC;IAE/C,OAAO3C,CAAC,CAACc,QAAQ,CAACoB,OAAO,CAACa,UAAU,CAAC,CAAChC,IAAI,CAAC7F,WAAW,CAAC8F,SAAS,CAAC;EACnE;;EAEA;AACF;AACA;AACA;EACE,MAAMgC,QAAQA,CACZjD,OAA2B,EAC3BkD,SAAuB,EACvB3E,OAAoB,EACL;IACf,MAAM+B,QAAQ,GAAGvE,eAAe,CAACiE,OAAO,CAAC;IACzC,MAAM;MAAEO;IAAE,CAAC,GAAG,IAAI,CAACf,KAAK,CAACgB,gBAAgB,CAACF,QAAQ,CAAC;;IAEnD;IACA,MAAMkB,cAAc,GAAGxF,YAAY,CAACuD,aAAa,CAC/C,IAAI,CAAClD,OAAO,EACZ,IAAI,CAACmD,KAAK,EACVjB,OAAO,CAACR,KACV,CAAC;IACD,IAAIyD,cAAc,KAAK,CAAC,EAAE;MACxB;IACF;IAEA,MAAM5C,YAAY,GAAG,IAAI,CAACd,wBAAwB,CAACS,OAAO,CAACR,KAAK,CAAC;IAEjE,IAAI,CAACa,YAAY,EAAE;MACjB,MAAM,IAAIjD,mBAAmB,CAC3B,IAAI,EACJ4E,CAAC,CAAC,yCAAyC,CAAC,EAC5C,IAAI,EACJ7E,iBAAiB,CAACyH,iBACpB,CAAC;IACH;IAEA,IAAIvE,YAAY,CAACwE,OAAO,EAAE9F,MAAM,KAAK,SAAS,EAAE;MAC9C;IACF;IAEA,MAAM;MAAEd,SAAS;MAAEW,aAAa;MAAED;IAAO,CAAC,GAAG0B,YAAY;IACzD,MAAMwC,YAAY,GAAG,IAAI,CAAC5B,KAAK,CAAC6B,QAAQ,CAACD,YAAY;IACrD,MAAME,cAAc,GAAG,MAAMzF,oBAAoB,CAC/CsB,aAAa,EACbD,MAAM,EACNkE,YACF,CAAC;;IAED;AACJ;AACA;IACI,MAAM9D,MAAM,GAAG,MAAMgE,cAAc,CAAC+B,gBAAgB,CAClD7G,SAAS,EACTW,aACF,CAAC;IAEDvB,sBAAsB,CAAC0H,kBAAkB,CACvChG,MAAM,CAACV,MAAM,EACb4E,cAAc,EACd,IAAI,EACJjB,CACF,CAAC;IAED,IAAIjD,MAAM,CAACS,KAAK,CAACT,MAAM,KAAK,SAAS,EAAE;MACrC,MAAM,IAAI,CAACiG,mBAAmB,CAACvD,OAAO,EAAEpB,YAAY,CAAC;MACrD;IACF;IAEA,IAAItB,MAAM,CAACS,KAAK,CAACT,MAAM,KAAK,YAAY,EAAE;MACxC,MAAM,IAAI3B,mBAAmB,CAC3B,IAAI,EACJ4E,CAAC,CAAC,wCAAwC,CAAC,EAC3C,IAAI,EACJ7E,iBAAiB,CAAC8H,cACpB,CAAC;IACH;IAEA,MAAMC,QAAQ,GAAG,MAAMnC,cAAc,CAACoC,cAAc,CAClDlH,SAAS,EACTc,MAAM,CAACV,MACT,CAAC;IAED,IAAI,CAAC6G,QAAQ,EAAE;MACb,MAAM,IAAI9H,mBAAmB,CAC3B,IAAI,EACJ4E,CAAC,CAAC,0CAA0C,CAAC,EAC7C,KACF,CAAC;IACH;IAEA,MAAM,IAAI,CAACgD,mBAAmB,CAACvD,OAAO,EAAEpB,YAAY,CAAC;EACvD;;EAEA;AACF;AACA;AACA;EACE,MAAc2E,mBAAmBA,CAC/BvD,OAA2B,EAC3BpB,YAA0B,EACX;IACf,MAAM+E,YAA0B,GAAG;MACjC,GAAG/E,YAAY;MACfwE,OAAO,EAAE;QACP9F,MAAM,EAAE,SAAS;QACjBE,SAAS,EAAE,IAAIoG,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;MACpC;IACF,CAAC;IAED,IAAI,IAAI,CAACC,IAAI,EAAE;MACb,MAAMC,YAAY,GAAG,MAAM,IAAI,CAACD,IAAI,CAACrD,QAAQ,CAACT,OAAO,CAAC;MACtD,MAAM,IAAI,CAAC8D,IAAI,CAACE,UAAU,CAAChE,OAAO,EAAE+D,YAAY,EAAE;QAChD,CAAC,IAAI,CAAC9F,IAAI,GAAG0F;MACf,CAAC,CAAC;IACJ;EACF;AACF;;AAEA;AACA;AACA","ignoreList":[]}
@@ -51,6 +51,7 @@ export declare class SelectField extends ListFormComponent {
51
51
  upload?: {
52
52
  count: number;
53
53
  summaryList: import("../types.js").SummaryList;
54
+ uploadingLabel?: string;
54
55
  };
55
56
  };
56
57
  }
@@ -52,6 +52,7 @@ export declare class SelectionControlField extends ListFormComponent {
52
52
  upload?: {
53
53
  count: number;
54
54
  summaryList: import("../../../../server/plugins/engine/types.js").SummaryList;
55
+ uploadingLabel?: string;
55
56
  };
56
57
  };
57
58
  /**
@@ -55,6 +55,7 @@ export declare class TelephoneNumberField extends FormComponent {
55
55
  upload?: {
56
56
  count: number;
57
57
  summaryList: import("../../../../server/plugins/engine/types.js").SummaryList;
58
+ uploadingLabel?: string;
58
59
  };
59
60
  };
60
61
  /**
@@ -0,0 +1,21 @@
1
+ import { type TrackingFieldComponent } from '@defra/forms-model';
2
+ import { type BooleanSchema } from 'joi';
3
+ import { FormComponent } from '../../../../server/plugins/engine/components/FormComponent.js';
4
+ import { type ErrorMessageTemplateList, type FormState, type FormStateValue, type FormSubmissionState } from '../../../../server/plugins/engine/types.js';
5
+ export declare class TrackingField extends FormComponent {
6
+ formSchema: BooleanSchema;
7
+ stateSchema: BooleanSchema;
8
+ options: TrackingFieldComponent['options'];
9
+ constructor(def: TrackingFieldComponent, props: ConstructorParameters<typeof FormComponent>[1]);
10
+ getFormValueFromState(state: FormSubmissionState): NonNullable<FormStateValue> | undefined;
11
+ isValue(value?: FormStateValue | FormState): value is true;
12
+ /**
13
+ * For error preview page that shows all possible errors on a component
14
+ */
15
+ getAllPossibleErrors(): ErrorMessageTemplateList;
16
+ static isTracking(value?: FormStateValue | FormState): value is true;
17
+ /**
18
+ * Static version of getAllPossibleErrors that doesn't require a component instance.
19
+ */
20
+ static getAllPossibleErrors(): ErrorMessageTemplateList;
21
+ }
@@ -0,0 +1,46 @@
1
+ import joi from 'joi';
2
+ import { FormComponent, isFormValue } from "./FormComponent.js";
3
+ import { messageTemplate } from "../pageControllers/validationOptions.js";
4
+ export class TrackingField extends FormComponent {
5
+ constructor(def, props) {
6
+ super(def, props);
7
+ const formSchema = joi.boolean().valid(true).label(this.label).required();
8
+ this.formSchema = formSchema.default(false);
9
+ this.stateSchema = formSchema.default(null).allow(null);
10
+ this.schema = {};
11
+ this.options = {};
12
+ }
13
+ getFormValueFromState(state) {
14
+ const {
15
+ name
16
+ } = this;
17
+ return this.getFormValue(state[name]);
18
+ }
19
+ isValue(value) {
20
+ return TrackingField.isTracking(value);
21
+ }
22
+
23
+ /**
24
+ * For error preview page that shows all possible errors on a component
25
+ */
26
+ getAllPossibleErrors() {
27
+ return TrackingField.getAllPossibleErrors();
28
+ }
29
+ static isTracking(value) {
30
+ return isFormValue(value) && typeof value === 'boolean';
31
+ }
32
+
33
+ /**
34
+ * Static version of getAllPossibleErrors that doesn't require a component instance.
35
+ */
36
+ static getAllPossibleErrors() {
37
+ return {
38
+ baseErrors: [{
39
+ type: 'required',
40
+ template: messageTemplate.required
41
+ }],
42
+ advancedSettingsErrors: []
43
+ };
44
+ }
45
+ }
46
+ //# sourceMappingURL=TrackingField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrackingField.js","names":["joi","FormComponent","isFormValue","messageTemplate","TrackingField","constructor","def","props","formSchema","boolean","valid","label","required","default","stateSchema","allow","schema","options","getFormValueFromState","state","name","getFormValue","isValue","value","isTracking","getAllPossibleErrors","baseErrors","type","template","advancedSettingsErrors"],"sources":["../../../../../src/server/plugins/engine/components/TrackingField.ts"],"sourcesContent":["import { type TrackingFieldComponent } from '@defra/forms-model'\nimport joi, { type BooleanSchema } from 'joi'\n\nimport {\n FormComponent,\n isFormValue\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'\nimport {\n type ErrorMessageTemplateList,\n type FormState,\n type FormStateValue,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class TrackingField extends FormComponent {\n declare formSchema: BooleanSchema\n declare stateSchema: BooleanSchema\n declare options: TrackingFieldComponent['options']\n\n constructor(\n def: TrackingFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n const formSchema = joi.boolean().valid(true).label(this.label).required()\n\n this.formSchema = formSchema.default(false)\n this.stateSchema = formSchema.default(null).allow(null)\n this.schema = {}\n this.options = {}\n }\n\n getFormValueFromState(state: FormSubmissionState) {\n const { name } = this\n return this.getFormValue(state[name])\n }\n\n isValue(value?: FormStateValue | FormState): value is true {\n return TrackingField.isTracking(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return TrackingField.getAllPossibleErrors()\n }\n\n static isTracking(value?: FormStateValue | FormState): value is true {\n return isFormValue(value) && typeof value === 'boolean'\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [{ type: 'required', template: messageTemplate.required }],\n advancedSettingsErrors: []\n }\n }\n}\n"],"mappings":"AACA,OAAOA,GAAG,MAA8B,KAAK;AAE7C,SACEC,aAAa,EACbC,WAAW;AAEb,SAASC,eAAe;AAQxB,OAAO,MAAMC,aAAa,SAASH,aAAa,CAAC;EAK/CI,WAAWA,CACTC,GAA2B,EAC3BC,KAAqD,EACrD;IACA,KAAK,CAACD,GAAG,EAAEC,KAAK,CAAC;IAEjB,MAAMC,UAAU,GAAGR,GAAG,CAACS,OAAO,CAAC,CAAC,CAACC,KAAK,CAAC,IAAI,CAAC,CAACC,KAAK,CAAC,IAAI,CAACA,KAAK,CAAC,CAACC,QAAQ,CAAC,CAAC;IAEzE,IAAI,CAACJ,UAAU,GAAGA,UAAU,CAACK,OAAO,CAAC,KAAK,CAAC;IAC3C,IAAI,CAACC,WAAW,GAAGN,UAAU,CAACK,OAAO,CAAC,IAAI,CAAC,CAACE,KAAK,CAAC,IAAI,CAAC;IACvD,IAAI,CAACC,MAAM,GAAG,CAAC,CAAC;IAChB,IAAI,CAACC,OAAO,GAAG,CAAC,CAAC;EACnB;EAEAC,qBAAqBA,CAACC,KAA0B,EAAE;IAChD,MAAM;MAAEC;IAAK,CAAC,GAAG,IAAI;IACrB,OAAO,IAAI,CAACC,YAAY,CAACF,KAAK,CAACC,IAAI,CAAC,CAAC;EACvC;EAEAE,OAAOA,CAACC,KAAkC,EAAiB;IACzD,OAAOnB,aAAa,CAACoB,UAAU,CAACD,KAAK,CAAC;EACxC;;EAEA;AACF;AACA;EACEE,oBAAoBA,CAAA,EAA6B;IAC/C,OAAOrB,aAAa,CAACqB,oBAAoB,CAAC,CAAC;EAC7C;EAEA,OAAOD,UAAUA,CAACD,KAAkC,EAAiB;IACnE,OAAOrB,WAAW,CAACqB,KAAK,CAAC,IAAI,OAAOA,KAAK,KAAK,SAAS;EACzD;;EAEA;AACF;AACA;EACE,OAAOE,oBAAoBA,CAAA,EAA6B;IACtD,OAAO;MACLC,UAAU,EAAE,CAAC;QAAEC,IAAI,EAAE,UAAU;QAAEC,QAAQ,EAAEzB,eAAe,CAACS;MAAS,CAAC,CAAC;MACtEiB,sBAAsB,EAAE;IAC1B,CAAC;EACH;AACF","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 {@link QuestionPageController | `showTitle` handling}
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: controller.model.name,
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.hint,
250
- componentTitle: component.title || controller.title,
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,9 @@ 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): LanguageMessages;
12
+ getValidationMessagesOverride(translator: Translator): {
13
+ [x: string]: import("joi").LanguageMessages;
14
+ };
14
15
  /**
15
16
  * For error preview page that shows all possible errors on a component
16
17
  */
@@ -1,10 +1,8 @@
1
1
  import { SchemaVersion, yesNoListId, yesNoListName } from '@defra/forms-model';
2
2
  import { SelectionControlField } from "./SelectionControlField.js";
3
- import { addClassOptionIfNone } from "./helpers/index.js";
3
+ import { addClassOptionIfNone, withCustomValidationOverrides } 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,19 +23,35 @@ export class YesNoField extends SelectionControlField {
25
23
  if (options.required === false) {
26
24
  formSchema = formSchema.optional();
27
25
  }
28
- formSchema = formSchema.messages(convertToLanguageMessages({
29
- 'any.required': messageTemplate.selectYesNoRequired
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
  }
34
41
  getValidationMessagesOverride(translator) {
42
+ const {
43
+ customValidationMessage,
44
+ customValidationMessages
45
+ } = this.options;
35
46
  const {
36
47
  selectYesNoRequired
37
48
  } = buildValidationMessages(translator.t);
38
- return convertToLanguageMessages({
49
+ const defaults = {
39
50
  'any.required': selectYesNoRequired
40
- });
51
+ };
52
+ return {
53
+ [this.name]: withCustomValidationOverrides(defaults, customValidationMessage, customValidationMessages)
54
+ };
41
55
  }
42
56
 
43
57
  /**