@defra/forms-engine-plugin 5.0.0-alpha.2 → 5.0.0-alpha.21

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 (346) hide show
  1. package/.public/javascripts/application.min.js +1 -1
  2. package/.public/javascripts/application.min.js.LICENSE.txt +7 -0
  3. package/.public/javascripts/application.min.js.map +1 -1
  4. package/.public/javascripts/shared.min.js +1 -1
  5. package/.public/javascripts/shared.min.js.LICENSE.txt +7 -0
  6. package/.public/javascripts/shared.min.js.map +1 -1
  7. package/.public/stylesheets/application.min.css.map +1 -1
  8. package/.server/client/javascripts/file-upload.js +6 -3
  9. package/.server/client/javascripts/file-upload.js.map +1 -1
  10. package/.server/client/javascripts/geospatial-map.d.ts +153 -5
  11. package/.server/client/javascripts/geospatial-map.js +157 -77
  12. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  13. package/.server/client/javascripts/govuk.js +2 -1
  14. package/.server/client/javascripts/govuk.js.map +1 -1
  15. package/.server/client/javascripts/location-map.d.ts +44 -0
  16. package/.server/client/javascripts/location-map.js +54 -5
  17. package/.server/client/javascripts/location-map.js.map +1 -1
  18. package/.server/client/javascripts/map-constants.d.ts +3 -0
  19. package/.server/client/javascripts/map-constants.js +4 -0
  20. package/.server/client/javascripts/map-constants.js.map +1 -0
  21. package/.server/client/javascripts/map.d.ts +10 -0
  22. package/.server/client/javascripts/map.js +42 -0
  23. package/.server/client/javascripts/map.js.map +1 -1
  24. package/.server/client/javascripts/maps.d.ts +5 -0
  25. package/.server/client/javascripts/maps.js +6 -0
  26. package/.server/client/javascripts/maps.js.map +1 -0
  27. package/.server/client/javascripts/shared.d.ts +1 -4
  28. package/.server/client/javascripts/shared.js +1 -4
  29. package/.server/client/javascripts/shared.js.map +1 -1
  30. package/.server/client/javascripts/sssi-dataset.d.ts +18 -20
  31. package/.server/client/javascripts/sssi-dataset.js +37 -39
  32. package/.server/client/javascripts/sssi-dataset.js.map +1 -1
  33. package/.server/client/stylesheets/maps.scss +4 -0
  34. package/.server/client/stylesheets/shared.scss +1 -5
  35. package/.server/server/constants.d.ts +2 -0
  36. package/.server/server/constants.js +2 -0
  37. package/.server/server/constants.js.map +1 -1
  38. package/.server/server/plugins/engine/__stubs__/definitions.d.ts +29 -0
  39. package/.server/server/plugins/engine/__stubs__/definitions.js +125 -0
  40. package/.server/server/plugins/engine/__stubs__/definitions.js.map +1 -0
  41. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +9 -3
  42. package/.server/server/plugins/engine/components/AutocompleteField.js +12 -0
  43. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  44. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +21 -0
  45. package/.server/server/plugins/engine/components/CheckboxesField.js +30 -5
  46. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  47. package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
  48. package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
  49. package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
  50. package/.server/server/plugins/engine/components/ComponentCollection.js +11 -6
  51. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  52. package/.server/server/plugins/engine/components/DatePartsField.d.ts +6 -3
  53. package/.server/server/plugins/engine/components/DatePartsField.js +12 -7
  54. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  55. package/.server/server/plugins/engine/components/DeclarationField.d.ts +5 -2
  56. package/.server/server/plugins/engine/components/DeclarationField.js +6 -4
  57. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  58. package/.server/server/plugins/engine/components/Details.d.ts +1 -0
  59. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +33 -2
  60. package/.server/server/plugins/engine/components/EastingNorthingField.js +110 -54
  61. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  62. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +4 -1
  63. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -1
  64. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  65. package/.server/server/plugins/engine/components/FileUploadField.d.ts +21 -0
  66. package/.server/server/plugins/engine/components/FileUploadField.js +35 -3
  67. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  68. package/.server/server/plugins/engine/components/FormComponent.d.ts +5 -1
  69. package/.server/server/plugins/engine/components/FormComponent.js +5 -2
  70. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  71. package/.server/server/plugins/engine/components/GeospatialField.d.ts +23 -0
  72. package/.server/server/plugins/engine/components/GeospatialField.js +33 -9
  73. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  74. package/.server/server/plugins/engine/components/Html.d.ts +1 -0
  75. package/.server/server/plugins/engine/components/InsetText.d.ts +1 -0
  76. package/.server/server/plugins/engine/components/LatLongField.d.ts +32 -2
  77. package/.server/server/plugins/engine/components/LatLongField.js +85 -48
  78. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  79. package/.server/server/plugins/engine/components/List.d.ts +1 -0
  80. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +1 -0
  81. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +8 -2
  82. package/.server/server/plugins/engine/components/LocationFieldBase.js +25 -6
  83. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  84. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +12 -3
  85. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +21 -13
  86. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  87. package/.server/server/plugins/engine/components/Markdown.d.ts +1 -0
  88. package/.server/server/plugins/engine/components/Markdown.js +1 -1
  89. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  90. package/.server/server/plugins/engine/components/MonthYearField.d.ts +5 -2
  91. package/.server/server/plugins/engine/components/MonthYearField.js +13 -9
  92. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  93. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +1 -0
  94. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  95. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +4 -3
  96. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  97. package/.server/server/plugins/engine/components/NotificationBanner.d.ts +1 -0
  98. package/.server/server/plugins/engine/components/NumberField.d.ts +5 -0
  99. package/.server/server/plugins/engine/components/NumberField.js +16 -0
  100. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  101. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +103 -1
  102. package/.server/server/plugins/engine/components/OsGridRefField.js +13 -3
  103. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  104. package/.server/server/plugins/engine/components/PaymentField.d.ts +3 -0
  105. package/.server/server/plugins/engine/components/PaymentField.js +17 -6
  106. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  107. package/.server/server/plugins/engine/components/SelectField.d.ts +1 -0
  108. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +1 -0
  109. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +1 -0
  110. package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -0
  111. package/.server/server/plugins/engine/components/UkAddressField.js +23 -8
  112. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  113. package/.server/server/plugins/engine/components/YesNoField.d.ts +5 -2
  114. package/.server/server/plugins/engine/components/YesNoField.js +17 -8
  115. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  116. package/.server/server/plugins/engine/components/helpers/components.js +3 -3
  117. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  118. package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +8 -1
  119. package/.server/server/plugins/engine/components/helpers/geospatial.js +56 -15
  120. package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -1
  121. package/.server/server/plugins/engine/components/helpers/index.d.ts +7 -0
  122. package/.server/server/plugins/engine/components/helpers/index.js +13 -1
  123. package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
  124. package/.server/server/plugins/engine/components/types.d.ts +1 -0
  125. package/.server/server/plugins/engine/components/types.js.map +1 -1
  126. package/.server/server/plugins/engine/errors.d.ts +49 -0
  127. package/.server/server/plugins/engine/errors.js +75 -0
  128. package/.server/server/plugins/engine/errors.js.map +1 -0
  129. package/.server/server/plugins/engine/form-availability.d.ts +3 -2
  130. package/.server/server/plugins/engine/form-availability.js +3 -2
  131. package/.server/server/plugins/engine/form-availability.js.map +1 -1
  132. package/.server/server/plugins/engine/form-context.js +2 -2
  133. package/.server/server/plugins/engine/form-context.js.map +1 -1
  134. package/.server/server/plugins/engine/helpers.d.ts +22 -2
  135. package/.server/server/plugins/engine/helpers.js +44 -5
  136. package/.server/server/plugins/engine/helpers.js.map +1 -1
  137. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +4 -1
  138. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +31 -7
  139. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -1
  140. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +4 -4
  141. package/.server/server/plugins/engine/i18n/createFormTranslator.js +33 -4
  142. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -1
  143. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +1 -1
  144. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +9 -0
  145. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -1
  146. package/.server/server/plugins/engine/i18n/form.d.ts +13 -0
  147. package/.server/server/plugins/engine/i18n/form.js +35 -0
  148. package/.server/server/plugins/engine/i18n/form.js.map +1 -0
  149. package/.server/server/plugins/engine/i18n/languages.d.ts +10 -0
  150. package/.server/server/plugins/engine/i18n/languages.js +19 -0
  151. package/.server/server/plugins/engine/i18n/languages.js.map +1 -0
  152. package/.server/server/plugins/engine/i18n/translations/cy.json +192 -9
  153. package/.server/server/plugins/engine/i18n/translations/en-GB.json +125 -7
  154. package/.server/server/plugins/engine/i18n/types.d.ts +3 -0
  155. package/.server/server/plugins/engine/i18n/types.js.map +1 -1
  156. package/.server/server/plugins/engine/index.d.ts +4 -0
  157. package/.server/server/plugins/engine/index.js +4 -0
  158. package/.server/server/plugins/engine/index.js.map +1 -1
  159. package/.server/server/plugins/engine/models/FormModel.d.ts +0 -4
  160. package/.server/server/plugins/engine/models/FormModel.js +35 -23
  161. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  162. package/.server/server/plugins/engine/models/SummaryViewModel.js +9 -4
  163. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  164. package/.server/server/plugins/engine/models/types.d.ts +28 -1
  165. package/.server/server/plugins/engine/models/types.js.map +1 -1
  166. package/.server/server/plugins/engine/models/unavailable-view-model.d.ts +11 -2
  167. package/.server/server/plugins/engine/models/unavailable-view-model.js +23 -4
  168. package/.server/server/plugins/engine/models/unavailable-view-model.js.map +1 -1
  169. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +14 -6
  170. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  171. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  172. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  173. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +2 -0
  174. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +2 -0
  175. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  176. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +7 -1
  177. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +56 -10
  178. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  179. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -1
  180. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +7 -3
  181. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  182. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
  183. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  184. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +10 -4
  185. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  186. package/.server/server/plugins/engine/pageControllers/helpers/pages.js +2 -1
  187. package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -1
  188. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +35 -2
  189. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +100 -3
  190. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  191. package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +1 -1
  192. package/.server/server/plugins/engine/pageControllers/validationOptions.js +24 -3
  193. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  194. package/.server/server/plugins/engine/types/enums.d.ts +3 -3
  195. package/.server/server/plugins/engine/types/enums.js +5 -4
  196. package/.server/server/plugins/engine/types/enums.js.map +1 -1
  197. package/.server/server/plugins/engine/types/schema.js +10 -3
  198. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  199. package/.server/server/plugins/engine/types.d.ts +18 -2
  200. package/.server/server/plugins/engine/types.js.map +1 -1
  201. package/.server/server/plugins/engine/unavailable-response.js +5 -2
  202. package/.server/server/plugins/engine/unavailable-response.js.map +1 -1
  203. package/.server/server/plugins/engine/views/components/_location-field-base.html +4 -2
  204. package/.server/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  205. package/.server/server/plugins/engine/views/components/geospatialfield.html +1 -0
  206. package/.server/server/plugins/engine/views/components/multilinetextfield.html +12 -1
  207. package/.server/server/plugins/engine/views/components/osgridreffield.html +4 -1
  208. package/.server/server/plugins/engine/views/components/paymentfield.html +1 -1
  209. package/.server/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  210. package/.server/server/plugins/engine/views/file-upload.html +1 -1
  211. package/.server/server/plugins/engine/views/partials/preview-banner.html +3 -1
  212. package/.server/server/plugins/engine/views/unavailable.html +14 -11
  213. package/.server/server/plugins/nunjucks/filters/applyUrlParam.d.ts +9 -0
  214. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  215. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js.map +1 -0
  216. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js +17 -0
  217. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js.map +1 -0
  218. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  219. package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
  220. package/.server/server/plugins/nunjucks/filters/index.js +1 -0
  221. package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
  222. package/.server/server/plugins/payment/helper.d.ts +11 -1
  223. package/.server/server/plugins/payment/helper.js +18 -2
  224. package/.server/server/plugins/payment/helper.js.map +1 -1
  225. package/.server/server/plugins/payment/helper.test.js +2 -1
  226. package/.server/server/plugins/payment/helper.test.js.map +1 -1
  227. package/.server/server/plugins/payment/service.d.ts +2 -1
  228. package/.server/server/plugins/payment/service.js +5 -2
  229. package/.server/server/plugins/payment/service.js.map +1 -1
  230. package/.server/server/plugins/payment/service.test.js +7 -3
  231. package/.server/server/plugins/payment/service.test.js.map +1 -1
  232. package/.server/server/plugins/payment/types.d.ts +4 -0
  233. package/.server/server/plugins/payment/types.js +1 -0
  234. package/.server/server/plugins/payment/types.js.map +1 -1
  235. package/.server/server/plugins/postcode-lookup/models/index.d.ts +249 -3
  236. package/.server/server/plugins/postcode-lookup/models/index.js +87 -33
  237. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  238. package/.server/server/plugins/postcode-lookup/routes/index.d.ts +15 -1
  239. package/.server/server/plugins/postcode-lookup/routes/index.js +47 -15
  240. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  241. package/.server/server/plugins/postcode-lookup/routes/index.test.js +84 -0
  242. package/.server/server/plugins/postcode-lookup/routes/index.test.js.map +1 -0
  243. package/.server/server/plugins/postcode-lookup/types.d.ts +12 -0
  244. package/.server/server/plugins/postcode-lookup/types.js +6 -1
  245. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  246. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  247. package/.server/server/utils/type-utils.d.ts +1 -2
  248. package/.server/server/utils/type-utils.js +0 -3
  249. package/.server/server/utils/type-utils.js.map +1 -1
  250. package/.server/server/utils/utils.d.ts +6 -0
  251. package/.server/server/utils/utils.js +18 -1
  252. package/.server/server/utils/utils.js.map +1 -1
  253. package/.server/server/utils/utils.test.js +21 -1
  254. package/.server/server/utils/utils.test.js.map +1 -1
  255. package/package.json +20 -5
  256. package/src/client/javascripts/file-upload.js +11 -3
  257. package/src/client/javascripts/geospatial-map.js +176 -81
  258. package/src/client/javascripts/govuk.js +2 -0
  259. package/src/client/javascripts/location-map.js +60 -4
  260. package/src/client/javascripts/map-constants.js +3 -0
  261. package/src/client/javascripts/map.js +47 -0
  262. package/src/client/javascripts/maps.js +5 -0
  263. package/src/client/javascripts/shared.js +1 -4
  264. package/src/client/javascripts/sssi-dataset.js +39 -41
  265. package/src/client/stylesheets/maps.scss +4 -0
  266. package/src/client/stylesheets/shared.scss +1 -5
  267. package/src/server/constants.js +2 -0
  268. package/src/server/plugins/engine/__stubs__/definitions.ts +155 -0
  269. package/src/server/plugins/engine/components/AutocompleteField.ts +13 -0
  270. package/src/server/plugins/engine/components/CheckboxesField.ts +38 -5
  271. package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
  272. package/src/server/plugins/engine/components/ComponentCollection.ts +16 -11
  273. package/src/server/plugins/engine/components/DatePartsField.ts +20 -9
  274. package/src/server/plugins/engine/components/DeclarationField.ts +7 -6
  275. package/src/server/plugins/engine/components/EastingNorthingField.ts +185 -89
  276. package/src/server/plugins/engine/components/EmailAddressField.ts +2 -1
  277. package/src/server/plugins/engine/components/FileUploadField.ts +44 -3
  278. package/src/server/plugins/engine/components/FormComponent.ts +6 -5
  279. package/src/server/plugins/engine/components/GeospatialField.ts +47 -9
  280. package/src/server/plugins/engine/components/LatLongField.ts +128 -58
  281. package/src/server/plugins/engine/components/LocationFieldBase.ts +30 -7
  282. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +28 -14
  283. package/src/server/plugins/engine/components/Markdown.ts +2 -3
  284. package/src/server/plugins/engine/components/MonthYearField.ts +20 -15
  285. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -3
  286. package/src/server/plugins/engine/components/NumberField.ts +21 -1
  287. package/src/server/plugins/engine/components/OsGridRefField.ts +22 -3
  288. package/src/server/plugins/engine/components/PaymentField.ts +15 -5
  289. package/src/server/plugins/engine/components/UkAddressField.ts +30 -7
  290. package/src/server/plugins/engine/components/YesNoField.ts +17 -9
  291. package/src/server/plugins/engine/components/helpers/components.ts +3 -3
  292. package/src/server/plugins/engine/components/helpers/geospatial.ts +84 -21
  293. package/src/server/plugins/engine/components/helpers/index.ts +19 -0
  294. package/src/server/plugins/engine/components/types.ts +1 -0
  295. package/src/server/plugins/engine/errors.ts +78 -0
  296. package/src/server/plugins/engine/form-availability.ts +8 -2
  297. package/src/server/plugins/engine/form-context.ts +4 -2
  298. package/src/server/plugins/engine/helpers.ts +52 -5
  299. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +16 -8
  300. package/src/server/plugins/engine/i18n/createFormTranslator.ts +62 -11
  301. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +7 -1
  302. package/src/server/plugins/engine/i18n/form.ts +54 -0
  303. package/src/server/plugins/engine/i18n/languages.ts +19 -0
  304. package/src/server/plugins/engine/i18n/translations/cy.json +192 -9
  305. package/src/server/plugins/engine/i18n/translations/en-GB.json +125 -7
  306. package/src/server/plugins/engine/i18n/types.ts +3 -0
  307. package/src/server/plugins/engine/index.ts +7 -0
  308. package/src/server/plugins/engine/models/FormModel.ts +46 -23
  309. package/src/server/plugins/engine/models/SummaryViewModel.ts +6 -5
  310. package/src/server/plugins/engine/models/types.ts +31 -0
  311. package/src/server/plugins/engine/models/unavailable-view-model.ts +26 -5
  312. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +18 -7
  313. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -1
  314. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +3 -0
  315. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +60 -9
  316. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +10 -5
  317. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
  318. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -4
  319. package/src/server/plugins/engine/pageControllers/helpers/pages.ts +2 -1
  320. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +143 -4
  321. package/src/server/plugins/engine/pageControllers/validationOptions.ts +29 -4
  322. package/src/server/plugins/engine/types/enums.ts +4 -3
  323. package/src/server/plugins/engine/types/schema.ts +17 -4
  324. package/src/server/plugins/engine/types.ts +19 -1
  325. package/src/server/plugins/engine/unavailable-response.ts +6 -2
  326. package/src/server/plugins/engine/views/components/_location-field-base.html +4 -2
  327. package/src/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  328. package/src/server/plugins/engine/views/components/geospatialfield.html +1 -0
  329. package/src/server/plugins/engine/views/components/multilinetextfield.html +12 -1
  330. package/src/server/plugins/engine/views/components/osgridreffield.html +4 -1
  331. package/src/server/plugins/engine/views/components/paymentfield.html +1 -1
  332. package/src/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  333. package/src/server/plugins/engine/views/file-upload.html +1 -1
  334. package/src/server/plugins/engine/views/partials/preview-banner.html +3 -1
  335. package/src/server/plugins/engine/views/unavailable.html +14 -11
  336. package/src/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  337. package/src/server/plugins/nunjucks/filters/index.js +1 -0
  338. package/src/server/plugins/payment/helper.js +22 -2
  339. package/src/server/plugins/payment/service.js +6 -2
  340. package/src/server/plugins/payment/types.js +1 -0
  341. package/src/server/plugins/postcode-lookup/models/index.js +75 -43
  342. package/src/server/plugins/postcode-lookup/routes/index.js +73 -16
  343. package/src/server/plugins/postcode-lookup/types.js +6 -1
  344. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  345. package/src/server/utils/type-utils.ts +1 -11
  346. package/src/server/utils/utils.js +19 -1
