@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
@@ -15,6 +15,7 @@ import {
15
15
  type Field,
16
16
  type Guidance
17
17
  } from './helpers/components.js'
18
+ import { getTranslatedLabel } from './helpers/index.js'
18
19
  import {
19
20
  type ComponentViewModel,
20
21
  type RenderContext
@@ -258,10 +259,7 @@ export class ComponentCollection {
258
259
 
259
260
  // Update error with parent title
260
261
  if (translator && parent) {
261
- error.local.title ??= translator.tComponent(
262
- parent as ComponentDef,
263
- 'title'
264
- )
262
+ error.local.title ??= getTranslatedLabel(parent.def, translator)
265
263
  } else {
266
264
  error.local.title ??= parent?.label
267
265
  }
@@ -302,26 +300,28 @@ export class ComponentCollection {
302
300
  for (const subField of field.collection.fields) {
303
301
  const translatedSubLabel = t(subField.title) || subField.label
304
302
  let patchedSchema = subField.formSchema.label(translatedSubLabel)
305
- if (messagesOverride) {
306
- patchedSchema = patchedSchema.messages(messagesOverride)
303
+ const subFieldMessages = messagesOverride
304
+ ? messagesOverride[subField.name]
305
+ : undefined
306
+ if (subFieldMessages) {
307
+ patchedSchema = patchedSchema.messages(subFieldMessages)
307
308
  }
308
309
  labelOverrides[subField.name] = patchedSchema
309
310
  }
310
311
  } else {
311
- const translatedLabel =
312
- translator.tComponent(
313
- field as unknown as ComponentDef,
314
- 'shortDescription'
315
- ) ||
316
- translator.tComponent(field as unknown as ComponentDef, 'title')
312
+ const fieldDef = field.def
313
+ const translatedLabel = getTranslatedLabel(fieldDef, translator)
317
314
  const messagesOverride =
318
315
  field.getValidationMessagesOverride(translator)
319
316
  let patchedSchema = field.formSchema
320
317
  if (translatedLabel && translatedLabel !== field.label) {
321
318
  patchedSchema = patchedSchema.label(translatedLabel)
322
319
  }
323
- if (messagesOverride) {
324
- patchedSchema = patchedSchema.messages(messagesOverride)
320
+ const fieldMessages = messagesOverride
321
+ ? messagesOverride[field.name]
322
+ : undefined
323
+ if (fieldMessages) {
324
+ patchedSchema = patchedSchema.messages(fieldMessages)
325
325
  }
326
326
  if (patchedSchema !== field.formSchema) {
327
327
  labelOverrides[field.name] = patchedSchema
@@ -340,10 +340,12 @@ export class ComponentCollection {
340
340
  })
341
341
 
342
342
  const details = result.error?.details
343
+ const language = translator?.language
343
344
 
344
345
  return {
345
346
  value: (result.value ?? {}) as typeof value,
346
- errors: this.page?.getErrors(details) ?? getErrors(details)
347
+ errors:
348
+ this.page?.getErrors(details, language) ?? getErrors(language, details)
347
349
  }
348
350
  }
349
351
 
@@ -1,6 +1,11 @@
1
1
  import { ComponentType, type DatePartsFieldComponent } from '@defra/forms-model'
2
2
  import { add, format, isValid, parse, startOfToday, sub } from 'date-fns'
3
- import { type Context, type CustomValidator, type ObjectSchema } from 'joi'
3
+ import {
4
+ type Context,
5
+ type CustomValidator,
6
+ type LanguageMessages,
7
+ type ObjectSchema
8
+ } from 'joi'
4
9
 
5
10
  import { ComponentCollection } from './ComponentCollection.js'
6
11
  import {
@@ -25,7 +30,7 @@ import {
25
30
  type FormStateValue,
26
31
  type FormSubmissionState
27
32
  } from '../types.js'
28
- import { convertToLanguageMessages } from '../../../utils/type-utils.js'
33
+ import { formatDateForLanguage } from '../../payment/helper.js'
29
34
 
30
35
  export class DatePartsField extends FormComponent {
31
36
  declare options: DatePartsFieldComponent['options']
@@ -43,7 +48,7 @@ export class DatePartsField extends FormComponent {
43
48
 
44
49
  const isRequired = options.required !== false
45
50
 
46
- const customValidationMessages = convertToLanguageMessages({
51
+ const customValidationMessages = {
47
52
  'any.required': messageTemplate.objectMissing,
48
53
  'number.base': messageTemplate.objectMissing,
49
54
  'number.precision': messageTemplate.dateFormat,
@@ -51,7 +56,7 @@ export class DatePartsField extends FormComponent {
51
56
  'number.unsafe': messageTemplate.dateFormat,
52
57
  'number.min': messageTemplate.dateFormat,
53
58
  'number.max': messageTemplate.dateFormat
54
- })
59
+ } as LanguageMessages
55
60
 
56
61
  this.collection = new ComponentCollection(
57
62
  [
@@ -111,15 +116,16 @@ export class DatePartsField extends FormComponent {
111
116
 
112
117
  getDisplayStringFromFormValue(
113
118
  formValue: DatePartsState | undefined,
114
- _translator: Translator
119
+ translator: Translator
115
120
  ) {
116
121
  if (!formValue) {
117
122
  return ''
118
123
  }
119
124
 
120
- return format(
125
+ return formatDateForLanguage(
121
126
  `${formValue.year}-${formValue.month}-${formValue.day}`,
122
- 'd MMMM yyyy'
127
+ 'd MMMM yyyy',
128
+ translator.language
123
129
  )
124
130
  }
125
131
 
@@ -158,7 +164,7 @@ export class DatePartsField extends FormComponent {
158
164
 
159
165
  getValidationMessagesOverride(translator: Translator) {
160
166
  const { t } = translator
161
- return convertToLanguageMessages({
167
+ const messages = {
162
168
  'any.required': buildValidationMessages(t).objectMissing,
163
169
  'number.base': buildValidationMessages(t).objectMissing,
164
170
  'number.precision': buildValidationMessages(t).dateFormat,
@@ -166,7 +172,12 @@ export class DatePartsField extends FormComponent {
166
172
  'number.unsafe': buildValidationMessages(t).dateFormat,
167
173
  'number.min': buildValidationMessages(t).dateFormat,
168
174
  'number.max': buildValidationMessages(t).dateFormat
169
- })
175
+ } as LanguageMessages
176
+ return {
177
+ [`${this.name}__day`]: messages,
178
+ [`${this.name}__month`]: messages,
179
+ [`${this.name}__year`]: messages
180
+ }
170
181
  }
171
182
 
172
183
  getViewModel(context: RenderContext) {
@@ -2,15 +2,13 @@ import {
2
2
  ComponentType,
3
3
  hasFormComponents,
4
4
  isFormType,
5
- type ComponentDef,
6
5
  type DeclarationFieldComponent,
7
6
  type Item
8
7
  } from '@defra/forms-model'
9
8
  import joi, {
10
9
  type ArraySchema,
11
10
  type BooleanSchema,
12
- type LanguageMessages,
13
- type StringSchema
11
+ type LanguageMessages
14
12
  } from 'joi'
15
13
 
16
14
  import {
@@ -35,7 +33,7 @@ export class DeclarationField extends FormComponent {
35
33
 
36
34
  declare declarationConfirmationLabel: string | undefined
37
35
 
38
- declare formSchema: ArraySchema<StringSchema[]>
36
+ declare formSchema: ArraySchema<string[]>
39
37
  declare stateSchema: BooleanSchema
40
38
  declare content: string
41
39
  headerStartLevel: number
@@ -64,7 +62,7 @@ export class DeclarationField extends FormComponent {
64
62
  'any.unknown': messageTemplate.declarationRequired as string,
65
63
  'array.includesRequiredUnknowns':
66
64
  messageTemplate.declarationRequired as string
67
- }) as ArraySchema<StringSchema[]>
65
+ })
68
66
 
69
67
  this.formSchema = formSchema
70
68
  this.stateSchema = joi.boolean().cast('string').label(this.label).required()
@@ -121,10 +119,12 @@ export class DeclarationField extends FormComponent {
121
119
  const { declarationRequired } = buildValidationMessages(translator.t)
122
120
  const msg = declarationRequired as unknown as string
123
121
  return {
124
- 'any.required': msg,
125
- 'any.unknown': msg,
126
- 'array.includesRequiredUnknowns': msg
127
- } as unknown as LanguageMessages
122
+ [this.name]: {
123
+ 'any.required': msg,
124
+ 'any.unknown': msg,
125
+ 'array.includesRequiredUnknowns': msg
126
+ } as unknown as LanguageMessages
127
+ }
128
128
  }
129
129
 
130
130
  getDisplayStringFromFormValue(
@@ -148,7 +148,7 @@ export class DeclarationField extends FormComponent {
148
148
  'components.declarationField.defaultLabel'
149
149
  )
150
150
  } = this
151
- const content = tComponent(this as unknown as ComponentDef, 'content')
151
+ const content = tComponent(this.def, 'content')
152
152
 
153
153
  const viewModel = super.getViewModel(context)
154
154
  let { fieldset, label } = viewModel
@@ -15,7 +15,11 @@ import {
15
15
  getLocationFieldViewModel
16
16
  } from './LocationFieldHelpers.js'
17
17
  import { NumberField } from './NumberField.js'
18
- import { createLowerFirstExpression } from './helpers/index.js'
18
+ import { getEastingNorthingCountryValidator } from './helpers/geospatial.js'
19
+ import {
20
+ createLowerFirstExpression,
21
+ getTranslatedLabel
22
+ } from './helpers/index.js'
19
23
  import {
20
24
  type EastingNorthingState,
21
25
  type RenderContext
@@ -31,7 +35,6 @@ import {
31
35
  type FormSubmissionError,
32
36
  type FormSubmissionState
33
37
  } from '../types.js'
34
- import { convertToLanguageMessages } from '../../../utils/type-utils.js'
35
38
 
36
39
  // British National Grid coordinate limits
37
40
  const DEFAULT_EASTING_MIN = 0
@@ -55,89 +58,18 @@ export class EastingNorthingField extends FormComponent {
55
58
 
56
59
  const isRequired = options.required !== false
57
60
 
58
- const eastingMin = schema?.easting?.min ?? DEFAULT_EASTING_MIN
59
- const eastingMax = schema?.easting?.max ?? DEFAULT_EASTING_MAX
60
- const northingMin = schema?.northing?.min ?? DEFAULT_NORTHING_MIN
61
- const northingMax = schema?.northing?.max ?? DEFAULT_NORTHING_MAX
62
-
63
- const fieldLabel = lowerFirst(this.label)
61
+ const { eastingMin, eastingMax, northingMin, northingMax } =
62
+ EastingNorthingField.getMinMax(schema)
64
63
 
65
- const eastingDigitsMessage = tPlugin(
66
- 'components.eastingNorthingField.eastingDigits',
67
- 'en-GB',
68
- { fieldLabel }
69
- )
70
- const northingDigitsMessage = tPlugin(
71
- 'components.eastingNorthingField.northingDigits',
72
- 'en-GB',
73
- { fieldLabel }
74
- )
75
-
76
- const customValidationMessages: LanguageMessages =
77
- convertToLanguageMessages({
78
- 'any.required': tPlugin(
79
- 'components.eastingNorthingField.eastingRequired',
80
- 'en-GB'
81
- ),
82
- 'number.base': tPlugin(
83
- 'components.eastingNorthingField.eastingRequired',
84
- 'en-GB'
85
- ),
86
- 'number.min': tPlugin(
87
- 'components.eastingNorthingField.eastingRange',
88
- 'en-GB',
89
- {
90
- fieldLabel,
91
- min: eastingMin,
92
- max: eastingMax
93
- }
94
- ),
95
- 'number.max': tPlugin(
96
- 'components.eastingNorthingField.eastingRange',
97
- 'en-GB',
98
- {
99
- fieldLabel,
100
- min: eastingMin,
101
- max: eastingMax
102
- }
103
- ),
104
- 'number.precision': eastingDigitsMessage,
105
- 'number.integer': eastingDigitsMessage,
106
- 'number.unsafe': eastingDigitsMessage
107
- })
108
-
109
- const northingValidationMessages: LanguageMessages =
110
- convertToLanguageMessages({
111
- 'any.required': tPlugin(
112
- 'components.eastingNorthingField.northingRequired',
113
- 'en-GB'
114
- ),
115
- 'number.base': tPlugin(
116
- 'components.eastingNorthingField.northingRequired',
117
- 'en-GB'
118
- ),
119
- 'number.min': tPlugin(
120
- 'components.eastingNorthingField.northingRange',
121
- 'en-GB',
122
- {
123
- fieldLabel,
124
- min: northingMin,
125
- max: northingMax
126
- }
127
- ),
128
- 'number.max': tPlugin(
129
- 'components.eastingNorthingField.northingRange',
130
- 'en-GB',
131
- {
132
- fieldLabel,
133
- min: northingMin,
134
- max: northingMax
135
- }
136
- ),
137
- 'number.precision': northingDigitsMessage,
138
- 'number.integer': northingDigitsMessage,
139
- 'number.unsafe': northingDigitsMessage
140
- })
64
+ const { eastingValidationMessages, northingValidationMessages } =
65
+ EastingNorthingField.buildErrorMessages(
66
+ this.label,
67
+ eastingMin,
68
+ eastingMax,
69
+ northingMin,
70
+ northingMax,
71
+ 'en-GB'
72
+ )
141
73
 
142
74
  this.collection = new ComponentCollection(
143
75
  [
@@ -154,7 +86,7 @@ export class EastingNorthingField extends FormComponent {
154
86
  required: isRequired,
155
87
  optionalText: true,
156
88
  classes: 'govuk-input--width-10',
157
- customValidationMessages
89
+ customValidationMessages: eastingValidationMessages
158
90
  }
159
91
  },
160
92
  {
@@ -181,6 +113,18 @@ export class EastingNorthingField extends FormComponent {
181
113
  )
182
114
 
183
115
  this.options = options
116
+
117
+ const country = options.countries?.at(0)
118
+
119
+ if (country) {
120
+ this.collection.formSchema = this.collection.formSchema.custom(
121
+ getEastingNorthingCountryValidator(this, country)
122
+ )
123
+ this.collection.stateSchema = this.collection.stateSchema.custom(
124
+ getEastingNorthingCountryValidator(this, country)
125
+ )
126
+ }
127
+
184
128
  this.formSchema = this.collection.formSchema
185
129
  this.stateSchema = this.collection.stateSchema
186
130
  }
@@ -192,14 +136,15 @@ export class EastingNorthingField extends FormComponent {
192
136
 
193
137
  getDisplayStringFromFormValue(
194
138
  value: EastingNorthingState | undefined,
195
- _translator: Translator
139
+ translator: Translator
196
140
  ): string {
197
141
  if (!value) {
198
142
  return ''
199
143
  }
200
144
 
201
- // CYA page format: <<eastingvalue, northingvalue>>
202
- return `${value.easting}, ${value.northing}`
145
+ const { t } = translator
146
+
147
+ return `${t('components.eastingNorthingField.easting')}: ${value.easting}\n${t('components.eastingNorthingField.northing')}: ${value.northing}`
203
148
  }
204
149
 
205
150
  getDisplayStringFromState(
@@ -218,7 +163,7 @@ export class EastingNorthingField extends FormComponent {
218
163
  return null
219
164
  }
220
165
 
221
- return `Easting: ${value.easting}\nNorthing: ${value.northing}`
166
+ return `${value.easting}, ${value.northing}`
222
167
  }
223
168
 
224
169
  getContextValueFromState(state: FormSubmissionState) {
@@ -232,6 +177,24 @@ export class EastingNorthingField extends FormComponent {
232
177
  return getLocationFieldViewModel(this, viewModel, context)
233
178
  }
234
179
 
180
+ getErrors(
181
+ translator: Translator,
182
+ errors?: FormSubmissionError[]
183
+ ): FormSubmissionError[] | undefined {
184
+ const fieldErrors = super.getErrors(translator, errors)
185
+
186
+ fieldErrors?.forEach((err) => {
187
+ if (err.context?.country) {
188
+ err.text = translator.t(
189
+ 'components.eastingNorthingField.wrongCountry',
190
+ { country: translator.t(`common.${err.context.country}`) }
191
+ )
192
+ }
193
+ })
194
+
195
+ return fieldErrors
196
+ }
197
+
235
198
  getViewErrors(
236
199
  translator: Translator,
237
200
  errors?: FormSubmissionError[]
@@ -244,6 +207,26 @@ export class EastingNorthingField extends FormComponent {
244
207
  return EastingNorthingField.isEastingNorthing(value)
245
208
  }
246
209
 
210
+ getValidationMessagesOverride(translator: Translator) {
211
+ const def = this.def as EastingNorthingFieldComponent
212
+ const translatedLabel = getTranslatedLabel(def, translator)
213
+ const { eastingMin, eastingMax, northingMin, northingMax } =
214
+ EastingNorthingField.getMinMax(def.schema)
215
+ const { eastingValidationMessages, northingValidationMessages } =
216
+ EastingNorthingField.buildErrorMessages(
217
+ translatedLabel,
218
+ eastingMin,
219
+ eastingMax,
220
+ northingMin,
221
+ northingMax,
222
+ translator.language
223
+ )
224
+ return {
225
+ [`${this.name}__easting`]: eastingValidationMessages,
226
+ [`${this.name}__northing`]: northingValidationMessages
227
+ }
228
+ }
229
+
247
230
  /**
248
231
  * For error preview page that shows all possible errors on a component
249
232
  */
@@ -309,4 +292,117 @@ export class EastingNorthingField extends FormComponent {
309
292
  NumberField.isNumber(value.northing)
310
293
  )
311
294
  }
295
+
296
+ static buildErrorMessages(
297
+ label: string,
298
+ eastingMin: number,
299
+ eastingMax: number,
300
+ northingMin: number,
301
+ northingMax: number,
302
+ language: string
303
+ ) {
304
+ const fieldLabel = lowerFirst(label)
305
+
306
+ const eastingDigitsMessage = tPlugin(
307
+ 'components.eastingNorthingField.eastingDigits',
308
+ language,
309
+ { fieldLabel }
310
+ )
311
+ const northingDigitsMessage = tPlugin(
312
+ 'components.eastingNorthingField.northingDigits',
313
+ language,
314
+ { fieldLabel }
315
+ )
316
+
317
+ const eastingValidationMessages: LanguageMessages = {
318
+ 'any.required': tPlugin(
319
+ 'components.eastingNorthingField.eastingRequired',
320
+ language
321
+ ),
322
+ 'number.base': tPlugin(
323
+ 'components.eastingNorthingField.eastingRequired',
324
+ language
325
+ ),
326
+ 'number.min': tPlugin(
327
+ 'components.eastingNorthingField.eastingRange',
328
+ language,
329
+ {
330
+ fieldLabel,
331
+ min: eastingMin,
332
+ max: eastingMax
333
+ }
334
+ ),
335
+ 'number.max': tPlugin(
336
+ 'components.eastingNorthingField.eastingRange',
337
+ language,
338
+ {
339
+ fieldLabel,
340
+ min: eastingMin,
341
+ max: eastingMax
342
+ }
343
+ ),
344
+ 'number.precision': eastingDigitsMessage,
345
+ 'number.integer': eastingDigitsMessage,
346
+ 'number.unsafe': eastingDigitsMessage
347
+ }
348
+
349
+ const northingValidationMessages: LanguageMessages = {
350
+ 'any.required': tPlugin(
351
+ 'components.eastingNorthingField.northingRequired',
352
+ language
353
+ ),
354
+ 'number.base': tPlugin(
355
+ 'components.eastingNorthingField.northingRequired',
356
+ language
357
+ ),
358
+ 'number.min': tPlugin(
359
+ 'components.eastingNorthingField.northingRange',
360
+ language,
361
+ {
362
+ fieldLabel,
363
+ min: northingMin,
364
+ max: northingMax
365
+ }
366
+ ),
367
+ 'number.max': tPlugin(
368
+ 'components.eastingNorthingField.northingRange',
369
+ language,
370
+ {
371
+ fieldLabel,
372
+ min: northingMin,
373
+ max: northingMax
374
+ }
375
+ ),
376
+ 'number.precision': northingDigitsMessage,
377
+ 'number.integer': northingDigitsMessage,
378
+ 'number.unsafe': northingDigitsMessage
379
+ }
380
+ return {
381
+ eastingValidationMessages,
382
+ northingValidationMessages
383
+ }
384
+ }
385
+
386
+ // Read schema values from def.schema with fallback defaults
387
+ static getMinMax(
388
+ schema:
389
+ | {
390
+ easting?: {
391
+ min?: number
392
+ max?: number
393
+ }
394
+ northing?: {
395
+ min?: number
396
+ max?: number
397
+ }
398
+ }
399
+ | undefined
400
+ ) {
401
+ return {
402
+ eastingMin: schema?.easting?.min ?? DEFAULT_EASTING_MIN,
403
+ eastingMax: schema?.easting?.max ?? DEFAULT_EASTING_MAX,
404
+ northingMin: schema?.northing?.min ?? DEFAULT_NORTHING_MIN,
405
+ northingMax: schema?.northing?.max ?? DEFAULT_NORTHING_MAX
406
+ }
407
+ }
312
408
  }
@@ -40,7 +40,8 @@ export class EmailAddressField extends FormComponent {
40
40
  formSchema = formSchema.messages({
41
41
  'any.required': message,
42
42
  'string.empty': message,
43
- 'string.email': message
43
+ 'string.email': message,
44
+ 'string.unicode': message
44
45
  })
45
46
  } else if (options.customValidationMessages) {
46
47
  formSchema = formSchema.messages(options.customValidationMessages)
@@ -5,11 +5,13 @@ import {
5
5
  import Boom from '@hapi/boom'
6
6
  import joi, { type ArraySchema } from 'joi'
7
7
 
8
+ import { EN_GB } from '../../../constants.js'
8
9
  import {
9
10
  FormComponent,
10
11
  isUploadState
11
12
  } from './FormComponent.js'
12
13
  import { type RenderContext } from './types.js'
14
+ import { t as tPlugin } from '../i18n/index.js'
13
15
  import { type Translator } from '../i18n/types.js'
14
16
  import { InvalidComponentStateError } from '../pageControllers/errors.js'
15
17
  import { messageTemplate } from '../pageControllers/validationOptions.js'
@@ -50,7 +52,9 @@ export const tempFileSchema = fileSchema.append({
50
52
  .string()
51
53
  .valid(FileStatus.complete, FileStatus.rejected, FileStatus.pending)
52
54
  .required(),
53
- errorMessage: joi.string().optional()
55
+ errorMessage: joi.string().optional(),
56
+ errorCode: joi.string().optional(),
57
+ errorParams: joi.any().optional()
54
58
  })
55
59
 
56
60
  export const formFileSchema = fileSchema.append({
@@ -107,8 +111,9 @@ export const formItemSchema = itemSchema.append({
107
111
  export class FileUploadField extends FormComponent {
108
112
  declare options: FileUploadFieldComponent['options']
109
113
  declare schema: FileUploadFieldComponent['schema']
110
- declare formSchema: ArraySchema<FileState>
111
- declare stateSchema: ArraySchema<FileState>
114
+ declare formSchema: ArraySchema<FileState[]>
115
+ declare stateSchema: ArraySchema<FileState[]>
116
+ declare limits: { min?: number; max?: number; length?: number }
112
117
 
113
118
  constructor(
114
119
  def: FileUploadFieldComponent,
@@ -128,20 +133,32 @@ export class FileUploadField extends FormComponent {
128
133
  formSchema = formSchema.optional()
129
134
  }
130
135
 
136
+ const limits: { min?: number; max?: number; length?: number } = {}
137
+
131
138
  if (typeof schema.length !== 'number') {
132
139
  if (typeof schema.max === 'number') {
133
140
  formSchema = formSchema.max(schema.max)
141
+ limits.max = schema.max
134
142
  }
135
143
 
136
144
  if (typeof schema.min === 'number') {
137
145
  formSchema = formSchema.min(schema.min)
146
+ limits.min = schema.min
138
147
  } else if (options.required !== false) {
139
148
  formSchema = formSchema.min(1)
149
+ limits.min = 1
140
150
  }
141
151
  } else {
142
152
  formSchema = formSchema.length(schema.length)
153
+ limits.length = schema.length
143
154
  }
144
155
 
156
+ this.limits = limits
157
+
158
+ formSchema = formSchema.messages(
159
+ FileUploadField.buildErrorMessages(EN_GB, limits)
160
+ )
161
+
145
162
  this.formSchema = formSchema.items(formItemSchema)
146
163
  this.stateSchema = formSchema
147
164
  .items(formItemSchema)
@@ -169,7 +186,7 @@ export class FileUploadField extends FormComponent {
169
186
  return ''
170
187
  }
171
188
 
172
- return translator.t('components.fileUploadField.filesCount', {
189
+ return translator.t('pages.summary.fileUpload', {
173
190
  count: files.length
174
191
  })
175
192
  }
@@ -244,7 +261,7 @@ export class FileUploadField extends FormComponent {
244
261
 
245
262
  items.push({
246
263
  href,
247
- text: 'Remove',
264
+ text: t('pages.fileUpload.remove'),
248
265
  classes: 'govuk-link--no-visited-state',
249
266
  attributes: { id: `${id}__${index}` },
250
267
  visuallyHiddenText: file.filename
@@ -300,6 +317,13 @@ export class FileUploadField extends FormComponent {
300
317
  return isUploadState(value)
301
318
  }
302
319
 
320
+ getValidationMessagesOverride(translator: Translator) {
321
+ const { language } = translator
322
+ return {
323
+ [this.name]: FileUploadField.buildErrorMessages(language, this.limits)
324
+ }
325
+ }
326
+
303
327
  /**
304
328
  * For error preview page that shows all possible errors on a component
305
329
  */
@@ -403,4 +427,21 @@ export class FileUploadField extends FormComponent {
403
427
  ]
404
428
  }
405
429
  }
430
+
431
+ static buildErrorMessages(
432
+ language: string,
433
+ limits: { min?: number; max?: number; length?: number } = {}
434
+ ) {
435
+ return {
436
+ 'array.min': tPlugin('validation.filesMin', language, {
437
+ count: limits.min ?? 1
438
+ }),
439
+ 'array.max': tPlugin('validation.filesMax', language, {
440
+ count: limits.max ?? 1
441
+ }),
442
+ 'array.length': tPlugin('validation.filesLength', language, {
443
+ count: limits.length ?? 1
444
+ })
445
+ }
446
+ }
406
447
  }