@@ -1 +1 @@
1
- {"version":3,"file":"QuestionPageController.js","names":["ComponentType","ControllerType","Engine","hasComponents","hasNext","hasRepeater","isPaymentPage","Boom","COMPONENT_STATE_ERROR","EXTERNAL_STATE_APPENDAGE","EXTERNAL_STATE_PAYLOAD","PAYMENT_EXPIRED_NOTIFICATION","ComponentCollection","PaymentField","checkFormStatus","getCacheService","getErrors","getSaveAndExitHelpers","normalisePath","proceed","PageController","prefillStateFromQueryParameters","getComponentsByType","formatCurrency","FormAction","FormStatus","actionSchema","crumbSchema","paramsSchema","merge","QuestionPageController","collection","errorSummaryTitle","allowSaveAndExit","constructor","model","pageDef","components","page","formSchema","keys","crumb","action","next","def","filter","path","linkPath","pages","some","pagePath","allowContinue","engine","V2","controller","Terminal","length","getItemId","request","itemId","getFormParams","params","getViewModel","context","translator","viewModel","payload","errors","t","tPage","tSection","showTitle","sectionTitle","pageTitle","title","section","hideTitle","formComponents","isFormComponent","fieldset","label","isPageHeading","labelOrLegend","legend","size","classes","isOptional","fields","at","options","required","text","comp","paymentField","find","f","resolvedAmount","resolveAmount","evaluationState","amount","hasIncompletePayment","paymentState","preAuth","status","backLink","getBackLink","shouldShowSaveAndExit","server","showSubmitButton","getRelevantPath","paths","startPath","getStartPath","relevantPath","getNextPath","summaryPath","getSummaryPath","statusPath","getStatusPath","defaultPath","undefined","pageIndex","indexOf","nextPage","slice","condition","conditionResult","fn","nextLink","link","conditions","getFormDataFromState","state","result","validate","abortEarly","stripUnknown","value","getStateFromValidForm","details","getState","query","cacheService","setState","mergeState","update","updated","filterConditionalComponents","filtered","component","content","type","Details","map","evaluatedComponent","Array","isArray","item","items","makeGetRouteHandler","h","viewName","getTranslator","redirect","url","pathname","getViewErrors","flashedError","yar","flash","flashedErrors","concat","paymentExpiredFlash","showPaymentExpiredNotification","hasMissingNotificationEmail","view","isForceAccess","formsService","services","getFormMetadata","includes","notificationEmail","slug","returnUrl","href","backPath","endsWith","getHref","makePostRouteHandler","startsWith","External","dispatchExternal","SaveAndExit","handleSaveAndExit","externalComponents","externalActionsWithArgs","split","externalActionArgs","arg","args","Object","fromEntries","componentName","componentDefMap","get","componentType","internal","selectedComponent","stashedPayload","clear","isPreview","isLive","Live","dispatcher","sourceUrl","search","actionArgs","nextPath","nextUrl","saveAndExit","getRouteOptions","ext","onPostHandler","method","_request","continue","postRouteOptions","parse","maxBytes","Number","MAX_SAFE_INTEGER","failAction"],"sources":["../../../../../src/server/plugins/engine/pageControllers/QuestionPageController.ts"],"sourcesContent":["import {\n ComponentType,\n ControllerType,\n Engine,\n hasComponents,\n hasNext,\n hasRepeater,\n isPaymentPage,\n type Link,\n type Page\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { type ValidationErrorItem } from 'joi'\n\nimport {\n COMPONENT_STATE_ERROR,\n EXTERNAL_STATE_APPENDAGE,\n EXTERNAL_STATE_PAYLOAD,\n PAYMENT_EXPIRED_NOTIFICATION\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type BackLink } from '~/src/server/plugins/engine/components/types.js'\nimport {\n checkFormStatus,\n getCacheService,\n getErrors,\n getSaveAndExitHelpers,\n normalisePath,\n proceed\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 { PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { prefillStateFromQueryParameters } from '~/src/server/plugins/engine/pageControllers/helpers/state.js'\nimport {\n type AnyFormRequest,\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormPayloadParams,\n type FormState,\n type FormStateValue,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { getComponentsByType } from '~/src/server/plugins/engine/validationHelpers.js'\nimport { formatCurrency } from '~/src/server/plugins/payment/helper.js'\nimport {\n FormAction,\n FormStatus,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n crumbSchema,\n paramsSchema\n} from '~/src/server/schemas/index.js'\nimport { merge } from '~/src/server/services/cacheService.js'\n\nexport class QuestionPageController extends PageController {\n collection: ComponentCollection\n errorSummaryTitle = 'There is a problem'\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponents(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n\n this.collection.formSchema = this.collection.formSchema.keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n }\n\n get next(): Link[] {\n const { def, pageDef } = this\n\n if (!hasNext(pageDef)) {\n return []\n }\n\n // Remove stale links\n return pageDef.next.filter(({ path }) => {\n const linkPath = normalisePath(path)\n\n return def.pages.some((page) => {\n const pagePath = normalisePath(page.path)\n return pagePath === linkPath\n })\n })\n }\n\n get allowContinue(): boolean {\n if (this.model.engine === Engine.V2) {\n return this.pageDef.controller !== ControllerType.Terminal\n }\n\n return this.next.length > 0\n }\n\n getItemId(request?: FormContextRequest) {\n const { itemId } = this.getFormParams(request)\n return itemId ?? request?.params.itemId\n }\n\n /**\n * Used for mapping form payloads and errors to govuk-frontend's template api, so a page can be rendered\n * @param request - the hapi request\n * @param context - the form context\n * @param translator - optional per-request translator pair\n */\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { collection, viewModel } = this\n const { payload, errors } = context\n\n const { t, tPage, tSection } = translator\n\n let { showTitle, sectionTitle } = viewModel\n\n let pageTitle = this.pageDef.title ? tPage(this.pageDef, 'title') : ''\n\n if (this.section) {\n sectionTitle =\n this.section.hideTitle !== true ? tSection(this.section, 'title') : ''\n }\n\n const components = collection.getViewModel({ payload, errors, translator })\n const formComponents = components.filter(\n ({ isFormComponent }) => isFormComponent\n )\n\n // Single form component? Hide title and customise label or legend instead\n if (formComponents.length === 1) {\n const { model } = formComponents[0]\n const { fieldset, label } = model\n\n // Set as page heading when not following other content\n const isPageHeading = formComponents[0] === components[0]\n\n // Check for legend or label\n const labelOrLegend = fieldset?.legend ?? label\n\n // Use legend or label as page heading\n if (labelOrLegend) {\n const size = isPageHeading ? 'l' : 'm'\n\n labelOrLegend.classes =\n labelOrLegend === label\n ? `govuk-label--${size}`\n : `govuk-fieldset__legend--${size}`\n\n if (isPageHeading) {\n labelOrLegend.isPageHeading = isPageHeading\n\n // Check for optional in label\n const isOptional =\n this.collection.fields.at(0)?.options.required === false\n\n if (!pageTitle) {\n pageTitle = labelOrLegend.text\n }\n labelOrLegend.text = isOptional\n ? `${pageTitle} ${t('common.optional')}`\n : pageTitle\n }\n\n // Fallback if still no pageTitle set\n if (!pageTitle) {\n pageTitle = labelOrLegend.text\n }\n }\n\n showTitle = !isPageHeading\n } else if (formComponents.length > 1) {\n // When there is more than one form component,\n // adjust the label/legends to give equal prominence\n for (const { model } of formComponents) {\n if (model.fieldset?.legend) {\n model.fieldset.legend.classes = 'govuk-fieldset__legend--m'\n }\n if (model.label) {\n model.label.classes = 'govuk-label--m'\n }\n }\n }\n\n // Override payment amount display with resolved conditional amount\n // getViewModel() only has the current page's payload, not full form state.\n // The full state is available via context.evaluationState.\n for (const comp of components) {\n if ('amount' in comp.model && 'paymentState' in comp.model) {\n const paymentField = this.collection.fields.find(\n (f): f is PaymentField => f instanceof PaymentField\n )\n if (paymentField) {\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n context.evaluationState\n )\n comp.model.amount = formatCurrency(resolvedAmount)\n }\n }\n }\n\n const hasIncompletePayment = components.some(({ model }) => {\n if ('paymentState' in model) {\n const paymentState = model.paymentState as\n | { preAuth?: { status?: string } }\n | undefined\n return !paymentState?.preAuth?.status\n }\n return false\n })\n\n return {\n ...viewModel,\n backLink: this.getBackLink(request, context, t),\n context,\n pageTitle,\n sectionTitle,\n showTitle,\n components,\n errors,\n allowSaveAndExit:\n this.shouldShowSaveAndExit(request.server) &&\n !isPaymentPage(this.pageDef),\n showSubmitButton: !hasIncompletePayment\n }\n }\n\n getRelevantPath(request: AnyFormRequest, context: FormContext) {\n const { paths } = context\n\n const startPath = this.getStartPath()\n const relevantPath = paths.at(-1) ?? startPath\n\n return !paths.length\n ? startPath // First possible path\n : relevantPath // Last possible path\n }\n\n /**\n * Apply conditions to evaluation state to determine next page path\n */\n getNextPath(context: FormContext) {\n const { model, next, path } = this\n const { evaluationState } = context\n\n const summaryPath = this.getSummaryPath()\n const statusPath = this.getStatusPath()\n\n // Walk from summary page (no next links) to status page\n let defaultPath = path === summaryPath ? statusPath : undefined\n\n if (model.engine === Engine.V2) {\n if (this.pageDef.controller !== ControllerType.Terminal) {\n const { pages } = this.model\n const pageIndex = pages.indexOf(this)\n\n // The \"next\" page is the first found after the current which is\n // either unconditional or has a condition that evaluates to \"true\"\n const nextPage = pages.slice(pageIndex + 1).find((page) => {\n const { condition } = page\n\n if (condition) {\n const conditionResult = condition.fn(evaluationState)\n\n if (!conditionResult) {\n return false\n }\n }\n\n // Skip payment pages in the normal page walk.\n // Users reach the payment page via \"Pay and submit\" on CYA,\n // not by navigating forward through the form.\n if (isPaymentPage(page.pageDef)) {\n return false\n }\n\n return true\n })\n\n return nextPage?.path ?? defaultPath\n } else {\n return defaultPath\n }\n }\n\n const nextLink = next.find((link) => {\n const { condition } = link\n\n if (condition) {\n return model.conditions[condition]?.fn(evaluationState) ?? false\n }\n\n defaultPath = link.path\n return false\n })\n\n return nextLink?.path ?? defaultPath\n }\n\n /**\n * Gets the form payload (from state) for this page only\n */\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ): FormPayload {\n const { collection } = this\n\n // Form params from request\n const params = this.getFormParams(request)\n\n // Form payload from state\n const payload = collection.getFormDataFromState(state)\n\n return {\n ...params,\n ...payload\n }\n }\n\n /**\n * Gets form params (from payload) for this page only\n */\n getFormParams(request?: FormContextRequest): FormPayloadParams {\n const { payload } = request ?? {}\n\n const result = paramsSchema.validate(payload, {\n abortEarly: false,\n stripUnknown: true\n })\n\n return result.value as FormPayloadParams\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ): FormState {\n return this.collection.getStateFromValidForm(payload)\n }\n\n getErrors(details?: ValidationErrorItem[]) {\n return getErrors(details)\n }\n\n async getState(request: AnyFormRequest) {\n const { query } = request\n\n // Skip get for preview URL direct access\n if ('force' in query) {\n return {}\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.getState(request)\n }\n\n async setState(request: AnyFormRequest, state: FormSubmissionState) {\n const { query } = request\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return state\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.setState(request, state)\n }\n\n async mergeState(\n request: AnyFormRequest,\n state: FormSubmissionState,\n update: object\n ) {\n const { query } = request\n\n // Merge state before set\n const updated = merge(state, update)\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return updated\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.setState(request, updated)\n }\n\n filterConditionalComponents(\n viewModel: FormPageViewModel,\n model: FormModel,\n evaluationState: Partial<Record<string, FormStateValue>>\n ) {\n // Filter our components based on their conditions using our evaluated state\n let filtered = viewModel.components.filter((component) => {\n if (\n (!!component.model.content ||\n component.type === ComponentType.Details) &&\n component.model.condition\n ) {\n const condition = model.conditions[component.model.condition]\n return condition?.fn(evaluationState)\n }\n return true\n })\n\n /**\n * For conditional reveal components (which we no longer support until GDS resolves the related accessibility issues {@link https://github.com/alphagov/govuk-frontend/issues/1991}\n */\n filtered = filtered.map((component) => {\n const evaluatedComponent = component\n const content = evaluatedComponent.model.content\n if (Array.isArray(content)) {\n evaluatedComponent.model.content = content.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n // apply condition to items for radios, checkboxes etc\n const items = evaluatedComponent.model.items\n\n if (Array.isArray(items)) {\n evaluatedComponent.model.items = items.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n\n return evaluatedComponent\n })\n\n return filtered\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, model, viewName } = this\n const { evaluationState } = context\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n // Copy any URL params into the form state (if not already done so)\n if (await prefillStateFromQueryParameters(request, this)) {\n // Forward to same page without query string\n return h.redirect(request.url.pathname)\n }\n\n const viewModel = this.getViewModel(request, context, translator)\n viewModel.errors = collection.getViewErrors(translator, viewModel.errors)\n\n const flashedError = request.yar.flash(COMPONENT_STATE_ERROR)\n const flashedErrors = !Array.isArray(flashedError) ? [flashedError] : []\n\n viewModel.errors = (viewModel.errors ?? []).concat(flashedErrors)\n\n const paymentExpiredFlash = request.yar.flash(\n PAYMENT_EXPIRED_NOTIFICATION\n )\n viewModel.showPaymentExpiredNotification =\n !Array.isArray(paymentExpiredFlash)\n\n /**\n * Content components can be hidden based on a condition. If the condition evaluates to true, it is safe to be kept, otherwise discard it\n */\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n return h.view(viewName, {\n ...viewModel,\n t\n })\n }\n }\n\n async hasMissingNotificationEmail(\n request: FormRequest,\n context: FormContext\n ) {\n const { path } = this\n const { params } = request\n const { isForceAccess } = context\n\n const startPath = this.getStartPath()\n const summaryPath = this.getSummaryPath()\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n // Warn the user if the form has no notification email set only on start page and summary page\n if ([startPath, summaryPath].includes(path) && !isForceAccess) {\n const { notificationEmail } = await getFormMetadata(params.slug)\n return !notificationEmail\n }\n\n return false\n }\n\n /**\n * Get the back link for a given progress.\n */\n protected getBackLink(\n request: FormContextRequest,\n context: FormContext,\n t: (key: string, opts?: Record<string, unknown>) => string\n ): BackLink | undefined {\n const { pageDef } = this\n const { path, query } = request\n const { returnUrl } = query\n const { paths } = context\n\n const itemId = this.getItemId(request)\n\n // Check answers back link\n if (returnUrl) {\n return {\n text:\n hasRepeater(pageDef) && itemId\n ? t('pages.question.backToAddAnother')\n : t('pages.question.backToCheckAnswers'),\n href: returnUrl\n }\n }\n\n // Item delete pages etc\n const backPath =\n itemId && !path.endsWith(itemId)\n ? paths.at(-1) // Back to main page\n : paths.at(-2) // Back to previous page\n\n // No back link\n if (!backPath) {\n return\n }\n\n // Default back link\n return {\n text: t('common.back'),\n href: this.getHref(backPath)\n }\n }\n\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, viewName, model } = this\n const { isForceAccess, state, evaluationState } = context\n const action = request.payload.action\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (action?.startsWith(FormAction.External)) {\n return await this.dispatchExternal(request, h, context)\n }\n\n /**\n * If there are any errors, render the page with the parsed errors\n * @todo Refactor to match POST REDIRECT GET pattern\n */\n if (context.errors || isForceAccess) {\n const viewModel = this.getViewModel(request, context, translator)\n viewModel.errors = collection.getViewErrors(\n translator,\n viewModel.errors\n )\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n return h.view(viewName, {\n ...viewModel,\n t\n })\n }\n\n // Save state\n await this.setState(request, state)\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n // Proceed to the next page\n return this.proceed(request, h, this.getNextPath(context))\n }\n }\n\n private async dispatchExternal(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n ) {\n const { externalComponents } = getComponentsByType()\n const action = request.payload.action ?? ''\n\n // Find the external action and arguments\n // `external-{componentName}--{argname1}:{argvalue1}--{argname2}:{argvalue2}`\n // E.g. external-abcdef--amount:10--step:manual\n const externalActionsWithArgs = action\n .slice(`${FormAction.External}-`.length)\n .split('--')\n\n const externalActionArgs = externalActionsWithArgs\n .slice(1)\n .map((arg) => arg.split(':'))\n\n const args = Object.fromEntries(externalActionArgs) as Record<\n string,\n string\n >\n\n const componentName = externalActionsWithArgs[0]\n const component = this.model.componentDefMap.get(componentName)\n const componentType = component?.type\n\n if (!componentType) {\n throw Boom.internal(\n `External component of type ${componentType} not found`\n )\n }\n\n const selectedComponent = externalComponents.get(componentType)\n\n if (!selectedComponent) {\n throw Boom.internal(`External component ${componentName} not found`)\n }\n\n // Stash payload without crumb and action\n const stashedPayload = {\n ...context.payload,\n crumb: undefined,\n action: undefined\n }\n request.yar.flash(EXTERNAL_STATE_PAYLOAD, stashedPayload, true)\n\n // Clear any previous state appendage\n request.yar.clear(EXTERNAL_STATE_APPENDAGE)\n\n // Determine if this is a live form (not preview/draft)\n const { state, isPreview } = checkFormStatus(request.params)\n const isLive = state === FormStatus.Live\n\n return await selectedComponent.dispatcher(request, h, {\n component,\n controller: this,\n sourceUrl: `${request.url.pathname}${request.url.search}`,\n actionArgs: args,\n isLive,\n isPreview\n })\n }\n\n proceed(\n request: FormContextRequest,\n h: FormResponseToolkit,\n nextPath?: string\n ) {\n const nextUrl = nextPath\n ? this.getHref(nextPath) // Redirect to next page\n : this.href // Redirect to current page (refresh)\n\n return proceed(request, h, nextUrl)\n }\n\n /**\n * Handle save-and-exit action\n */\n handleSaveAndExit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const saveAndExit = getSaveAndExitHelpers(request.server)\n\n if (!saveAndExit) {\n throw Boom.internal('Server misconfigured for save and exit')\n }\n\n return saveAndExit(request, h, context)\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get getRouteOptions(): RouteOptions<FormRequestRefs> {\n return {\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n payload: {\n parse: true,\n maxBytes: Number.MAX_SAFE_INTEGER,\n failAction: 'ignore'\n },\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"QuestionPageController.js","names":["ComponentType","ControllerType","Engine","hasComponents","hasNext","hasRepeater","isPaymentPage","Boom","COMPONENT_STATE_ERROR","EXTERNAL_STATE_APPENDAGE","EXTERNAL_STATE_PAYLOAD","PAYMENT_EXPIRED_NOTIFICATION","ComponentCollection","PaymentField","checkFormStatus","getCacheService","getErrors","getSaveAndExitHelpers","normalisePath","proceed","PageController","prefillStateFromQueryParameters","getComponentsByType","formatCurrency","FormAction","FormStatus","actionSchema","crumbSchema","paramsSchema","merge","QuestionPageController","collection","errorSummaryTitle","allowSaveAndExit","constructor","model","pageDef","components","page","formSchema","keys","crumb","action","next","def","filter","path","linkPath","pages","some","pagePath","allowContinue","engine","V2","controller","Terminal","length","getItemId","request","itemId","getFormParams","params","getViewModel","context","translator","viewModel","payload","errors","t","tPage","tSection","showTitle","sectionTitle","pageTitle","title","section","hideTitle","formComponents","isFormComponent","fieldset","label","isPageHeading","labelOrLegend","legend","size","classes","isOptional","fields","at","options","required","text","optionalWord","optionalAlreadyAppended","endsWith","comp","paymentField","find","f","resolvedAmount","resolveAmount","evaluationState","amount","hasIncompletePayment","paymentState","preAuth","status","backLink","getBackLink","shouldShowSaveAndExit","server","showSubmitButton","getRelevantPath","paths","startPath","getStartPath","relevantPath","getNextPath","summaryPath","getSummaryPath","statusPath","getStatusPath","defaultPath","undefined","pageIndex","indexOf","nextPage","slice","condition","conditionResult","fn","nextLink","link","conditions","getFormDataFromState","state","result","validate","abortEarly","stripUnknown","value","getStateFromValidForm","details","language","getState","query","cacheService","setState","mergeState","update","updated","filterConditionalComponents","filtered","component","content","type","Details","map","evaluatedComponent","Array","isArray","item","items","makeGetRouteHandler","h","viewName","getTranslator","redirect","url","pathname","getViewErrors","flashedError","yar","flash","flashedErrors","concat","paymentExpiredFlash","showPaymentExpiredNotification","hasMissingNotificationEmail","view","isForceAccess","formsService","services","getFormMetadata","includes","notificationEmail","slug","returnUrl","href","backPath","getHref","makePostRouteHandler","startsWith","External","dispatchExternal","SaveAndExit","handleSaveAndExit","externalComponents","externalActionsWithArgs","split","externalActionArgs","arg","args","Object","fromEntries","componentName","componentDefMap","get","componentType","internal","selectedComponent","stashedPayload","clear","isPreview","isLive","Live","dispatcher","sourceUrl","search","actionArgs","nextPath","nextUrl","saveAndExit","getRouteOptions","ext","onPostHandler","method","_request","continue","postRouteOptions","parse","maxBytes","Number","MAX_SAFE_INTEGER","failAction"],"sources":["../../../../../src/server/plugins/engine/pageControllers/QuestionPageController.ts"],"sourcesContent":["import {\n ComponentType,\n ControllerType,\n Engine,\n hasComponents,\n hasNext,\n hasRepeater,\n isPaymentPage,\n type Link,\n type Page\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { type ValidationErrorItem } from 'joi'\n\nimport {\n COMPONENT_STATE_ERROR,\n EXTERNAL_STATE_APPENDAGE,\n EXTERNAL_STATE_PAYLOAD,\n PAYMENT_EXPIRED_NOTIFICATION\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport { type BackLink } from '~/src/server/plugins/engine/components/types.js'\nimport {\n checkFormStatus,\n getCacheService,\n getErrors,\n getSaveAndExitHelpers,\n normalisePath,\n proceed\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 { PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { prefillStateFromQueryParameters } from '~/src/server/plugins/engine/pageControllers/helpers/state.js'\nimport {\n type AnyFormRequest,\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormPayloadParams,\n type FormState,\n type FormStateValue,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { getComponentsByType } from '~/src/server/plugins/engine/validationHelpers.js'\nimport { formatCurrency } from '~/src/server/plugins/payment/helper.js'\nimport {\n FormAction,\n FormStatus,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n crumbSchema,\n paramsSchema\n} from '~/src/server/schemas/index.js'\nimport { merge } from '~/src/server/services/cacheService.js'\n\nexport class QuestionPageController extends PageController {\n collection: ComponentCollection\n errorSummaryTitle = 'There is a problem'\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponents(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n\n this.collection.formSchema = this.collection.formSchema.keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n }\n\n get next(): Link[] {\n const { def, pageDef } = this\n\n if (!hasNext(pageDef)) {\n return []\n }\n\n // Remove stale links\n return pageDef.next.filter(({ path }) => {\n const linkPath = normalisePath(path)\n\n return def.pages.some((page) => {\n const pagePath = normalisePath(page.path)\n return pagePath === linkPath\n })\n })\n }\n\n get allowContinue(): boolean {\n if (this.model.engine === Engine.V2) {\n return this.pageDef.controller !== ControllerType.Terminal\n }\n\n return this.next.length > 0\n }\n\n getItemId(request?: FormContextRequest) {\n const { itemId } = this.getFormParams(request)\n return itemId ?? request?.params.itemId\n }\n\n /**\n * Used for mapping form payloads and errors to govuk-frontend's template api, so a page can be rendered\n * @param request - the hapi request\n * @param context - the form context\n * @param translator - optional per-request translator pair\n */\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { collection, viewModel } = this\n const { payload, errors } = context\n\n const { t, tPage, tSection } = translator\n\n let { showTitle, sectionTitle } = viewModel\n\n let pageTitle = this.pageDef.title ? tPage(this.pageDef, 'title') : ''\n\n if (this.section) {\n sectionTitle =\n this.section.hideTitle !== true ? tSection(this.section, 'title') : ''\n }\n\n const components = collection.getViewModel({ payload, errors, translator })\n const formComponents = components.filter(\n ({ isFormComponent }) => isFormComponent\n )\n\n // Single form component? Hide title and customise label or legend instead\n if (formComponents.length === 1) {\n const { model } = formComponents[0]\n const { fieldset, label } = model\n\n // Set as page heading when not following other content\n const isPageHeading = formComponents[0] === components[0]\n\n // Check for legend or label\n const labelOrLegend = fieldset?.legend ?? label\n\n // Use legend or label as page heading\n if (labelOrLegend) {\n const size = isPageHeading ? 'l' : 'm'\n\n labelOrLegend.classes =\n labelOrLegend === label\n ? `govuk-label--${size}`\n : `govuk-fieldset__legend--${size}`\n\n if (isPageHeading) {\n labelOrLegend.isPageHeading = isPageHeading\n\n // Check for optional in label\n const isOptional =\n this.collection.fields.at(0)?.options.required === false\n\n if (!pageTitle) {\n pageTitle = labelOrLegend.text\n }\n\n // The question text may have already appended 'optional' in the relevant language\n const optionalWord = t('common.optional')\n const optionalAlreadyAppended = pageTitle.endsWith(` ${optionalWord}`)\n labelOrLegend.text =\n isOptional && !optionalAlreadyAppended\n ? `${pageTitle} ${optionalWord}`\n : pageTitle\n }\n\n // Fallback if still no pageTitle set\n if (!pageTitle) {\n pageTitle = labelOrLegend.text\n }\n }\n\n showTitle = !isPageHeading\n } else if (formComponents.length > 1) {\n // When there is more than one form component,\n // adjust the label/legends to give equal prominence\n for (const { model } of formComponents) {\n if (model.fieldset?.legend) {\n model.fieldset.legend.classes = 'govuk-fieldset__legend--m'\n }\n if (model.label) {\n model.label.classes = 'govuk-label--m'\n }\n }\n }\n\n // Override payment amount display with resolved conditional amount\n // getViewModel() only has the current page's payload, not full form state.\n // The full state is available via context.evaluationState.\n for (const comp of components) {\n if ('amount' in comp.model && 'paymentState' in comp.model) {\n const paymentField = this.collection.fields.find(\n (f): f is PaymentField => f instanceof PaymentField\n )\n if (paymentField) {\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n context.evaluationState\n )\n comp.model.amount = formatCurrency(resolvedAmount)\n }\n }\n }\n\n const hasIncompletePayment = components.some(({ model }) => {\n if ('paymentState' in model) {\n const paymentState = model.paymentState as\n | { preAuth?: { status?: string } }\n | undefined\n return !paymentState?.preAuth?.status\n }\n return false\n })\n\n return {\n ...viewModel,\n backLink: this.getBackLink(request, context, t),\n context,\n pageTitle,\n sectionTitle,\n showTitle,\n components,\n errors,\n allowSaveAndExit:\n this.shouldShowSaveAndExit(request.server) &&\n !isPaymentPage(this.pageDef),\n showSubmitButton: !hasIncompletePayment\n }\n }\n\n getRelevantPath(request: AnyFormRequest, context: FormContext) {\n const { paths } = context\n\n const startPath = this.getStartPath()\n const relevantPath = paths.at(-1) ?? startPath\n\n return !paths.length\n ? startPath // First possible path\n : relevantPath // Last possible path\n }\n\n /**\n * Apply conditions to evaluation state to determine next page path\n */\n getNextPath(context: FormContext) {\n const { model, next, path } = this\n const { evaluationState } = context\n\n const summaryPath = this.getSummaryPath()\n const statusPath = this.getStatusPath()\n\n // Walk from summary page (no next links) to status page\n let defaultPath = path === summaryPath ? statusPath : undefined\n\n if (model.engine === Engine.V2) {\n if (this.pageDef.controller !== ControllerType.Terminal) {\n const { pages } = this.model\n const pageIndex = pages.indexOf(this)\n\n // The \"next\" page is the first found after the current which is\n // either unconditional or has a condition that evaluates to \"true\"\n const nextPage = pages.slice(pageIndex + 1).find((page) => {\n const { condition } = page\n\n if (condition) {\n const conditionResult = condition.fn(evaluationState)\n\n if (!conditionResult) {\n return false\n }\n }\n\n // Skip payment pages in the normal page walk.\n // Users reach the payment page via \"Pay and submit\" on CYA,\n // not by navigating forward through the form.\n if (isPaymentPage(page.pageDef)) {\n return false\n }\n\n return true\n })\n\n return nextPage?.path ?? defaultPath\n } else {\n return defaultPath\n }\n }\n\n const nextLink = next.find((link) => {\n const { condition } = link\n\n if (condition) {\n return model.conditions[condition]?.fn(evaluationState) ?? false\n }\n\n defaultPath = link.path\n return false\n })\n\n return nextLink?.path ?? defaultPath\n }\n\n /**\n * Gets the form payload (from state) for this page only\n */\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ): FormPayload {\n const { collection } = this\n\n // Form params from request\n const params = this.getFormParams(request)\n\n // Form payload from state\n const payload = collection.getFormDataFromState(state)\n\n return {\n ...params,\n ...payload\n }\n }\n\n /**\n * Gets form params (from payload) for this page only\n */\n getFormParams(request?: FormContextRequest): FormPayloadParams {\n const { payload } = request ?? {}\n\n const result = paramsSchema.validate(payload, {\n abortEarly: false,\n stripUnknown: true\n })\n\n return result.value as FormPayloadParams\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ): FormState {\n return this.collection.getStateFromValidForm(payload)\n }\n\n getErrors(details?: ValidationErrorItem[], language?: string) {\n return getErrors(language, details)\n }\n\n async getState(request: AnyFormRequest) {\n const { query } = request\n\n // Skip get for preview URL direct access\n if ('force' in query) {\n return {}\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.getState(request)\n }\n\n async setState(request: AnyFormRequest, state: FormSubmissionState) {\n const { query } = request\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return state\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.setState(request, state)\n }\n\n async mergeState(\n request: AnyFormRequest,\n state: FormSubmissionState,\n update: object\n ) {\n const { query } = request\n\n // Merge state before set\n const updated = merge(state, update)\n\n // Skip set for preview URL direct access\n if ('force' in query) {\n return updated\n }\n\n const cacheService = getCacheService(request.server)\n\n return cacheService.setState(request, updated)\n }\n\n filterConditionalComponents(\n viewModel: FormPageViewModel,\n model: FormModel,\n evaluationState: Partial<Record<string, FormStateValue>>\n ) {\n // Filter our components based on their conditions using our evaluated state\n let filtered = viewModel.components.filter((component) => {\n if (\n (!!component.model.content ||\n component.type === ComponentType.Details) &&\n component.model.condition\n ) {\n const condition = model.conditions[component.model.condition]\n return condition?.fn(evaluationState)\n }\n return true\n })\n\n /**\n * For conditional reveal components (which we no longer support until GDS resolves the related accessibility issues {@link https://github.com/alphagov/govuk-frontend/issues/1991}\n */\n filtered = filtered.map((component) => {\n const evaluatedComponent = component\n const content = evaluatedComponent.model.content\n if (Array.isArray(content)) {\n evaluatedComponent.model.content = content.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n // apply condition to items for radios, checkboxes etc\n const items = evaluatedComponent.model.items\n\n if (Array.isArray(items)) {\n evaluatedComponent.model.items = items.filter((item) =>\n item.condition\n ? model.conditions[item.condition]?.fn(evaluationState)\n : true\n )\n }\n\n return evaluatedComponent\n })\n\n return filtered\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, model, viewName } = this\n const { evaluationState } = context\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n // Copy any URL params into the form state (if not already done so)\n if (await prefillStateFromQueryParameters(request, this)) {\n // Forward to same page without query string\n return h.redirect(request.url.pathname)\n }\n\n const viewModel = this.getViewModel(request, context, translator)\n viewModel.errors = collection.getViewErrors(translator, viewModel.errors)\n\n const flashedError = request.yar.flash(COMPONENT_STATE_ERROR)\n const flashedErrors = !Array.isArray(flashedError) ? [flashedError] : []\n\n viewModel.errors = (viewModel.errors ?? []).concat(flashedErrors)\n\n const paymentExpiredFlash = request.yar.flash(\n PAYMENT_EXPIRED_NOTIFICATION\n )\n viewModel.showPaymentExpiredNotification =\n !Array.isArray(paymentExpiredFlash)\n\n /**\n * Content components can be hidden based on a condition. If the condition evaluates to true, it is safe to be kept, otherwise discard it\n */\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n return h.view(viewName, {\n ...viewModel,\n t\n })\n }\n }\n\n async hasMissingNotificationEmail(\n request: FormRequest,\n context: FormContext\n ) {\n const { path } = this\n const { params } = request\n const { isForceAccess } = context\n\n const startPath = this.getStartPath()\n const summaryPath = this.getSummaryPath()\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n // Warn the user if the form has no notification email set only on start page and summary page\n if ([startPath, summaryPath].includes(path) && !isForceAccess) {\n const { notificationEmail } = await getFormMetadata(params.slug)\n return !notificationEmail\n }\n\n return false\n }\n\n /**\n * Get the back link for a given progress.\n */\n protected getBackLink(\n request: FormContextRequest,\n context: FormContext,\n t: (key: string, opts?: Record<string, unknown>) => string\n ): BackLink | undefined {\n const { pageDef } = this\n const { path, query } = request\n const { returnUrl } = query\n const { paths } = context\n\n const itemId = this.getItemId(request)\n\n // Check answers back link\n if (returnUrl) {\n return {\n text:\n hasRepeater(pageDef) && itemId\n ? t('pages.question.backToAddAnother')\n : t('pages.question.backToCheckAnswers'),\n href: returnUrl\n }\n }\n\n // Item delete pages etc\n const backPath =\n itemId && !path.endsWith(itemId)\n ? paths.at(-1) // Back to main page\n : paths.at(-2) // Back to previous page\n\n // No back link\n if (!backPath) {\n return\n }\n\n // Default back link\n return {\n text: t('common.back'),\n href: this.getHref(backPath)\n }\n }\n\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { collection, viewName, model } = this\n const { isForceAccess, state, evaluationState } = context\n const action = request.payload.action\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (action?.startsWith(FormAction.External)) {\n return await this.dispatchExternal(request, h, context)\n }\n\n /**\n * If there are any errors, render the page with the parsed errors\n * @todo Refactor to match POST REDIRECT GET pattern\n */\n if (context.errors || isForceAccess) {\n const viewModel = this.getViewModel(request, context, translator)\n viewModel.errors = collection.getViewErrors(\n translator,\n viewModel.errors\n )\n\n // Filter our components based on their conditions using our evaluated state\n viewModel.components = this.filterConditionalComponents(\n viewModel,\n model,\n evaluationState\n )\n\n return h.view(viewName, {\n ...viewModel,\n t\n })\n }\n\n // Save state\n await this.setState(request, state)\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n // Proceed to the next page\n return this.proceed(request, h, this.getNextPath(context))\n }\n }\n\n private async dispatchExternal(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n ) {\n const { externalComponents } = getComponentsByType()\n const action = request.payload.action ?? ''\n\n // Find the external action and arguments\n // `external-{componentName}--{argname1}:{argvalue1}--{argname2}:{argvalue2}`\n // E.g. external-abcdef--amount:10--step:manual\n const externalActionsWithArgs = action\n .slice(`${FormAction.External}-`.length)\n .split('--')\n\n const externalActionArgs = externalActionsWithArgs\n .slice(1)\n .map((arg) => arg.split(':'))\n\n const args = Object.fromEntries(externalActionArgs) as Record<\n string,\n string\n >\n\n const componentName = externalActionsWithArgs[0]\n const component = this.model.componentDefMap.get(componentName)\n const componentType = component?.type\n\n if (!componentType) {\n throw Boom.internal(\n `External component of type ${componentType} not found`\n )\n }\n\n const selectedComponent = externalComponents.get(componentType)\n\n if (!selectedComponent) {\n throw Boom.internal(`External component ${componentName} not found`)\n }\n\n // Stash payload without crumb and action\n const stashedPayload = {\n ...context.payload,\n crumb: undefined,\n action: undefined\n }\n request.yar.flash(EXTERNAL_STATE_PAYLOAD, stashedPayload, true)\n\n // Clear any previous state appendage\n request.yar.clear(EXTERNAL_STATE_APPENDAGE)\n\n // Determine if this is a live form (not preview/draft)\n const { state, isPreview } = checkFormStatus(request.params)\n const isLive = state === FormStatus.Live\n\n return await selectedComponent.dispatcher(request, h, {\n component,\n controller: this,\n sourceUrl: `${request.url.pathname}${request.url.search}`,\n actionArgs: args,\n isLive,\n isPreview\n })\n }\n\n proceed(\n request: FormContextRequest,\n h: FormResponseToolkit,\n nextPath?: string\n ) {\n const nextUrl = nextPath\n ? this.getHref(nextPath) // Redirect to next page\n : this.href // Redirect to current page (refresh)\n\n return proceed(request, h, nextUrl)\n }\n\n /**\n * Handle save-and-exit action\n */\n handleSaveAndExit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const saveAndExit = getSaveAndExitHelpers(request.server)\n\n if (!saveAndExit) {\n throw Boom.internal('Server misconfigured for save and exit')\n }\n\n return saveAndExit(request, h, context)\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get getRouteOptions(): RouteOptions<FormRequestRefs> {\n return {\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n\n /**\n * {@link https://hapi.dev/api/?v=20.1.2#route-options}\n */\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n payload: {\n parse: true,\n maxBytes: Number.MAX_SAFE_INTEGER,\n failAction: 'ignore'\n },\n ext: {\n onPostHandler: {\n method(_request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -326,11 +326,10 @@ export class RepeatPageController extends QuestionPageController {
326
326
  errors
327
327
  } = context;
328
328
  const {
329
- t
329
+ t,
330
+ tPage
330
331
  } = translator;
331
- const {
332
- title
333
- } = repeat.options;
332
+ const title = tPage(this.pageDef, 'repeatTitle') || repeat.options.title;
334
333
  const summaryList = {
335
334
  classes: 'govuk-summary-list--long-actions',
336
335
  rows: []
@@ -1 +1 @@
1
- {"version":3,"file":"RepeatPageController.js","names":["randomUUID","Boom","Joi","isRepeatState","redirectPath","QuestionPageController","FormAction","RepeatPageController","listSummaryViewName","listDeleteViewName","repeat","allowSaveAndExit","constructor","model","pageDef","options","schema","itemId","string","uuid","required","collection","formSchema","append","stateSchema","object","keys","name","array","items","min","max","label","title","getFormParams","request","params","payload","getFormDataFromState","state","list","getListFromState","getItemId","item","getItemFromList","getStateFromValidForm","badRequest","itemState","updated","newList","push","indexOf","proceed","h","nextPath","getSummaryPath","find","values","makeGetRouteHandler","context","path","query","summaryPath","returnUrl","force","length","makeGetListSummaryRouteHandler","translator","getTranslator","t","viewModel","getListSummaryViewModel","view","makePostListSummaryRouteHandler","action","hasErrorMin","Continue","hasErrorMax","AddAnother","count","errors","href","text","SaveAndExit","handleSaveAndExit","getNextPath","makeGetItemDeleteRouteHandler","notFound","backLink","getBackLink","pageTitle","itemTitle","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","splice","update","mergeState","getViewModel","tPage","itemNumber","repeatCaption","sectionTitle","isForceAccess","summaryList","classes","rows","Array","isArray","forEach","index","getHref","visuallyHiddenText","itemDisplayText","fields","getDisplayStringFromState","key","value","actions","repeatTitle","showTitle","checkAnswers","shouldShowSaveAndExit","server"],"sources":["../../../../../src/server/plugins/engine/pageControllers/RepeatPageController.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\n\nimport { type PageRepeat, type Repeat } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport Joi from 'joi'\n\nimport { isRepeatState } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { redirectPath } 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 { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type RepeatItemState,\n type RepeatListState,\n type RepeaterSummaryPageViewModel,\n type SummaryList,\n type SummaryListAction\n} from '~/src/server/plugins/engine/types.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class RepeatPageController extends QuestionPageController {\n declare pageDef: PageRepeat\n\n listSummaryViewName = 'repeat-list-summary'\n listDeleteViewName = 'item-delete'\n repeat: Repeat\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: PageRepeat) {\n super(model, pageDef)\n\n this.repeat = pageDef.repeat\n\n const { options, schema } = this.repeat\n const itemId = Joi.string().uuid().required()\n\n this.collection.formSchema = this.collection.formSchema.append({ itemId })\n this.collection.stateSchema = Joi.object<RepeatItemState>().keys({\n [options.name]: Joi.array()\n .items(this.collection.stateSchema.append({ itemId }))\n .min(schema.min)\n .max(schema.max)\n .label(`${options.title} list`)\n .required()\n })\n }\n\n get keys() {\n const { repeat } = this\n return [repeat.options.name, ...super.keys]\n }\n\n getFormParams(request?: FormContextRequest) {\n const params = super.getFormParams(request)\n\n // Apply an itemId to the form payload\n if (request?.payload) {\n params.itemId = request.params.itemId ?? randomUUID()\n }\n\n return params\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { repeat } = this\n\n const params = this.getFormParams(request)\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n\n // Create payload with repeater list state\n if (!itemId) {\n return {\n ...params,\n [repeat.options.name]: list\n }\n }\n\n // Create payload with repeater item state\n const item = this.getItemFromList(list, itemId)\n\n return {\n ...params,\n ...item\n }\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ) {\n const itemId = this.getItemId(request)\n\n if (!itemId) {\n throw Boom.badRequest('No item ID found')\n }\n\n const list = this.getListFromState(state)\n const item = this.getItemFromList(list, itemId)\n\n const itemState = super.getStateFromValidForm(request, state, payload)\n const updated: RepeatItemState = { ...itemState, itemId }\n const newList = [...list]\n\n if (!item) {\n // Adding a new item\n newList.push(updated)\n } else {\n // Update an existing item\n newList[list.indexOf(item)] = updated\n }\n\n return {\n [this.repeat.options.name]: newList\n }\n }\n\n proceed(request: FormContextRequest, h: FormResponseToolkit) {\n const nextPath = this.getSummaryPath(request)\n return super.proceed(request, h, nextPath)\n }\n\n getItemFromList(list: RepeatListState, itemId?: string) {\n return list.find((item) => item.itemId === itemId)\n }\n\n getListFromState(state: FormSubmissionState) {\n const { name } = this.repeat.options\n const values = state[name]\n\n return isRepeatState(values) ? values : []\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const itemId = this.getItemId(request)\n const list = this.getListFromState(state)\n\n if (!itemId) {\n const summaryPath = this.getSummaryPath(request)\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl,\n force: query.force\n })\n\n // Only redirect to new item when list is empty\n return super.proceed(request, h, list.length ? summaryPath : nextPath)\n }\n\n return super.makeGetRouteHandler()(request, context, h)\n }\n }\n\n makeGetListSummaryRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n }\n\n makePostListSummaryRouteHandler() {\n return (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path, repeat } = this\n const { query } = request\n const { schema } = repeat\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const { action } = this.getFormParams(request)\n\n const hasErrorMin =\n action === FormAction.Continue && list.length < schema.min\n\n const hasErrorMax =\n (action === FormAction.AddAnother && list.length >= schema.max) ||\n (action === FormAction.Continue && list.length > schema.max)\n\n // Show error if repeat limits apply\n if (hasErrorMin || hasErrorMax) {\n const count = hasErrorMax ? schema.max : schema.min\n\n context.errors = [\n {\n path: [],\n href: '',\n name: '',\n text: hasErrorMax\n ? t('pages.repeater.tooMany', { count })\n : t('pages.repeater.tooFew', { count })\n }\n ]\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n\n if (action === FormAction.AddAnother) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n const nextPath = this.getNextPath(context)\n return super.proceed(request, h, nextPath)\n }\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { state } = context\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n const { title } = this.repeat.options\n\n return h.view(this.listDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: t('pages.repeater.removeAnswer'),\n itemTitle: `${title} ${list.indexOf(item) + 1}`,\n buttonConfirm: { text: t('pages.repeater.remove') },\n buttonCancel: { text: t('pages.repeater.cancel') },\n t\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { repeat } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const { t } = this.getTranslator(request)\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n // Remove the item from the list\n if (confirm) {\n list.splice(list.indexOf(item), 1)\n\n const update = {\n [repeat.options.name]: list\n }\n\n await this.mergeState(request, state, update)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { state } = context\n const { tPage } = translator\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const viewModel = super.getViewModel(request, context, translator)\n const itemNumber = item ? list.indexOf(item) + 1 : list.length + 1\n const title =\n tPage(this.pageDef, 'repeatTitle') || this.pageDef.repeat.options.title\n const repeatCaption = `${title} ${itemNumber}`\n\n return {\n ...viewModel,\n\n sectionTitle: viewModel.sectionTitle\n ? `${viewModel.sectionTitle}: ${repeatCaption}`\n : repeatCaption\n }\n }\n\n getListSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n list: RepeatListState,\n translator: Translator\n ): RepeaterSummaryPageViewModel {\n const { collection, href, repeat } = this\n const { query } = request\n const { isForceAccess, errors } = context\n\n const { t } = translator\n\n const { title } = repeat.options\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-actions',\n rows: []\n }\n\n let count = 0\n\n if (Array.isArray(list)) {\n count = list.length\n\n const summaryPath = this.getSummaryPath(request)\n\n list.forEach((item, index) => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}`, {\n returnUrl: query.returnUrl ?? this.getHref(summaryPath)\n }),\n text: t('pages.repeater.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n\n if (count > 1) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}/confirm-delete`, {\n returnUrl: query.returnUrl\n }),\n text: t('pages.repeater.remove'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n }\n }\n\n const itemDisplayText = collection.fields.length\n ? collection.fields[0].getDisplayStringFromState(item, translator)\n : ''\n\n summaryList.rows.push({\n key: {\n text: `${title} ${index + 1}`\n },\n value: {\n text: itemDisplayText || t('pages.repeater.notProvided')\n },\n actions: {\n items\n }\n })\n })\n }\n\n return {\n ...this.viewModel,\n backLink: this.getBackLink(request, context, t),\n repeatTitle: title,\n pageTitle: t('pages.repeater.pageTitle', { count }),\n showTitle: true,\n context,\n errors,\n checkAnswers: [{ summaryList }],\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getSummaryPath(request?: FormContextRequest) {\n const { path } = this\n\n const summaryPath = super.getSummaryPath()\n\n if (!request) {\n return summaryPath\n }\n\n const { query } = request\n\n return redirectPath(`${path}${summaryPath}`, {\n returnUrl: query.returnUrl\n })\n }\n}\n"],"mappings":"AAAA,SAASA,UAAU,QAAQ,QAAQ;AAGnC,OAAOC,IAAI,MAAM,YAAY;AAC7B,OAAOC,GAAG,MAAM,KAAK;AAErB,SAASC,aAAa;AACtB,SAASC,YAAY;AAGrB,SAASC,sBAAsB;AAc/B,SACEC,UAAU;AAMZ,OAAO,MAAMC,oBAAoB,SAASF,sBAAsB,CAAC;EAG/DG,mBAAmB,GAAG,qBAAqB;EAC3CC,kBAAkB,GAAG,aAAa;EAClCC,MAAM;EACNC,gBAAgB,GAAG,IAAI;EAEvBC,WAAWA,CAACC,KAAgB,EAAEC,OAAmB,EAAE;IACjD,KAAK,CAACD,KAAK,EAAEC,OAAO,CAAC;IAErB,IAAI,CAACJ,MAAM,GAAGI,OAAO,CAACJ,MAAM;IAE5B,MAAM;MAAEK,OAAO;MAAEC;IAAO,CAAC,GAAG,IAAI,CAACN,MAAM;IACvC,MAAMO,MAAM,GAAGf,GAAG,CAACgB,MAAM,CAAC,CAAC,CAACC,IAAI,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;IAE7C,IAAI,CAACC,UAAU,CAACC,UAAU,GAAG,IAAI,CAACD,UAAU,CAACC,UAAU,CAACC,MAAM,CAAC;MAAEN;IAAO,CAAC,CAAC;IAC1E,IAAI,CAACI,UAAU,CAACG,WAAW,GAAGtB,GAAG,CAACuB,MAAM,CAAkB,CAAC,CAACC,IAAI,CAAC;MAC/D,CAACX,OAAO,CAACY,IAAI,GAAGzB,GAAG,CAAC0B,KAAK,CAAC,CAAC,CACxBC,KAAK,CAAC,IAAI,CAACR,UAAU,CAACG,WAAW,CAACD,MAAM,CAAC;QAAEN;MAAO,CAAC,CAAC,CAAC,CACrDa,GAAG,CAACd,MAAM,CAACc,GAAG,CAAC,CACfC,GAAG,CAACf,MAAM,CAACe,GAAG,CAAC,CACfC,KAAK,CAAC,GAAGjB,OAAO,CAACkB,KAAK,OAAO,CAAC,CAC9Bb,QAAQ,CAAC;IACd,CAAC,CAAC;EACJ;EAEA,IAAIM,IAAIA,CAAA,EAAG;IACT,MAAM;MAAEhB;IAAO,CAAC,GAAG,IAAI;IACvB,OAAO,CAACA,MAAM,CAACK,OAAO,CAACY,IAAI,EAAE,GAAG,KAAK,CAACD,IAAI,CAAC;EAC7C;EAEAQ,aAAaA,CAACC,OAA4B,EAAE;IAC1C,MAAMC,MAAM,GAAG,KAAK,CAACF,aAAa,CAACC,OAAO,CAAC;;IAE3C;IACA,IAAIA,OAAO,EAAEE,OAAO,EAAE;MACpBD,MAAM,CAACnB,MAAM,GAAGkB,OAAO,CAACC,MAAM,CAACnB,MAAM,IAAIjB,UAAU,CAAC,CAAC;IACvD;IAEA,OAAOoC,MAAM;EACf;EAEAE,oBAAoBA,CAClBH,OAAuC,EACvCI,KAA0B,EAC1B;IACA,MAAM;MAAE7B;IAAO,CAAC,GAAG,IAAI;IAEvB,MAAM0B,MAAM,GAAG,IAAI,CAACF,aAAa,CAACC,OAAO,CAAC;IAC1C,MAAMK,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;IACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;;IAEtC;IACA,IAAI,CAAClB,MAAM,EAAE;MACX,OAAO;QACL,GAAGmB,MAAM;QACT,CAAC1B,MAAM,CAACK,OAAO,CAACY,IAAI,GAAGa;MACzB,CAAC;IACH;;IAEA;IACA,MAAMG,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;IAE/C,OAAO;MACL,GAAGmB,MAAM;MACT,GAAGO;IACL,CAAC;EACH;EAEAE,qBAAqBA,CACnBV,OAA2B,EAC3BI,KAA0B,EAC1BF,OAAoB,EACpB;IACA,MAAMpB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;IAEtC,IAAI,CAAClB,MAAM,EAAE;MACX,MAAMhB,IAAI,CAAC6C,UAAU,CAAC,kBAAkB,CAAC;IAC3C;IAEA,MAAMN,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;IACzC,MAAMI,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;IAE/C,MAAM8B,SAAS,GAAG,KAAK,CAACF,qBAAqB,CAACV,OAAO,EAAEI,KAAK,EAAEF,OAAO,CAAC;IACtE,MAAMW,OAAwB,GAAG;MAAE,GAAGD,SAAS;MAAE9B;IAAO,CAAC;IACzD,MAAMgC,OAAO,GAAG,CAAC,GAAGT,IAAI,CAAC;IAEzB,IAAI,CAACG,IAAI,EAAE;MACT;MACAM,OAAO,CAACC,IAAI,CAACF,OAAO,CAAC;IACvB,CAAC,MAAM;MACL;MACAC,OAAO,CAACT,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,CAAC,GAAGK,OAAO;IACvC;IAEA,OAAO;MACL,CAAC,IAAI,CAACtC,MAAM,CAACK,OAAO,CAACY,IAAI,GAAGsB;IAC9B,CAAC;EACH;EAEAG,OAAOA,CAACjB,OAA2B,EAAEkB,CAAsB,EAAE;IAC3D,MAAMC,QAAQ,GAAG,IAAI,CAACC,cAAc,CAACpB,OAAO,CAAC;IAC7C,OAAO,KAAK,CAACiB,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;EAC5C;EAEAV,eAAeA,CAACJ,IAAqB,EAAEvB,MAAe,EAAE;IACtD,OAAOuB,IAAI,CAACgB,IAAI,CAAEb,IAAI,IAAKA,IAAI,CAAC1B,MAAM,KAAKA,MAAM,CAAC;EACpD;EAEAwB,gBAAgBA,CAACF,KAA0B,EAAE;IAC3C,MAAM;MAAEZ;IAAK,CAAC,GAAG,IAAI,CAACjB,MAAM,CAACK,OAAO;IACpC,MAAM0C,MAAM,GAAGlB,KAAK,CAACZ,IAAI,CAAC;IAE1B,OAAOxB,aAAa,CAACsD,MAAM,CAAC,GAAGA,MAAM,GAAG,EAAE;EAC5C;EAEAC,mBAAmBA,CAAA,EAAG;IACpB,OAAO,OACLvB,OAAoB,EACpBwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEO;MAAK,CAAC,GAAG,IAAI;MACrB,MAAM;QAAEC;MAAM,CAAC,GAAG1B,OAAO;MACzB,MAAM;QAAEI;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAM1C,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;MACtC,MAAMK,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MAEzC,IAAI,CAACtB,MAAM,EAAE;QACX,MAAM6C,WAAW,GAAG,IAAI,CAACP,cAAc,CAACpB,OAAO,CAAC;QAChD,MAAMmB,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE,SAAS;UAC1BC,KAAK,EAAEH,KAAK,CAACG;QACf,CAAC,CAAC;;QAEF;QACA,OAAO,KAAK,CAACZ,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEb,IAAI,CAACyB,MAAM,GAAGH,WAAW,GAAGR,QAAQ,CAAC;MACxE;MAEA,OAAO,KAAK,CAACI,mBAAmB,CAAC,CAAC,CAACvB,OAAO,EAAEwB,OAAO,EAAEN,CAAC,CAAC;IACzD,CAAC;EACH;EAEAa,8BAA8BA,CAAA,EAAG;IAC/B,OAAO,CACL/B,OAAoB,EACpBwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEO;MAAK,CAAC,GAAG,IAAI;MACrB,MAAM;QAAEC;MAAM,CAAC,GAAG1B,OAAO;MACzB,MAAM;QAAEI;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAMnB,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MAEzC,IAAI,CAACC,IAAI,CAACyB,MAAM,EAAE;QAChB,MAAMX,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE;QACnB,CAAC,CAAC;QAEF,OAAO,KAAK,CAACX,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;MAC5C;MAEA,MAAMa,UAAU,GAAG,IAAI,CAACC,aAAa,CAACjC,OAAO,CAAC;MAC9C,MAAM;QAAEkC;MAAE,CAAC,GAAGF,UAAU;MAExB,MAAMG,SAAS,GAAG,IAAI,CAACC,uBAAuB,CAC5CpC,OAAO,EACPwB,OAAO,EACPnB,IAAI,EACJ2B,UACF,CAAC;MAED,OAAOd,CAAC,CAACmB,IAAI,CAAC,IAAI,CAAChE,mBAAmB,EAAE;QACtC,GAAG8D,SAAS;QACZD;MACF,CAAC,CAAC;IACJ,CAAC;EACH;EAEAI,+BAA+BA,CAAA,EAAG;IAChC,OAAO,CACLtC,OAA2B,EAC3BwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEO,IAAI;QAAElD;MAAO,CAAC,GAAG,IAAI;MAC7B,MAAM;QAAEmD;MAAM,CAAC,GAAG1B,OAAO;MACzB,MAAM;QAAEnB;MAAO,CAAC,GAAGN,MAAM;MACzB,MAAM;QAAE6B;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAMnB,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MAEzC,IAAI,CAACC,IAAI,CAACyB,MAAM,EAAE;QAChB,MAAMX,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE;QACnB,CAAC,CAAC;QAEF,OAAO,KAAK,CAACX,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;MAC5C;MAEA,MAAMa,UAAU,GAAG,IAAI,CAACC,aAAa,CAACjC,OAAO,CAAC;MAC9C,MAAM;QAAEkC;MAAE,CAAC,GAAGF,UAAU;MAExB,MAAM;QAAEO;MAAO,CAAC,GAAG,IAAI,CAACxC,aAAa,CAACC,OAAO,CAAC;MAE9C,MAAMwC,WAAW,GACfD,MAAM,KAAKpE,UAAU,CAACsE,QAAQ,IAAIpC,IAAI,CAACyB,MAAM,GAAGjD,MAAM,CAACc,GAAG;MAE5D,MAAM+C,WAAW,GACdH,MAAM,KAAKpE,UAAU,CAACwE,UAAU,IAAItC,IAAI,CAACyB,MAAM,IAAIjD,MAAM,CAACe,GAAG,IAC7D2C,MAAM,KAAKpE,UAAU,CAACsE,QAAQ,IAAIpC,IAAI,CAACyB,MAAM,GAAGjD,MAAM,CAACe,GAAI;;MAE9D;MACA,IAAI4C,WAAW,IAAIE,WAAW,EAAE;QAC9B,MAAME,KAAK,GAAGF,WAAW,GAAG7D,MAAM,CAACe,GAAG,GAAGf,MAAM,CAACc,GAAG;QAEnD6B,OAAO,CAACqB,MAAM,GAAG,CACf;UACEpB,IAAI,EAAE,EAAE;UACRqB,IAAI,EAAE,EAAE;UACRtD,IAAI,EAAE,EAAE;UACRuD,IAAI,EAAEL,WAAW,GACbR,CAAC,CAAC,wBAAwB,EAAE;YAAEU;UAAM,CAAC,CAAC,GACtCV,CAAC,CAAC,uBAAuB,EAAE;YAAEU;UAAM,CAAC;QAC1C,CAAC,CACF;QAED,MAAMT,SAAS,GAAG,IAAI,CAACC,uBAAuB,CAC5CpC,OAAO,EACPwB,OAAO,EACPnB,IAAI,EACJ2B,UACF,CAAC;QAED,OAAOd,CAAC,CAACmB,IAAI,CAAC,IAAI,CAAChE,mBAAmB,EAAE;UACtC,GAAG8D,SAAS;UACZD;QACF,CAAC,CAAC;MACJ;MAEA,IAAIK,MAAM,KAAKpE,UAAU,CAACwE,UAAU,EAAE;QACpC,MAAMxB,QAAQ,GAAGlD,YAAY,CAAC,GAAGwD,IAAI,IAAI5D,UAAU,CAAC,CAAC,EAAE,EAAE;UACvD+D,SAAS,EAAEF,KAAK,CAACE;QACnB,CAAC,CAAC;QAEF,OAAO,KAAK,CAACX,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;MAC5C;;MAEA;MACA,IAAIoB,MAAM,KAAKpE,UAAU,CAAC6E,WAAW,EAAE;QACrC,OAAO,IAAI,CAACC,iBAAiB,CAACjD,OAAO,EAAEwB,OAAO,EAAEN,CAAC,CAAC;MACpD;MAEA,MAAMC,QAAQ,GAAG,IAAI,CAAC+B,WAAW,CAAC1B,OAAO,CAAC;MAC1C,OAAO,KAAK,CAACP,OAAO,CAACjB,OAAO,EAAEkB,CAAC,EAAEC,QAAQ,CAAC;IAC5C,CAAC;EACH;EAEAgC,6BAA6BA,CAAA,EAAG;IAC9B,OAAO,CACLnD,OAAoB,EACpBwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAEiB;MAAU,CAAC,GAAG,IAAI;MAC1B,MAAM;QAAE/B;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAMnB,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;MACtC,MAAMQ,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;MAE/C,MAAMkD,UAAU,GAAG,IAAI,CAACC,aAAa,CAACjC,OAAO,CAAC;MAC9C,MAAM;QAAEkC;MAAE,CAAC,GAAGF,UAAU;MAExB,IAAI,CAACxB,IAAI,IAAIH,IAAI,CAACyB,MAAM,KAAK,CAAC,EAAE;QAC9B,MAAMhE,IAAI,CAACsF,QAAQ,CACjB5C,IAAI,GACA0B,CAAC,CAAC,wCAAwC,CAAC,GAC3CA,CAAC,CAAC,qCAAqC,CAC7C,CAAC;MACH;MAEA,MAAM;QAAEpC;MAAM,CAAC,GAAG,IAAI,CAACvB,MAAM,CAACK,OAAO;MAErC,OAAOsC,CAAC,CAACmB,IAAI,CAAC,IAAI,CAAC/D,kBAAkB,EAAE;QACrC,GAAG6D,SAAS;QACZX,OAAO;QACP6B,QAAQ,EAAE,IAAI,CAACC,WAAW,CAACtD,OAAO,EAAEwB,OAAO,EAAEU,CAAC,CAAC;QAC/CqB,SAAS,EAAErB,CAAC,CAAC,6BAA6B,CAAC;QAC3CsB,SAAS,EAAE,GAAG1D,KAAK,IAAIO,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,GAAG,CAAC,EAAE;QAC/CiD,aAAa,EAAE;UAAEV,IAAI,EAAEb,CAAC,CAAC,uBAAuB;QAAE,CAAC;QACnDwB,YAAY,EAAE;UAAEX,IAAI,EAAEb,CAAC,CAAC,uBAAuB;QAAE,CAAC;QAClDA;MACF,CAAmC,CAAC;IACtC,CAAC;EACH;EAEAyB,8BAA8BA,CAAA,EAAG;IAC/B,OAAO,OACL3D,OAA2B,EAC3BwB,OAAoB,EACpBN,CAAsB,KACnB;MACH,MAAM;QAAE3C;MAAO,CAAC,GAAG,IAAI;MACvB,MAAM;QAAE6B;MAAM,CAAC,GAAGoB,OAAO;MAEzB,MAAM;QAAEoC;MAAQ,CAAC,GAAG,IAAI,CAAC7D,aAAa,CAACC,OAAO,CAAC;MAE/C,MAAMK,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;MACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;MACtC,MAAMQ,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;MAE/C,MAAM;QAAEoD;MAAE,CAAC,GAAG,IAAI,CAACD,aAAa,CAACjC,OAAO,CAAC;MAEzC,IAAI,CAACQ,IAAI,IAAIH,IAAI,CAACyB,MAAM,KAAK,CAAC,EAAE;QAC9B,MAAMhE,IAAI,CAACsF,QAAQ,CACjB5C,IAAI,GACA0B,CAAC,CAAC,wCAAwC,CAAC,GAC3CA,CAAC,CAAC,qCAAqC,CAC7C,CAAC;MACH;;MAEA;MACA,IAAI0B,OAAO,EAAE;QACXvD,IAAI,CAACwD,MAAM,CAACxD,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,EAAE,CAAC,CAAC;QAElC,MAAMsD,MAAM,GAAG;UACb,CAACvF,MAAM,CAACK,OAAO,CAACY,IAAI,GAAGa;QACzB,CAAC;QAED,MAAM,IAAI,CAAC0D,UAAU,CAAC/D,OAAO,EAAEI,KAAK,EAAE0D,MAAM,CAAC;MAC/C;MAEA,OAAO,IAAI,CAAC7C,OAAO,CAACjB,OAAO,EAAEkB,CAAC,CAAC;IACjC,CAAC;EACH;EAEA8C,YAAYA,CACVhE,OAA2B,EAC3BwB,OAAoB,EACpBQ,UAAsB,EACH;IACnB,MAAM;MAAE5B;IAAM,CAAC,GAAGoB,OAAO;IACzB,MAAM;MAAEyC;IAAM,CAAC,GAAGjC,UAAU;IAE5B,MAAM3B,IAAI,GAAG,IAAI,CAACC,gBAAgB,CAACF,KAAK,CAAC;IACzC,MAAMtB,MAAM,GAAG,IAAI,CAACyB,SAAS,CAACP,OAAO,CAAC;IACtC,MAAMQ,IAAI,GAAG,IAAI,CAACC,eAAe,CAACJ,IAAI,EAAEvB,MAAM,CAAC;IAE/C,MAAMqD,SAAS,GAAG,KAAK,CAAC6B,YAAY,CAAChE,OAAO,EAAEwB,OAAO,EAAEQ,UAAU,CAAC;IAClE,MAAMkC,UAAU,GAAG1D,IAAI,GAAGH,IAAI,CAACW,OAAO,CAACR,IAAI,CAAC,GAAG,CAAC,GAAGH,IAAI,CAACyB,MAAM,GAAG,CAAC;IAClE,MAAMhC,KAAK,GACTmE,KAAK,CAAC,IAAI,CAACtF,OAAO,EAAE,aAAa,CAAC,IAAI,IAAI,CAACA,OAAO,CAACJ,MAAM,CAACK,OAAO,CAACkB,KAAK;IACzE,MAAMqE,aAAa,GAAG,GAAGrE,KAAK,IAAIoE,UAAU,EAAE;IAE9C,OAAO;MACL,GAAG/B,SAAS;MAEZiC,YAAY,EAAEjC,SAAS,CAACiC,YAAY,GAChC,GAAGjC,SAAS,CAACiC,YAAY,KAAKD,aAAa,EAAE,GAC7CA;IACN,CAAC;EACH;EAEA/B,uBAAuBA,CACrBpC,OAA2B,EAC3BwB,OAAoB,EACpBnB,IAAqB,EACrB2B,UAAsB,EACQ;IAC9B,MAAM;MAAE9C,UAAU;MAAE4D,IAAI;MAAEvE;IAAO,CAAC,GAAG,IAAI;IACzC,MAAM;MAAEmD;IAAM,CAAC,GAAG1B,OAAO;IACzB,MAAM;MAAEqE,aAAa;MAAExB;IAAO,CAAC,GAAGrB,OAAO;IAEzC,MAAM;MAAEU;IAAE,CAAC,GAAGF,UAAU;IAExB,MAAM;MAAElC;IAAM,CAAC,GAAGvB,MAAM,CAACK,OAAO;IAEhC,MAAM0F,WAAwB,GAAG;MAC/BC,OAAO,EAAE,kCAAkC;MAC3CC,IAAI,EAAE;IACR,CAAC;IAED,IAAI5B,KAAK,GAAG,CAAC;IAEb,IAAI6B,KAAK,CAACC,OAAO,CAACrE,IAAI,CAAC,EAAE;MACvBuC,KAAK,GAAGvC,IAAI,CAACyB,MAAM;MAEnB,MAAMH,WAAW,GAAG,IAAI,CAACP,cAAc,CAACpB,OAAO,CAAC;MAEhDK,IAAI,CAACsE,OAAO,CAAC,CAACnE,IAAI,EAAEoE,KAAK,KAAK;QAC5B,MAAMlF,KAA0B,GAAG,EAAE;;QAErC;QACA,IAAI,CAAC2E,aAAa,EAAE;UAClB3E,KAAK,CAACqB,IAAI,CAAC;YACT+B,IAAI,EAAE7E,YAAY,CAAC,GAAG6E,IAAI,IAAItC,IAAI,CAAC1B,MAAM,EAAE,EAAE;cAC3C8C,SAAS,EAAEF,KAAK,CAACE,SAAS,IAAI,IAAI,CAACiD,OAAO,CAAClD,WAAW;YACxD,CAAC,CAAC;YACFoB,IAAI,EAAEb,CAAC,CAAC,uBAAuB,CAAC;YAChCqC,OAAO,EAAE,8BAA8B;YACvCO,kBAAkB,EAAE5C,CAAC,CAAC,mCAAmC,EAAE;cACzD0C,KAAK,EAAEA,KAAK,GAAG;YACjB,CAAC;UACH,CAAC,CAAC;UAEF,IAAIhC,KAAK,GAAG,CAAC,EAAE;YACblD,KAAK,CAACqB,IAAI,CAAC;cACT+B,IAAI,EAAE7E,YAAY,CAAC,GAAG6E,IAAI,IAAItC,IAAI,CAAC1B,MAAM,iBAAiB,EAAE;gBAC1D8C,SAAS,EAAEF,KAAK,CAACE;cACnB,CAAC,CAAC;cACFmB,IAAI,EAAEb,CAAC,CAAC,uBAAuB,CAAC;cAChCqC,OAAO,EAAE,8BAA8B;cACvCO,kBAAkB,EAAE5C,CAAC,CAAC,mCAAmC,EAAE;gBACzD0C,KAAK,EAAEA,KAAK,GAAG;cACjB,CAAC;YACH,CAAC,CAAC;UACJ;QACF;QAEA,MAAMG,eAAe,GAAG7F,UAAU,CAAC8F,MAAM,CAAClD,MAAM,GAC5C5C,UAAU,CAAC8F,MAAM,CAAC,CAAC,CAAC,CAACC,yBAAyB,CAACzE,IAAI,EAAEwB,UAAU,CAAC,GAChE,EAAE;QAENsC,WAAW,CAACE,IAAI,CAACzD,IAAI,CAAC;UACpBmE,GAAG,EAAE;YACHnC,IAAI,EAAE,GAAGjD,KAAK,IAAI8E,KAAK,GAAG,CAAC;UAC7B,CAAC;UACDO,KAAK,EAAE;YACLpC,IAAI,EAAEgC,eAAe,IAAI7C,CAAC,CAAC,4BAA4B;UACzD,CAAC;UACDkD,OAAO,EAAE;YACP1F;UACF;QACF,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ;IAEA,OAAO;MACL,GAAG,IAAI,CAACyC,SAAS;MACjBkB,QAAQ,EAAE,IAAI,CAACC,WAAW,CAACtD,OAAO,EAAEwB,OAAO,EAAEU,CAAC,CAAC;MAC/CmD,WAAW,EAAEvF,KAAK;MAClByD,SAAS,EAAErB,CAAC,CAAC,0BAA0B,EAAE;QAAEU;MAAM,CAAC,CAAC;MACnD0C,SAAS,EAAE,IAAI;MACf9D,OAAO;MACPqB,MAAM;MACN0C,YAAY,EAAE,CAAC;QAAEjB;MAAY,CAAC,CAAC;MAC/B9F,gBAAgB,EAAE,IAAI,CAACgH,qBAAqB,CAACxF,OAAO,CAACyF,MAAM;IAC7D,CAAC;EACH;EAEArE,cAAcA,CAACpB,OAA4B,EAAE;IAC3C,MAAM;MAAEyB;IAAK,CAAC,GAAG,IAAI;IAErB,MAAME,WAAW,GAAG,KAAK,CAACP,cAAc,CAAC,CAAC;IAE1C,IAAI,CAACpB,OAAO,EAAE;MACZ,OAAO2B,WAAW;IACpB;IAEA,MAAM;MAAED;IAAM,CAAC,GAAG1B,OAAO;IAEzB,OAAO/B,YAAY,CAAC,GAAGwD,IAAI,GAAGE,WAAW,EAAE,EAAE;MAC3CC,SAAS,EAAEF,KAAK,CAACE;IACnB,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
1
+ {"version":3,"file":"RepeatPageController.js","names":["randomUUID","Boom","Joi","isRepeatState","redirectPath","QuestionPageController","FormAction","RepeatPageController","listSummaryViewName","listDeleteViewName","repeat","allowSaveAndExit","constructor","model","pageDef","options","schema","itemId","string","uuid","required","collection","formSchema","append","stateSchema","object","keys","name","array","items","min","max","label","title","getFormParams","request","params","payload","getFormDataFromState","state","list","getListFromState","getItemId","item","getItemFromList","getStateFromValidForm","badRequest","itemState","updated","newList","push","indexOf","proceed","h","nextPath","getSummaryPath","find","values","makeGetRouteHandler","context","path","query","summaryPath","returnUrl","force","length","makeGetListSummaryRouteHandler","translator","getTranslator","t","viewModel","getListSummaryViewModel","view","makePostListSummaryRouteHandler","action","hasErrorMin","Continue","hasErrorMax","AddAnother","count","errors","href","text","SaveAndExit","handleSaveAndExit","getNextPath","makeGetItemDeleteRouteHandler","notFound","backLink","getBackLink","pageTitle","itemTitle","buttonConfirm","buttonCancel","makePostItemDeleteRouteHandler","confirm","splice","update","mergeState","getViewModel","tPage","itemNumber","repeatCaption","sectionTitle","isForceAccess","summaryList","classes","rows","Array","isArray","forEach","index","getHref","visuallyHiddenText","itemDisplayText","fields","getDisplayStringFromState","key","value","actions","repeatTitle","showTitle","checkAnswers","shouldShowSaveAndExit","server"],"sources":["../../../../../src/server/plugins/engine/pageControllers/RepeatPageController.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\n\nimport { type PageRepeat, type Repeat } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport Joi from 'joi'\n\nimport { isRepeatState } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { redirectPath } 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 { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormPageViewModel,\n type FormPayload,\n type FormSubmissionState,\n type ItemDeletePageViewModel,\n type RepeatItemState,\n type RepeatListState,\n type RepeaterSummaryPageViewModel,\n type SummaryList,\n type SummaryListAction\n} from '~/src/server/plugins/engine/types.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class RepeatPageController extends QuestionPageController {\n declare pageDef: PageRepeat\n\n listSummaryViewName = 'repeat-list-summary'\n listDeleteViewName = 'item-delete'\n repeat: Repeat\n allowSaveAndExit = true\n\n constructor(model: FormModel, pageDef: PageRepeat) {\n super(model, pageDef)\n\n this.repeat = pageDef.repeat\n\n const { options, schema } = this.repeat\n const itemId = Joi.string().uuid().required()\n\n this.collection.formSchema = this.collection.formSchema.append({ itemId })\n this.collection.stateSchema = Joi.object<RepeatItemState>().keys({\n [options.name]: Joi.array()\n .items(this.collection.stateSchema.append({ itemId }))\n .min(schema.min)\n .max(schema.max)\n .label(`${options.title} list`)\n .required()\n })\n }\n\n get keys() {\n const { repeat } = this\n return [repeat.options.name, ...super.keys]\n }\n\n getFormParams(request?: FormContextRequest) {\n const params = super.getFormParams(request)\n\n // Apply an itemId to the form payload\n if (request?.payload) {\n params.itemId = request.params.itemId ?? randomUUID()\n }\n\n return params\n }\n\n getFormDataFromState(\n request: FormContextRequest | undefined,\n state: FormSubmissionState\n ) {\n const { repeat } = this\n\n const params = this.getFormParams(request)\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n\n // Create payload with repeater list state\n if (!itemId) {\n return {\n ...params,\n [repeat.options.name]: list\n }\n }\n\n // Create payload with repeater item state\n const item = this.getItemFromList(list, itemId)\n\n return {\n ...params,\n ...item\n }\n }\n\n getStateFromValidForm(\n request: FormContextRequest,\n state: FormSubmissionState,\n payload: FormPayload\n ) {\n const itemId = this.getItemId(request)\n\n if (!itemId) {\n throw Boom.badRequest('No item ID found')\n }\n\n const list = this.getListFromState(state)\n const item = this.getItemFromList(list, itemId)\n\n const itemState = super.getStateFromValidForm(request, state, payload)\n const updated: RepeatItemState = { ...itemState, itemId }\n const newList = [...list]\n\n if (!item) {\n // Adding a new item\n newList.push(updated)\n } else {\n // Update an existing item\n newList[list.indexOf(item)] = updated\n }\n\n return {\n [this.repeat.options.name]: newList\n }\n }\n\n proceed(request: FormContextRequest, h: FormResponseToolkit) {\n const nextPath = this.getSummaryPath(request)\n return super.proceed(request, h, nextPath)\n }\n\n getItemFromList(list: RepeatListState, itemId?: string) {\n return list.find((item) => item.itemId === itemId)\n }\n\n getListFromState(state: FormSubmissionState) {\n const { name } = this.repeat.options\n const values = state[name]\n\n return isRepeatState(values) ? values : []\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const itemId = this.getItemId(request)\n const list = this.getListFromState(state)\n\n if (!itemId) {\n const summaryPath = this.getSummaryPath(request)\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl,\n force: query.force\n })\n\n // Only redirect to new item when list is empty\n return super.proceed(request, h, list.length ? summaryPath : nextPath)\n }\n\n return super.makeGetRouteHandler()(request, context, h)\n }\n }\n\n makeGetListSummaryRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path } = this\n const { query } = request\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n }\n\n makePostListSummaryRouteHandler() {\n return (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { path, repeat } = this\n const { query } = request\n const { schema } = repeat\n const { state } = context\n\n const list = this.getListFromState(state)\n\n if (!list.length) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n const { action } = this.getFormParams(request)\n\n const hasErrorMin =\n action === FormAction.Continue && list.length < schema.min\n\n const hasErrorMax =\n (action === FormAction.AddAnother && list.length >= schema.max) ||\n (action === FormAction.Continue && list.length > schema.max)\n\n // Show error if repeat limits apply\n if (hasErrorMin || hasErrorMax) {\n const count = hasErrorMax ? schema.max : schema.min\n\n context.errors = [\n {\n path: [],\n href: '',\n name: '',\n text: hasErrorMax\n ? t('pages.repeater.tooMany', { count })\n : t('pages.repeater.tooFew', { count })\n }\n ]\n\n const viewModel = this.getListSummaryViewModel(\n request,\n context,\n list,\n translator\n )\n\n return h.view(this.listSummaryViewName, {\n ...viewModel,\n t\n })\n }\n\n if (action === FormAction.AddAnother) {\n const nextPath = redirectPath(`${path}/${randomUUID()}`, {\n returnUrl: query.returnUrl\n })\n\n return super.proceed(request, h, nextPath)\n }\n\n // Check if this is a save-and-exit action\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n const nextPath = this.getNextPath(context)\n return super.proceed(request, h, nextPath)\n }\n }\n\n makeGetItemDeleteRouteHandler() {\n return (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewModel } = this\n const { state } = context\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n const { title } = this.repeat.options\n\n return h.view(this.listDeleteViewName, {\n ...viewModel,\n context,\n backLink: this.getBackLink(request, context, t),\n pageTitle: t('pages.repeater.removeAnswer'),\n itemTitle: `${title} ${list.indexOf(item) + 1}`,\n buttonConfirm: { text: t('pages.repeater.remove') },\n buttonCancel: { text: t('pages.repeater.cancel') },\n t\n } satisfies ItemDeletePageViewModel)\n }\n }\n\n makePostItemDeleteRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { repeat } = this\n const { state } = context\n\n const { confirm } = this.getFormParams(request)\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const { t } = this.getTranslator(request)\n\n if (!item || list.length === 1) {\n throw Boom.notFound(\n item\n ? t('pages.repeater.lastItemCannotBeRemoved')\n : t('pages.repeater.itemToRemoveNotFound')\n )\n }\n\n // Remove the item from the list\n if (confirm) {\n list.splice(list.indexOf(item), 1)\n\n const update = {\n [repeat.options.name]: list\n }\n\n await this.mergeState(request, state, update)\n }\n\n return this.proceed(request, h)\n }\n }\n\n getViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): FormPageViewModel {\n const { state } = context\n const { tPage } = translator\n\n const list = this.getListFromState(state)\n const itemId = this.getItemId(request)\n const item = this.getItemFromList(list, itemId)\n\n const viewModel = super.getViewModel(request, context, translator)\n const itemNumber = item ? list.indexOf(item) + 1 : list.length + 1\n const title =\n tPage(this.pageDef, 'repeatTitle') || this.pageDef.repeat.options.title\n const repeatCaption = `${title} ${itemNumber}`\n\n return {\n ...viewModel,\n\n sectionTitle: viewModel.sectionTitle\n ? `${viewModel.sectionTitle}: ${repeatCaption}`\n : repeatCaption\n }\n }\n\n getListSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n list: RepeatListState,\n translator: Translator\n ): RepeaterSummaryPageViewModel {\n const { collection, href, repeat } = this\n const { query } = request\n const { isForceAccess, errors } = context\n\n const { t, tPage } = translator\n\n const title = tPage(this.pageDef, 'repeatTitle') || repeat.options.title\n\n const summaryList: SummaryList = {\n classes: 'govuk-summary-list--long-actions',\n rows: []\n }\n\n let count = 0\n\n if (Array.isArray(list)) {\n count = list.length\n\n const summaryPath = this.getSummaryPath(request)\n\n list.forEach((item, index) => {\n const items: SummaryListAction[] = []\n\n // Remove summary list actions from previews\n if (!isForceAccess) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}`, {\n returnUrl: query.returnUrl ?? this.getHref(summaryPath)\n }),\n text: t('pages.repeater.change'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n\n if (count > 1) {\n items.push({\n href: redirectPath(`${href}/${item.itemId}/confirm-delete`, {\n returnUrl: query.returnUrl\n }),\n text: t('pages.repeater.remove'),\n classes: 'govuk-link--no-visited-state',\n visuallyHiddenText: t('pages.repeater.visuallyHiddenItem', {\n index: index + 1\n })\n })\n }\n }\n\n const itemDisplayText = collection.fields.length\n ? collection.fields[0].getDisplayStringFromState(item, translator)\n : ''\n\n summaryList.rows.push({\n key: {\n text: `${title} ${index + 1}`\n },\n value: {\n text: itemDisplayText || t('pages.repeater.notProvided')\n },\n actions: {\n items\n }\n })\n })\n }\n\n return {\n ...this.viewModel,\n backLink: this.getBackLink(request, context, t),\n repeatTitle: title,\n pageTitle: t('pages.repeater.pageTitle', { count }),\n showTitle: true,\n context,\n errors,\n checkAnswers: [{ summaryList }],\n allowSaveAndExit: this.shouldShowSaveAndExit(request.server)\n }\n }\n\n getSummaryPath(request?: FormContextRequest) {\n const { path } = this\n\n const summaryPath = super.getSummaryPath()\n\n if (!request) {\n return summaryPath\n }\n\n const { query } = request\n\n return redirectPath(`${path}${summaryPath}`, {\n returnUrl: query.returnUrl\n })\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -51,7 +51,7 @@ export class SummaryPageController extends QuestionPageController {
51
51
  const paymentState = paymentField.getPaymentStateFromState(state);
52
52
  if (paymentState?.amount === resolvedAmount) {
53
53
  viewModel.paymentState = paymentState;
54
- viewModel.paymentDetails = this.buildPaymentDetails(paymentField, paymentState, t);
54
+ viewModel.paymentDetails = this.buildPaymentDetails(paymentField, paymentState, translator);
55
55
  }
56
56
  if (resolvedAmount > 0) {
57
57
  viewModel.paymentRequired = true;
@@ -73,7 +73,10 @@ export class SummaryPageController extends QuestionPageController {
73
73
  viewModel.errors = errors;
74
74
  return viewModel;
75
75
  }
76
- buildPaymentDetails(paymentField, paymentState, t) {
76
+ buildPaymentDetails(paymentField, paymentState, translator) {
77
+ const {
78
+ t
79
+ } = translator;
77
80
  const rows = [{
78
81
  key: {
79
82
  text: t('pages.summary.paymentFor')
@@ -102,7 +105,7 @@ export class SummaryPageController extends QuestionPageController {
102
105
  text: t('pages.summary.dateOfPayment')
103
106
  },
104
107
  value: {
105
- text: formatPaymentDate(paymentState.preAuth.createdAt)
108
+ text: formatPaymentDate(paymentState.preAuth.createdAt, translator.language)
106
109
  }
107
110
  });
108
111
  }
@@ -360,7 +363,10 @@ function submitData(model, items, retrievalKey, sessionId, translator, reference
360
363
  retrievalKey,
361
364
  referenceNumber,
362
365
  main: buildMainRecords(items, translator),
363
- repeaters: buildRepeaterRecords(items, translator)
366
+ repeaters: buildRepeaterRecords(items, translator),
367
+ // Only populate the language property if the form is multi-language enabled
368
+ // @ts-expect-error - dynamic language property
369
+ language: model.def.metadata?.translations?.cy ? translator.language : undefined
364
370
  };
365
371
  return submit(payload);
366
372
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SummaryPageController.js","names":["hasComponentsEvenIfNoNext","Boom","StatusCodes","COMPONENT_STATE_ERROR","PAYMENT_EXPIRED_NOTIFICATION","ComponentCollection","PaymentField","checkEmailAddressForLiveFormSubmission","checkFormStatus","createError","getCacheService","SummaryViewModel","QuestionPageController","InvalidComponentStateError","PaymentErrorTypes","PaymentPreAuthError","PaymentSubmissionError","buildMainRecords","buildRepeaterRecords","DEFAULT_PAYMENT_HELP_URL","formatCurrency","formatPaymentDate","FormAction","SummaryPageController","allowSaveAndExit","findPaymentField","model","pages","flatMap","page","collection","fields","find","field","constructor","pageDef","viewName","components","getSummaryViewModel","request","context","translator","t","viewModel","payload","errors","state","paymentField","resolvedAmount","resolveAmount","options","paymentState","getPaymentStateFromState","amount","paymentDetails","buildPaymentDetails","paymentRequired","preAuth","status","paymentPreAuthorized","getViewModel","backLink","getBackLink","feedbackLink","phaseTag","shouldShowSaveAndExit","server","rows","key","text","value","description","reference","createdAt","push","title","summaryList","makeGetRouteHandler","h","getTranslator","query","paymentComplete","handleFormSubmit","reconcilePaymentState","hasMissingNotificationEmail","view","cacheService","resetComponentStates","name","makePostRouteHandler","action","SaveAndExit","handleSaveAndExit","params","formsService","services","getFormMetadata","formMetadata","slug","notificationEmail","isPreview","submitForm","error","handleSubmissionError","setConfirmationState","confirmed","formId","referenceNumber","clearState","proceed","getStatusPath","handleInvalidComponentStateError","handlePaymentPreAuthError","handlePaymentSubmissionError","govukError","component","userMessage","yar","flash","getStateKeys","path","shouldResetState","errorType","PaymentExpired","PaymentIncomplete","redirect","getHref","code","SEE_OTHER","redirectPath","undefined","helpUrl","helpLink","contactUsLink","helpLinkHtml","postRouteOptions","ext","onPreHandler","method","continue","summaryViewModel","emailAddress","finaliseComponents","paymentWasCaptured","hasPaymentBeenCaptured","formStatus","logTags","logger","info","items","getFormSubmissionData","details","submitResponse","submitData","id","badRequest","outputService","submit","err","contact","online","url","capture","metadata","allFields","Set","relevantPages","filter","onSubmit","retrievalKey","sessionId","formSubmissionService","main","repeaters","map","href","flat","paymentItems","getPaymentFieldItems","label","summaryLabel","getDisplayStringFromState"],"sources":["../../../../../src/server/plugins/engine/pageControllers/SummaryPageController.ts"],"sourcesContent":["import {\n hasComponentsEvenIfNoNext,\n type FormMetadata,\n type Page,\n type SubmitPayload\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { StatusCodes } from 'http-status-codes'\n\nimport {\n COMPONENT_STATE_ERROR,\n PAYMENT_EXPIRED_NOTIFICATION\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n createError,\n getCacheService\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n SummaryViewModel,\n type FormModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField\n} from '~/src/server/plugins/engine/models/types.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n InvalidComponentStateError,\n PaymentErrorTypes,\n PaymentPreAuthError,\n PaymentSubmissionError\n} from '~/src/server/plugins/engine/pageControllers/errors.js'\nimport {\n buildMainRecords,\n buildRepeaterRecords\n} from '~/src/server/plugins/engine/pageControllers/helpers/submission.js'\nimport {\n type FormConfirmationState,\n type FormContext,\n type FormContextRequest\n} from '~/src/server/plugins/engine/types.js'\nimport {\n DEFAULT_PAYMENT_HELP_URL,\n formatCurrency,\n formatPaymentDate\n} from '~/src/server/plugins/payment/helper.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class SummaryPageController extends QuestionPageController {\n declare pageDef: Page\n allowSaveAndExit = true\n\n /**\n * The controller which is used when Page[\"controller\"] is defined as \"./pages/summary.js\"\n */\n\n /**\n * Finds the PaymentField component across all pages in the model.\n * Payment pages are skipped in the normal page walk\n */\n private findPaymentField(): PaymentField | undefined {\n return this.model.pages\n .flatMap((page) => page.collection.fields)\n .find((field): field is PaymentField => field instanceof PaymentField)\n }\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n this.viewName = 'summary'\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponentsEvenIfNoNext(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n }\n\n getSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): SummaryViewModel {\n const { t } = translator\n\n const viewModel = new SummaryViewModel(request, this, context, translator)\n\n const { payload, errors, state } = context\n\n const paymentField = this.findPaymentField()\n\n if (paymentField) {\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n state\n )\n const paymentState = paymentField.getPaymentStateFromState(state)\n\n if (paymentState?.amount === resolvedAmount) {\n viewModel.paymentState = paymentState\n viewModel.paymentDetails = this.buildPaymentDetails(\n paymentField,\n paymentState,\n t\n )\n }\n\n if (resolvedAmount > 0) {\n viewModel.paymentRequired = true\n }\n if (\n paymentState &&\n paymentState.preAuth?.status === 'success' &&\n paymentState.amount === resolvedAmount\n ) {\n viewModel.paymentPreAuthorized = true\n }\n }\n\n const components = this.collection.getViewModel({\n payload,\n errors,\n translator\n })\n\n viewModel.backLink = this.getBackLink(request, context, t)\n viewModel.feedbackLink = this.feedbackLink\n viewModel.phaseTag = this.phaseTag\n viewModel.components = components\n viewModel.allowSaveAndExit = this.shouldShowSaveAndExit(request.server)\n viewModel.errors = errors\n\n return viewModel\n }\n\n private buildPaymentDetails(\n paymentField: PaymentField,\n paymentState: NonNullable<\n ReturnType<PaymentField['getPaymentStateFromState']>\n >,\n t: (key: string, opts?: Record<string, unknown>) => string\n ) {\n const rows = [\n {\n key: { text: t('pages.summary.paymentFor') },\n value: { text: paymentState.description }\n },\n {\n key: { text: t('pages.summary.totalAmount') },\n value: { text: formatCurrency(paymentState.amount) }\n },\n {\n key: { text: t('pages.summary.reference') },\n value: { text: paymentState.reference }\n }\n ]\n\n if (paymentState.preAuth?.createdAt) {\n rows.push({\n key: { text: t('pages.summary.dateOfPayment') },\n value: { text: formatPaymentDate(paymentState.preAuth.createdAt) }\n })\n }\n\n return {\n title: { text: t('pages.summary.paymentDetailsTitle') },\n summaryList: { rows }\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a GET request at `/{id}/{path*}`,\n */\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewName } = this\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n // After GOV.UK Pay callback, auto-submit the form instead of\n // showing CYA again. The payment is already pre-authorized.\n if (request.query.paymentComplete === 'true') {\n return this.handleFormSubmit(\n request as unknown as FormRequestPayload,\n context,\n h\n )\n }\n\n await this.reconcilePaymentState(request, context)\n\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n viewModel.t = t\n return h.view(viewName, viewModel)\n }\n }\n\n /**\n * Checks if the resolved payment amount has changed since pre-auth\n * and invalidates stale payment state if so.\n */\n private async reconcilePaymentState(\n request: FormRequest,\n context: FormContext\n ) {\n const paymentField = this.findPaymentField()\n\n if (!paymentField) {\n return\n }\n\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n context.state\n )\n const paymentState = paymentField.getPaymentStateFromState(context.state)\n\n if (paymentState && paymentState.amount !== resolvedAmount) {\n const cacheService = getCacheService(request.server)\n await cacheService.resetComponentStates(request, [paymentField.name])\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a POST request at `/{id}/{path*}`.\n * If a form is incomplete, a user will be redirected to the start page.\n */\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { action } = request.payload\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n return this.handleFormSubmit(request, context, h)\n }\n }\n\n async handleFormSubmit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const { model } = this\n const { params } = request\n\n const cacheService = getCacheService(request.server)\n\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n const formMetadata = await getFormMetadata(params.slug)\n const { notificationEmail } = formMetadata\n const { isPreview } = checkFormStatus(request.params)\n\n checkEmailAddressForLiveFormSubmission(notificationEmail, isPreview)\n\n if (notificationEmail) {\n const translator = this.getTranslator(request)\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n try {\n await submitForm(\n context,\n formMetadata,\n request,\n viewModel,\n model,\n notificationEmail,\n translator\n )\n } catch (error) {\n return this.handleSubmissionError(error, request, h)\n }\n }\n\n await cacheService.setConfirmationState(request, {\n confirmed: true,\n formId: context.state.formId,\n referenceNumber: context.referenceNumber\n } as FormConfirmationState)\n\n await cacheService.clearState(request)\n\n return this.proceed(request, h, this.getStatusPath())\n }\n\n /**\n * Handles errors during form submission\n */\n private async handleSubmissionError(\n error: unknown,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n if (error instanceof InvalidComponentStateError) {\n return this.handleInvalidComponentStateError(error, request, h)\n }\n\n if (error instanceof PaymentPreAuthError) {\n return this.handlePaymentPreAuthError(error, request, h)\n }\n\n if (error instanceof PaymentSubmissionError) {\n return this.handlePaymentSubmissionError(error, request, h)\n }\n\n throw error\n }\n\n /**\n * Handles InvalidComponentStateError during submission\n */\n private async handleInvalidComponentStateError(\n error: InvalidComponentStateError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n const govukError = createError(error.component.name, error.userMessage)\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n return this.proceed(request, h, error.component.page?.path)\n }\n\n /**\n * Handles PaymentPreAuthError during submission\n */\n private async handlePaymentPreAuthError(\n error: PaymentPreAuthError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n if (error.shouldResetState) {\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n if (error.errorType === PaymentErrorTypes.PaymentExpired) {\n request.yar.flash(PAYMENT_EXPIRED_NOTIFICATION, true, true)\n return this.proceed(request, h, error.component.page?.path)\n }\n }\n\n // Payment page is skipped in the page walk, so proceed() would redirect\n // to an earlier page. For PaymentIncomplete, redirect directly to the\n // payment page using its href.\n if (\n error.errorType === PaymentErrorTypes.PaymentIncomplete &&\n error.component.page\n ) {\n return h\n .redirect(error.component.page.getHref(error.component.page.path))\n .code(StatusCodes.SEE_OTHER)\n }\n\n const govukError = createError(error.component.name, error.userMessage)\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n const redirectPath = error.shouldResetState\n ? error.component.page?.path\n : undefined\n\n return this.proceed(request, h, redirectPath)\n }\n\n /**\n * Handles PaymentSubmissionError during submission\n */\n private handlePaymentSubmissionError(\n error: PaymentSubmissionError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const { t } = this.getTranslator(request)\n\n const helpUrl = error.helpLink ?? DEFAULT_PAYMENT_HELP_URL\n const contactUsLink = `<a href=\"${helpUrl}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"govuk-link\">${t('pages.summary.contactUsLinkText')}</a>`\n const helpLinkHtml = t('pages.summary.submissionFailedContactSuffix', {\n contactUsLink\n })\n\n const govukError = createError(\n 'submission',\n `${t('pages.summary.submissionFailed')}${helpLinkHtml}.`\n )\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n return this.proceed(request, h)\n }\n\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n ext: {\n onPreHandler: {\n method(request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n\nexport async function submitForm(\n context: FormContext,\n formMetadata: FormMetadata,\n request: FormRequestPayload,\n summaryViewModel: SummaryViewModel,\n model: FormModel,\n emailAddress: string,\n translator: Translator\n) {\n await finaliseComponents(request, formMetadata, context, model)\n\n const paymentWasCaptured = hasPaymentBeenCaptured(context, model)\n\n const formStatus = checkFormStatus(request.params)\n const logTags = ['submit', 'submissionApi']\n\n request.logger.info(logTags, 'Preparing email', formStatus)\n\n const items = getFormSubmissionData(\n summaryViewModel.context,\n summaryViewModel.details,\n translator,\n model\n )\n\n try {\n request.logger.info(logTags, 'Submitting data')\n const submitResponse = await submitData(\n model,\n items,\n emailAddress,\n request.yar.id,\n translator,\n summaryViewModel.context.referenceNumber\n )\n\n if (submitResponse === undefined) {\n throw Boom.badRequest('Unexpected empty response from submit api')\n }\n\n await model.services.outputService.submit(\n context,\n request,\n model,\n emailAddress,\n items,\n submitResponse,\n formMetadata\n )\n } catch (err) {\n if (paymentWasCaptured) {\n throw new PaymentSubmissionError(\n context.referenceNumber,\n formMetadata.contact?.online?.url\n )\n }\n throw err\n }\n}\n\n/**\n * Checks if any payment component has been captured\n */\nfunction hasPaymentBeenCaptured(\n context: FormContext,\n model: FormModel\n): boolean {\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n const paymentState = field.getPaymentStateFromState(context.state)\n if (paymentState?.capture?.status === 'success') {\n return true\n }\n }\n }\n }\n return false\n}\n\n/**\n * Finalises any components that need post-processing before form submission. Candidates usually involve\n * those that have external state.\n * Examples include:\n * - file uploads which are 'persisted' before submission\n * - payments which are 'captured' before submission\n */\nasync function finaliseComponents(\n request: FormRequestPayload,\n metadata: FormMetadata,\n context: FormContext,\n model: FormModel\n) {\n // Get fields from relevant pages (normal components)\n // plus PaymentField from all pages (payment page is skipped in the page walk)\n const allFields = new Set([\n ...context.relevantPages.flatMap((page) => page.collection.fields),\n ...model.pages\n .flatMap((page) => page.collection.fields)\n .filter((field) => field instanceof PaymentField)\n ])\n\n for (const component of allFields) {\n await component.onSubmit(request, metadata, context)\n }\n}\n\nfunction submitData(\n model: FormModel,\n items: DetailItem[],\n retrievalKey: string,\n sessionId: string,\n translator: Translator,\n referenceNumber: string\n) {\n const { formSubmissionService } = model.services\n const { submit } = formSubmissionService\n\n const payload: SubmitPayload = {\n sessionId,\n retrievalKey,\n referenceNumber,\n main: buildMainRecords(items, translator),\n repeaters: buildRepeaterRecords(items, translator)\n }\n return submit(payload)\n}\n\nexport function getFormSubmissionData(\n context: FormContext,\n details: Detail[],\n translator: Translator,\n model: FormModel\n) {\n const items = context.relevantPages\n .map(({ href }) =>\n details.flatMap(({ items }) =>\n items.filter(({ page }) => page.href === href)\n )\n )\n .flat()\n\n const paymentItems = getPaymentFieldItems(context, translator, model)\n\n return [...items, ...paymentItems]\n}\n\n/**\n * Gets DetailItems for PaymentField components\n * PaymentField is excluded from summaryDetails for UI but needs to be in submission data\n */\nfunction getPaymentFieldItems(\n context: FormContext,\n translator: Translator,\n model: FormModel\n): DetailItemField[] {\n const items: DetailItemField[] = []\n\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n items.push({\n name: field.name,\n page,\n title: field.title,\n label: field.summaryLabel,\n field,\n state: context.state,\n href: page.href,\n value: field.getDisplayStringFromState(context.state, translator)\n })\n }\n }\n }\n\n return items\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"SummaryPageController.js","names":["hasComponentsEvenIfNoNext","Boom","StatusCodes","COMPONENT_STATE_ERROR","PAYMENT_EXPIRED_NOTIFICATION","ComponentCollection","PaymentField","checkEmailAddressForLiveFormSubmission","checkFormStatus","createError","getCacheService","SummaryViewModel","QuestionPageController","InvalidComponentStateError","PaymentErrorTypes","PaymentPreAuthError","PaymentSubmissionError","buildMainRecords","buildRepeaterRecords","DEFAULT_PAYMENT_HELP_URL","formatCurrency","formatPaymentDate","FormAction","SummaryPageController","allowSaveAndExit","findPaymentField","model","pages","flatMap","page","collection","fields","find","field","constructor","pageDef","viewName","components","getSummaryViewModel","request","context","translator","t","viewModel","payload","errors","state","paymentField","resolvedAmount","resolveAmount","options","paymentState","getPaymentStateFromState","amount","paymentDetails","buildPaymentDetails","paymentRequired","preAuth","status","paymentPreAuthorized","getViewModel","backLink","getBackLink","feedbackLink","phaseTag","shouldShowSaveAndExit","server","rows","key","text","value","description","reference","createdAt","push","language","title","summaryList","makeGetRouteHandler","h","getTranslator","query","paymentComplete","handleFormSubmit","reconcilePaymentState","hasMissingNotificationEmail","view","cacheService","resetComponentStates","name","makePostRouteHandler","action","SaveAndExit","handleSaveAndExit","params","formsService","services","getFormMetadata","formMetadata","slug","notificationEmail","isPreview","submitForm","error","handleSubmissionError","setConfirmationState","confirmed","formId","referenceNumber","clearState","proceed","getStatusPath","handleInvalidComponentStateError","handlePaymentPreAuthError","handlePaymentSubmissionError","govukError","component","userMessage","yar","flash","getStateKeys","path","shouldResetState","errorType","PaymentExpired","PaymentIncomplete","redirect","getHref","code","SEE_OTHER","redirectPath","undefined","helpUrl","helpLink","contactUsLink","helpLinkHtml","postRouteOptions","ext","onPreHandler","method","continue","summaryViewModel","emailAddress","finaliseComponents","paymentWasCaptured","hasPaymentBeenCaptured","formStatus","logTags","logger","info","items","getFormSubmissionData","details","submitResponse","submitData","id","badRequest","outputService","submit","err","contact","online","url","capture","metadata","allFields","Set","relevantPages","filter","onSubmit","retrievalKey","sessionId","formSubmissionService","main","repeaters","def","translations","cy","map","href","flat","paymentItems","getPaymentFieldItems","label","summaryLabel","getDisplayStringFromState"],"sources":["../../../../../src/server/plugins/engine/pageControllers/SummaryPageController.ts"],"sourcesContent":["import {\n hasComponentsEvenIfNoNext,\n type FormMetadata,\n type Page,\n type SubmitPayload\n} from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type RouteOptions } from '@hapi/hapi'\nimport { StatusCodes } from 'http-status-codes'\n\nimport {\n COMPONENT_STATE_ERROR,\n PAYMENT_EXPIRED_NOTIFICATION\n} from '~/src/server/constants.js'\nimport { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'\nimport { PaymentField } from '~/src/server/plugins/engine/components/PaymentField.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n createError,\n getCacheService\n} from '~/src/server/plugins/engine/helpers.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport {\n SummaryViewModel,\n type FormModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport {\n type Detail,\n type DetailItem,\n type DetailItemField\n} from '~/src/server/plugins/engine/models/types.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n InvalidComponentStateError,\n PaymentErrorTypes,\n PaymentPreAuthError,\n PaymentSubmissionError\n} from '~/src/server/plugins/engine/pageControllers/errors.js'\nimport {\n buildMainRecords,\n buildRepeaterRecords\n} from '~/src/server/plugins/engine/pageControllers/helpers/submission.js'\nimport {\n type FormConfirmationState,\n type FormContext,\n type FormContextRequest\n} from '~/src/server/plugins/engine/types.js'\nimport {\n DEFAULT_PAYMENT_HELP_URL,\n formatCurrency,\n formatPaymentDate\n} from '~/src/server/plugins/payment/helper.js'\nimport {\n FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport class SummaryPageController extends QuestionPageController {\n declare pageDef: Page\n allowSaveAndExit = true\n\n /**\n * The controller which is used when Page[\"controller\"] is defined as \"./pages/summary.js\"\n */\n\n /**\n * Finds the PaymentField component across all pages in the model.\n * Payment pages are skipped in the normal page walk\n */\n private findPaymentField(): PaymentField | undefined {\n return this.model.pages\n .flatMap((page) => page.collection.fields)\n .find((field): field is PaymentField => field instanceof PaymentField)\n }\n\n constructor(model: FormModel, pageDef: Page) {\n super(model, pageDef)\n this.viewName = 'summary'\n\n // Components collection\n this.collection = new ComponentCollection(\n hasComponentsEvenIfNoNext(pageDef) ? pageDef.components : [],\n { model, page: this }\n )\n }\n\n getSummaryViewModel(\n request: FormContextRequest,\n context: FormContext,\n translator: Translator\n ): SummaryViewModel {\n const { t } = translator\n\n const viewModel = new SummaryViewModel(request, this, context, translator)\n\n const { payload, errors, state } = context\n\n const paymentField = this.findPaymentField()\n\n if (paymentField) {\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n state\n )\n const paymentState = paymentField.getPaymentStateFromState(state)\n\n if (paymentState?.amount === resolvedAmount) {\n viewModel.paymentState = paymentState\n viewModel.paymentDetails = this.buildPaymentDetails(\n paymentField,\n paymentState,\n translator\n )\n }\n\n if (resolvedAmount > 0) {\n viewModel.paymentRequired = true\n }\n if (\n paymentState &&\n paymentState.preAuth?.status === 'success' &&\n paymentState.amount === resolvedAmount\n ) {\n viewModel.paymentPreAuthorized = true\n }\n }\n\n const components = this.collection.getViewModel({\n payload,\n errors,\n translator\n })\n\n viewModel.backLink = this.getBackLink(request, context, t)\n viewModel.feedbackLink = this.feedbackLink\n viewModel.phaseTag = this.phaseTag\n viewModel.components = components\n viewModel.allowSaveAndExit = this.shouldShowSaveAndExit(request.server)\n viewModel.errors = errors\n\n return viewModel\n }\n\n private buildPaymentDetails(\n paymentField: PaymentField,\n paymentState: NonNullable<\n ReturnType<PaymentField['getPaymentStateFromState']>\n >,\n translator: Translator\n ) {\n const { t } = translator\n const rows = [\n {\n key: { text: t('pages.summary.paymentFor') },\n value: { text: paymentState.description }\n },\n {\n key: { text: t('pages.summary.totalAmount') },\n value: { text: formatCurrency(paymentState.amount) }\n },\n {\n key: { text: t('pages.summary.reference') },\n value: { text: paymentState.reference }\n }\n ]\n\n if (paymentState.preAuth?.createdAt) {\n rows.push({\n key: { text: t('pages.summary.dateOfPayment') },\n value: {\n text: formatPaymentDate(\n paymentState.preAuth.createdAt,\n translator.language\n )\n }\n })\n }\n\n return {\n title: { text: t('pages.summary.paymentDetailsTitle') },\n summaryList: { rows }\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a GET request at `/{id}/{path*}`,\n */\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { viewName } = this\n\n const translator = this.getTranslator(request)\n const { t } = translator\n\n // After GOV.UK Pay callback, auto-submit the form instead of\n // showing CYA again. The payment is already pre-authorized.\n if (request.query.paymentComplete === 'true') {\n return this.handleFormSubmit(\n request as unknown as FormRequestPayload,\n context,\n h\n )\n }\n\n await this.reconcilePaymentState(request, context)\n\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n viewModel.t = t\n return h.view(viewName, viewModel)\n }\n }\n\n /**\n * Checks if the resolved payment amount has changed since pre-auth\n * and invalidates stale payment state if so.\n */\n private async reconcilePaymentState(\n request: FormRequest,\n context: FormContext\n ) {\n const paymentField = this.findPaymentField()\n\n if (!paymentField) {\n return\n }\n\n const resolvedAmount = PaymentField.resolveAmount(\n paymentField.options,\n this.model,\n context.state\n )\n const paymentState = paymentField.getPaymentStateFromState(context.state)\n\n if (paymentState && paymentState.amount !== resolvedAmount) {\n const cacheService = getCacheService(request.server)\n await cacheService.resetComponentStates(request, [paymentField.name])\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a POST request at `/{id}/{path*}`.\n * If a form is incomplete, a user will be redirected to the start page.\n */\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) => {\n const { action } = request.payload\n if (action === FormAction.SaveAndExit) {\n return this.handleSaveAndExit(request, context, h)\n }\n\n return this.handleFormSubmit(request, context, h)\n }\n }\n\n async handleFormSubmit(\n request: FormRequestPayload,\n context: FormContext,\n h: FormResponseToolkit\n ) {\n const { model } = this\n const { params } = request\n\n const cacheService = getCacheService(request.server)\n\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n const formMetadata = await getFormMetadata(params.slug)\n const { notificationEmail } = formMetadata\n const { isPreview } = checkFormStatus(request.params)\n\n checkEmailAddressForLiveFormSubmission(notificationEmail, isPreview)\n\n if (notificationEmail) {\n const translator = this.getTranslator(request)\n const viewModel = this.getSummaryViewModel(request, context, translator)\n\n try {\n await submitForm(\n context,\n formMetadata,\n request,\n viewModel,\n model,\n notificationEmail,\n translator\n )\n } catch (error) {\n return this.handleSubmissionError(error, request, h)\n }\n }\n\n await cacheService.setConfirmationState(request, {\n confirmed: true,\n formId: context.state.formId,\n referenceNumber: context.referenceNumber\n } as FormConfirmationState)\n\n await cacheService.clearState(request)\n\n return this.proceed(request, h, this.getStatusPath())\n }\n\n /**\n * Handles errors during form submission\n */\n private async handleSubmissionError(\n error: unknown,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n if (error instanceof InvalidComponentStateError) {\n return this.handleInvalidComponentStateError(error, request, h)\n }\n\n if (error instanceof PaymentPreAuthError) {\n return this.handlePaymentPreAuthError(error, request, h)\n }\n\n if (error instanceof PaymentSubmissionError) {\n return this.handlePaymentSubmissionError(error, request, h)\n }\n\n throw error\n }\n\n /**\n * Handles InvalidComponentStateError during submission\n */\n private async handleInvalidComponentStateError(\n error: InvalidComponentStateError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n const govukError = createError(error.component.name, error.userMessage)\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n return this.proceed(request, h, error.component.page?.path)\n }\n\n /**\n * Handles PaymentPreAuthError during submission\n */\n private async handlePaymentPreAuthError(\n error: PaymentPreAuthError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const cacheService = getCacheService(request.server)\n\n if (error.shouldResetState) {\n await cacheService.resetComponentStates(request, error.getStateKeys())\n\n if (error.errorType === PaymentErrorTypes.PaymentExpired) {\n request.yar.flash(PAYMENT_EXPIRED_NOTIFICATION, true, true)\n return this.proceed(request, h, error.component.page?.path)\n }\n }\n\n // Payment page is skipped in the page walk, so proceed() would redirect\n // to an earlier page. For PaymentIncomplete, redirect directly to the\n // payment page using its href.\n if (\n error.errorType === PaymentErrorTypes.PaymentIncomplete &&\n error.component.page\n ) {\n return h\n .redirect(error.component.page.getHref(error.component.page.path))\n .code(StatusCodes.SEE_OTHER)\n }\n\n const govukError = createError(error.component.name, error.userMessage)\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n const redirectPath = error.shouldResetState\n ? error.component.page?.path\n : undefined\n\n return this.proceed(request, h, redirectPath)\n }\n\n /**\n * Handles PaymentSubmissionError during submission\n */\n private handlePaymentSubmissionError(\n error: PaymentSubmissionError,\n request: FormRequestPayload,\n h: FormResponseToolkit\n ) {\n const { t } = this.getTranslator(request)\n\n const helpUrl = error.helpLink ?? DEFAULT_PAYMENT_HELP_URL\n const contactUsLink = `<a href=\"${helpUrl}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"govuk-link\">${t('pages.summary.contactUsLinkText')}</a>`\n const helpLinkHtml = t('pages.summary.submissionFailedContactSuffix', {\n contactUsLink\n })\n\n const govukError = createError(\n 'submission',\n `${t('pages.summary.submissionFailed')}${helpLinkHtml}.`\n )\n\n request.yar.flash(COMPONENT_STATE_ERROR, govukError, true)\n\n return this.proceed(request, h)\n }\n\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n ext: {\n onPreHandler: {\n method(request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n\nexport async function submitForm(\n context: FormContext,\n formMetadata: FormMetadata,\n request: FormRequestPayload,\n summaryViewModel: SummaryViewModel,\n model: FormModel,\n emailAddress: string,\n translator: Translator\n) {\n await finaliseComponents(request, formMetadata, context, model)\n\n const paymentWasCaptured = hasPaymentBeenCaptured(context, model)\n\n const formStatus = checkFormStatus(request.params)\n const logTags = ['submit', 'submissionApi']\n\n request.logger.info(logTags, 'Preparing email', formStatus)\n\n const items = getFormSubmissionData(\n summaryViewModel.context,\n summaryViewModel.details,\n translator,\n model\n )\n\n try {\n request.logger.info(logTags, 'Submitting data')\n const submitResponse = await submitData(\n model,\n items,\n emailAddress,\n request.yar.id,\n translator,\n summaryViewModel.context.referenceNumber\n )\n\n if (submitResponse === undefined) {\n throw Boom.badRequest('Unexpected empty response from submit api')\n }\n\n await model.services.outputService.submit(\n context,\n request,\n model,\n emailAddress,\n items,\n submitResponse,\n formMetadata\n )\n } catch (err) {\n if (paymentWasCaptured) {\n throw new PaymentSubmissionError(\n context.referenceNumber,\n formMetadata.contact?.online?.url\n )\n }\n throw err\n }\n}\n\n/**\n * Checks if any payment component has been captured\n */\nfunction hasPaymentBeenCaptured(\n context: FormContext,\n model: FormModel\n): boolean {\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n const paymentState = field.getPaymentStateFromState(context.state)\n if (paymentState?.capture?.status === 'success') {\n return true\n }\n }\n }\n }\n return false\n}\n\n/**\n * Finalises any components that need post-processing before form submission. Candidates usually involve\n * those that have external state.\n * Examples include:\n * - file uploads which are 'persisted' before submission\n * - payments which are 'captured' before submission\n */\nasync function finaliseComponents(\n request: FormRequestPayload,\n metadata: FormMetadata,\n context: FormContext,\n model: FormModel\n) {\n // Get fields from relevant pages (normal components)\n // plus PaymentField from all pages (payment page is skipped in the page walk)\n const allFields = new Set([\n ...context.relevantPages.flatMap((page) => page.collection.fields),\n ...model.pages\n .flatMap((page) => page.collection.fields)\n .filter((field) => field instanceof PaymentField)\n ])\n\n for (const component of allFields) {\n await component.onSubmit(request, metadata, context)\n }\n}\n\nfunction submitData(\n model: FormModel,\n items: DetailItem[],\n retrievalKey: string,\n sessionId: string,\n translator: Translator,\n referenceNumber: string\n) {\n const { formSubmissionService } = model.services\n const { submit } = formSubmissionService\n\n const payload: SubmitPayload = {\n sessionId,\n retrievalKey,\n referenceNumber,\n main: buildMainRecords(items, translator),\n repeaters: buildRepeaterRecords(items, translator),\n // Only populate the language property if the form is multi-language enabled\n // @ts-expect-error - dynamic language property\n language: model.def.metadata?.translations?.cy\n ? translator.language\n : undefined\n }\n return submit(payload)\n}\n\nexport function getFormSubmissionData(\n context: FormContext,\n details: Detail[],\n translator: Translator,\n model: FormModel\n) {\n const items = context.relevantPages\n .map(({ href }) =>\n details.flatMap(({ items }) =>\n items.filter(({ page }) => page.href === href)\n )\n )\n .flat()\n\n const paymentItems = getPaymentFieldItems(context, translator, model)\n\n return [...items, ...paymentItems]\n}\n\n/**\n * Gets DetailItems for PaymentField components\n * PaymentField is excluded from summaryDetails for UI but needs to be in submission data\n */\nfunction getPaymentFieldItems(\n context: FormContext,\n translator: Translator,\n model: FormModel\n): DetailItemField[] {\n const items: DetailItemField[] = []\n\n for (const page of model.pages) {\n for (const field of page.collection.fields) {\n if (field instanceof PaymentField) {\n items.push({\n name: field.name,\n page,\n title: field.title,\n label: field.summaryLabel,\n field,\n state: context.state,\n href: page.href,\n value: field.getDisplayStringFromState(context.state, translator)\n })\n }\n }\n }\n\n return items\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,4 +1,5 @@
1
1
  import { ControllerType, controllerNameFromPath } from '@defra/forms-model';
2
+ import { UnknownPageControllerError } from "../../errors.js";
2
3
  import * as PageControllers from "../index.js";
3
4
  /**
4
5
  * Creates page instance for each {@link Page} type
@@ -44,7 +45,7 @@ export function createPage(model, pageDef) {
44
45
  }
45
46
  }
46
47
  if (typeof controller === 'undefined') {
47
- throw new Error(`Page controller ${pageDef.controller} does not exist`);
48
+ throw new UnknownPageControllerError(pageDef.controller);
48
49
  }
49
50
  return controller;
50
51
  }