@defra/forms-engine-plugin 0.0.4 → 0.0.5

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 (224) hide show
  1. package/package.json +3 -2
  2. package/src/client/javascripts/application.js +87 -0
  3. package/src/client/javascripts/file-upload.js +386 -0
  4. package/src/client/stylesheets/_code.scss +33 -0
  5. package/src/client/stylesheets/_govuk-frontend.scss +4 -0
  6. package/src/client/stylesheets/_prose.scss +56 -0
  7. package/src/client/stylesheets/_service-banner.scss +24 -0
  8. package/src/client/stylesheets/_summary-list.scss +28 -0
  9. package/src/client/stylesheets/_tag-env.scss +24 -0
  10. package/src/client/stylesheets/application.scss +14 -0
  11. package/src/common/cookies.js +58 -0
  12. package/src/common/cookies.test.js +23 -0
  13. package/src/common/types.js +5 -0
  14. package/src/config/index.ts +271 -0
  15. package/src/index.ts +31 -0
  16. package/src/server/common/helpers/logging/logger-options.test.ts +50 -0
  17. package/src/server/common/helpers/logging/logger-options.ts +46 -0
  18. package/src/server/common/helpers/logging/logger.ts +7 -0
  19. package/src/server/common/helpers/logging/request-logger.ts +9 -0
  20. package/src/server/common/helpers/logging/request-tracing.js +10 -0
  21. package/src/server/common/helpers/redis-client.js +70 -0
  22. package/src/server/constants.js +1 -0
  23. package/src/server/forms/README.md +10 -0
  24. package/src/server/forms/components.json +1015 -0
  25. package/src/server/forms/report-a-terrorist.json +270 -0
  26. package/src/server/forms/runner-components-test.json +365 -0
  27. package/src/server/forms/test.json +581 -0
  28. package/src/server/index.test.ts +582 -0
  29. package/src/server/index.ts +140 -0
  30. package/src/server/plugins/blankie.test.ts +73 -0
  31. package/src/server/plugins/blankie.ts +48 -0
  32. package/src/server/plugins/crumb.ts +20 -0
  33. package/src/server/plugins/engine/README.md +87 -0
  34. package/src/server/plugins/engine/components/AutocompleteField.test.ts +294 -0
  35. package/src/server/plugins/engine/components/AutocompleteField.ts +49 -0
  36. package/src/server/plugins/engine/components/CheckboxesField.test.ts +379 -0
  37. package/src/server/plugins/engine/components/CheckboxesField.ts +106 -0
  38. package/src/server/plugins/engine/components/ComponentBase.ts +97 -0
  39. package/src/server/plugins/engine/components/ComponentCollection.ts +278 -0
  40. package/src/server/plugins/engine/components/DatePartsField.test.ts +822 -0
  41. package/src/server/plugins/engine/components/DatePartsField.ts +264 -0
  42. package/src/server/plugins/engine/components/Details.test.ts +49 -0
  43. package/src/server/plugins/engine/components/Details.ts +30 -0
  44. package/src/server/plugins/engine/components/EmailAddressField.test.ts +395 -0
  45. package/src/server/plugins/engine/components/EmailAddressField.ts +55 -0
  46. package/src/server/plugins/engine/components/FileUploadField.test.ts +778 -0
  47. package/src/server/plugins/engine/components/FileUploadField.ts +262 -0
  48. package/src/server/plugins/engine/components/FormComponent.ts +249 -0
  49. package/src/server/plugins/engine/components/Html.test.ts +48 -0
  50. package/src/server/plugins/engine/components/Html.ts +29 -0
  51. package/src/server/plugins/engine/components/InsetText.test.ts +48 -0
  52. package/src/server/plugins/engine/components/InsetText.ts +27 -0
  53. package/src/server/plugins/engine/components/List.test.ts +76 -0
  54. package/src/server/plugins/engine/components/List.ts +72 -0
  55. package/src/server/plugins/engine/components/ListFormComponent.ts +140 -0
  56. package/src/server/plugins/engine/components/MonthYearField.test.ts +567 -0
  57. package/src/server/plugins/engine/components/MonthYearField.ts +222 -0
  58. package/src/server/plugins/engine/components/MultilineTextField.test.ts +558 -0
  59. package/src/server/plugins/engine/components/MultilineTextField.ts +138 -0
  60. package/src/server/plugins/engine/components/NumberField.test.ts +701 -0
  61. package/src/server/plugins/engine/components/NumberField.ts +163 -0
  62. package/src/server/plugins/engine/components/RadiosField.test.ts +288 -0
  63. package/src/server/plugins/engine/components/RadiosField.ts +24 -0
  64. package/src/server/plugins/engine/components/SelectField.test.ts +288 -0
  65. package/src/server/plugins/engine/components/SelectField.ts +47 -0
  66. package/src/server/plugins/engine/components/SelectionControlField.ts +43 -0
  67. package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +356 -0
  68. package/src/server/plugins/engine/components/TelephoneNumberField.ts +67 -0
  69. package/src/server/plugins/engine/components/TextField.test.ts +489 -0
  70. package/src/server/plugins/engine/components/TextField.ts +96 -0
  71. package/src/server/plugins/engine/components/UkAddressField.test.ts +623 -0
  72. package/src/server/plugins/engine/components/UkAddressField.ts +172 -0
  73. package/src/server/plugins/engine/components/YesNoField.test.ts +248 -0
  74. package/src/server/plugins/engine/components/YesNoField.ts +31 -0
  75. package/src/server/plugins/engine/components/constants.ts +1 -0
  76. package/src/server/plugins/engine/components/helpers.ts +330 -0
  77. package/src/server/plugins/engine/components/index.ts +24 -0
  78. package/src/server/plugins/engine/components/types.ts +117 -0
  79. package/src/server/plugins/engine/configureEnginePlugin.ts +47 -0
  80. package/src/server/plugins/engine/helpers.test.ts +791 -0
  81. package/src/server/plugins/engine/helpers.ts +379 -0
  82. package/src/server/plugins/engine/index.ts +7 -0
  83. package/src/server/plugins/engine/models/FormModel.test.ts +42 -0
  84. package/src/server/plugins/engine/models/FormModel.ts +443 -0
  85. package/src/server/plugins/engine/models/RepeatingSummaryViewModel.ts +0 -0
  86. package/src/server/plugins/engine/models/Section.ts +0 -0
  87. package/src/server/plugins/engine/models/SummaryViewModel.test.ts +209 -0
  88. package/src/server/plugins/engine/models/SummaryViewModel.ts +220 -0
  89. package/src/server/plugins/engine/models/index.ts +2 -0
  90. package/src/server/plugins/engine/models/types.ts +114 -0
  91. package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +143 -0
  92. package/src/server/plugins/engine/outputFormatters/human/v1.ts +73 -0
  93. package/src/server/plugins/engine/outputFormatters/index.test.ts +17 -0
  94. package/src/server/plugins/engine/outputFormatters/index.ts +44 -0
  95. package/src/server/plugins/engine/outputFormatters/machine/v1.test.ts +229 -0
  96. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +140 -0
  97. package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +229 -0
  98. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +153 -0
  99. package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +1108 -0
  100. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +446 -0
  101. package/src/server/plugins/engine/pageControllers/PageController.test.ts +205 -0
  102. package/src/server/plugins/engine/pageControllers/PageController.ts +176 -0
  103. package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +1264 -0
  104. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +561 -0
  105. package/src/server/plugins/engine/pageControllers/README.md +28 -0
  106. package/src/server/plugins/engine/pageControllers/RepeatPageController.test.ts +264 -0
  107. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +458 -0
  108. package/src/server/plugins/engine/pageControllers/StartPageController.ts +18 -0
  109. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +50 -0
  110. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +261 -0
  111. package/src/server/plugins/engine/pageControllers/TerminalController.test.ts +28 -0
  112. package/src/server/plugins/engine/pageControllers/TerminalPageController.ts +19 -0
  113. package/src/server/plugins/engine/pageControllers/helpers.test.ts +198 -0
  114. package/src/server/plugins/engine/pageControllers/helpers.ts +101 -0
  115. package/src/server/plugins/engine/pageControllers/index.ts +10 -0
  116. package/src/server/plugins/engine/pageControllers/validationOptions.ts +89 -0
  117. package/src/server/plugins/engine/plugin.ts +673 -0
  118. package/src/server/plugins/engine/services/formSubmissionService.js +46 -0
  119. package/src/server/plugins/engine/services/formsService.js +46 -0
  120. package/src/server/plugins/engine/services/formsService.test.js +90 -0
  121. package/src/server/plugins/engine/services/index.js +3 -0
  122. package/src/server/plugins/engine/services/notifyService.test.ts +132 -0
  123. package/src/server/plugins/engine/services/notifyService.ts +64 -0
  124. package/src/server/plugins/engine/services/uploadService.js +60 -0
  125. package/src/server/plugins/engine/types.ts +315 -0
  126. package/src/server/plugins/engine/views/components/autocompletefield.html +5 -0
  127. package/src/server/plugins/engine/views/components/checkboxesfield.html +5 -0
  128. package/src/server/plugins/engine/views/components/datepartsfield.html +5 -0
  129. package/src/server/plugins/engine/views/components/details.html +6 -0
  130. package/src/server/plugins/engine/views/components/emailaddressfield.html +5 -0
  131. package/src/server/plugins/engine/views/components/fileuploadfield-key.html +8 -0
  132. package/src/server/plugins/engine/views/components/fileuploadfield-value.html +3 -0
  133. package/src/server/plugins/engine/views/components/fileuploadfield.html +24 -0
  134. package/src/server/plugins/engine/views/components/html.html +3 -0
  135. package/src/server/plugins/engine/views/components/insettext.html +7 -0
  136. package/src/server/plugins/engine/views/components/list.html +36 -0
  137. package/src/server/plugins/engine/views/components/monthyearfield.html +5 -0
  138. package/src/server/plugins/engine/views/components/multilinetextfield.html +10 -0
  139. package/src/server/plugins/engine/views/components/numberfield.html +5 -0
  140. package/src/server/plugins/engine/views/components/radiosfield.html +5 -0
  141. package/src/server/plugins/engine/views/components/selectfield.html +5 -0
  142. package/src/server/plugins/engine/views/components/telephonenumberfield.html +5 -0
  143. package/src/server/plugins/engine/views/components/textfield.html +5 -0
  144. package/src/server/plugins/engine/views/components/ukaddressfield.html +25 -0
  145. package/src/server/plugins/engine/views/components/yesnofield.html +5 -0
  146. package/src/server/plugins/engine/views/file-upload.html +45 -0
  147. package/src/server/plugins/engine/views/index.html +39 -0
  148. package/src/server/plugins/engine/views/item-delete.html +56 -0
  149. package/src/server/plugins/engine/views/partials/components.html +6 -0
  150. package/src/server/plugins/engine/views/partials/conditional-components.html +3 -0
  151. package/src/server/plugins/engine/views/partials/debug.html +44 -0
  152. package/src/server/plugins/engine/views/partials/form.html +15 -0
  153. package/src/server/plugins/engine/views/partials/heading.html +16 -0
  154. package/src/server/plugins/engine/views/partials/preview-banner.html +32 -0
  155. package/src/server/plugins/engine/views/partials/preview-banner.test.js +122 -0
  156. package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +10 -0
  157. package/src/server/plugins/engine/views/repeat-list-summary.html +53 -0
  158. package/src/server/plugins/errorPages.ts +58 -0
  159. package/src/server/plugins/nunjucks/context.js +88 -0
  160. package/src/server/plugins/nunjucks/context.test.js +142 -0
  161. package/src/server/plugins/nunjucks/enviroment.test.js +201 -0
  162. package/src/server/plugins/nunjucks/environment.js +116 -0
  163. package/src/server/plugins/nunjucks/filters/answer.js +27 -0
  164. package/src/server/plugins/nunjucks/filters/answer.test.js +89 -0
  165. package/src/server/plugins/nunjucks/filters/evaluate.js +21 -0
  166. package/src/server/plugins/nunjucks/filters/field.js +28 -0
  167. package/src/server/plugins/nunjucks/filters/field.test.js +75 -0
  168. package/src/server/plugins/nunjucks/filters/highlight.js +11 -0
  169. package/src/server/plugins/nunjucks/filters/href.js +30 -0
  170. package/src/server/plugins/nunjucks/filters/href.test.js +80 -0
  171. package/src/server/plugins/nunjucks/filters/index.js +8 -0
  172. package/src/server/plugins/nunjucks/filters/inspect.js +15 -0
  173. package/src/server/plugins/nunjucks/filters/page.js +24 -0
  174. package/src/server/plugins/nunjucks/filters/page.test.js +65 -0
  175. package/src/server/plugins/nunjucks/index.js +3 -0
  176. package/src/server/plugins/nunjucks/plugin.js +40 -0
  177. package/src/server/plugins/nunjucks/render.js +42 -0
  178. package/src/server/plugins/nunjucks/types.js +40 -0
  179. package/src/server/plugins/pulse.ts +11 -0
  180. package/src/server/plugins/router.ts +201 -0
  181. package/src/server/plugins/session.ts +28 -0
  182. package/src/server/routes/health.js +13 -0
  183. package/src/server/routes/health.test.js +35 -0
  184. package/src/server/routes/index.test.ts +125 -0
  185. package/src/server/routes/index.ts +2 -0
  186. package/src/server/routes/public.ts +47 -0
  187. package/src/server/routes/types.ts +48 -0
  188. package/src/server/schemas/index.ts +34 -0
  189. package/src/server/secure-context.js +43 -0
  190. package/src/server/services/cacheService.test.ts +276 -0
  191. package/src/server/services/cacheService.ts +131 -0
  192. package/src/server/services/httpService.test.js +491 -0
  193. package/src/server/services/httpService.ts +50 -0
  194. package/src/server/services/index.ts +1 -0
  195. package/src/server/types.ts +54 -0
  196. package/src/server/utils/notify.test.ts +37 -0
  197. package/src/server/utils/notify.ts +50 -0
  198. package/src/server/utils/secure-context/get-trust-store-certs.js +11 -0
  199. package/src/server/utils/secure-context/get-trust-store-certs.test.js +19 -0
  200. package/src/server/utils/utils.js +24 -0
  201. package/src/server/utils/utils.test.js +54 -0
  202. package/src/server/views/404.html +16 -0
  203. package/src/server/views/500.html +19 -0
  204. package/src/server/views/components/debug/macro.njk +3 -0
  205. package/src/server/views/components/debug/template.njk +13 -0
  206. package/src/server/views/components/service-banner/macro.njk +3 -0
  207. package/src/server/views/components/service-banner/template.njk +20 -0
  208. package/src/server/views/components/service-banner/template.test.js +43 -0
  209. package/src/server/views/components/tag-env/macro.njk +3 -0
  210. package/src/server/views/components/tag-env/template.njk +30 -0
  211. package/src/server/views/components/tag-env/template.test.js +66 -0
  212. package/src/server/views/confirmation.html +19 -0
  213. package/src/server/views/help/accessibility-statement.html +58 -0
  214. package/src/server/views/help/cookie-preferences.html +57 -0
  215. package/src/server/views/help/cookies.html +71 -0
  216. package/src/server/views/help/get-support.html +37 -0
  217. package/src/server/views/help/privacy-notice.html +68 -0
  218. package/src/server/views/help/terms-and-conditions.html +83 -0
  219. package/src/server/views/layout.html +199 -0
  220. package/src/server/views/summary.html +50 -0
  221. package/src/typings/hapi/index.d.ts +95 -0
  222. package/src/typings/hapi-tracing/index.d.ts +6 -0
  223. package/src/typings/index.d.ts +3 -0
  224. package/src/typings/joi/index.d.ts +22 -0
@@ -0,0 +1,264 @@
1
+ import { ComponentType, type DatePartsFieldComponent } from '@defra/forms-model'
2
+ import { add, format, isValid, parse, startOfToday, sub } from 'date-fns'
3
+ import {
4
+ type Context,
5
+ type CustomValidator,
6
+ type LanguageMessages,
7
+ type ObjectSchema
8
+ } from 'joi'
9
+
10
+ import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'
11
+ import {
12
+ FormComponent,
13
+ isFormState,
14
+ isFormValue
15
+ } from '~/src/server/plugins/engine/components/FormComponent.js'
16
+ import { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'
17
+ import { type DateInputItem } from '~/src/server/plugins/engine/components/types.js'
18
+ import { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'
19
+ import {
20
+ type FormPayload,
21
+ type FormState,
22
+ type FormStateValue,
23
+ type FormSubmissionError,
24
+ type FormSubmissionState
25
+ } from '~/src/server/plugins/engine/types.js'
26
+
27
+ export class DatePartsField extends FormComponent {
28
+ declare options: DatePartsFieldComponent['options']
29
+ declare formSchema: ObjectSchema<FormPayload>
30
+ declare stateSchema: ObjectSchema<FormState>
31
+ declare collection: ComponentCollection
32
+
33
+ constructor(
34
+ def: DatePartsFieldComponent,
35
+ props: ConstructorParameters<typeof FormComponent>[1]
36
+ ) {
37
+ super(def, props)
38
+
39
+ const { name, options } = def
40
+
41
+ const isRequired = options.required !== false
42
+
43
+ const customValidationMessages: LanguageMessages = {
44
+ 'any.required': messageTemplate.objectMissing,
45
+ 'number.base': messageTemplate.objectMissing,
46
+ 'number.precision': messageTemplate.dateFormat,
47
+ 'number.integer': messageTemplate.dateFormat,
48
+ 'number.unsafe': messageTemplate.dateFormat,
49
+ 'number.min': messageTemplate.dateFormat,
50
+ 'number.max': messageTemplate.dateFormat
51
+ }
52
+
53
+ this.collection = new ComponentCollection(
54
+ [
55
+ {
56
+ type: ComponentType.NumberField,
57
+ name: `${name}__day`,
58
+ title: 'Day',
59
+ schema: { min: 1, max: 31, precision: 0 },
60
+ options: {
61
+ required: isRequired,
62
+ optionalText: true,
63
+ classes: 'govuk-input--width-2',
64
+ customValidationMessages
65
+ }
66
+ },
67
+ {
68
+ type: ComponentType.NumberField,
69
+ name: `${name}__month`,
70
+ title: 'Month',
71
+ schema: { min: 1, max: 12, precision: 0 },
72
+ options: {
73
+ required: isRequired,
74
+ optionalText: true,
75
+ classes: 'govuk-input--width-2',
76
+ customValidationMessages
77
+ }
78
+ },
79
+ {
80
+ type: ComponentType.NumberField,
81
+ name: `${name}__year`,
82
+ title: 'Year',
83
+ schema: { min: 1000, max: 3000, precision: 0 },
84
+ options: {
85
+ required: isRequired,
86
+ optionalText: true,
87
+ classes: 'govuk-input--width-4',
88
+ customValidationMessages
89
+ }
90
+ }
91
+ ],
92
+ { ...props, parent: this },
93
+ {
94
+ custom: getValidatorDate(this),
95
+ peers: [`${name}__day`, `${name}__month`, `${name}__year`]
96
+ }
97
+ )
98
+
99
+ this.options = options
100
+ this.formSchema = this.collection.formSchema
101
+ this.stateSchema = this.collection.stateSchema
102
+ }
103
+
104
+ getFormValueFromState(state: FormSubmissionState) {
105
+ const value = super.getFormValueFromState(state)
106
+ return this.isState(value) ? value : undefined
107
+ }
108
+
109
+ getDisplayStringFromState(state: FormSubmissionState) {
110
+ const value = this.getFormValueFromState(state)
111
+
112
+ if (!value) {
113
+ return ''
114
+ }
115
+
116
+ return format(`${value.year}-${value.month}-${value.day}`, 'd MMMM yyyy')
117
+ }
118
+
119
+ getContextValueFromState(state: FormSubmissionState) {
120
+ const value = this.getFormValueFromState(state)
121
+
122
+ if (
123
+ !value ||
124
+ !isValid(
125
+ parse(
126
+ `${value.year}-${value.month}-${value.day}`,
127
+ 'yyyy-MM-dd',
128
+ new Date()
129
+ )
130
+ )
131
+ ) {
132
+ return null
133
+ }
134
+
135
+ return format(`${value.year}-${value.month}-${value.day}`, 'yyyy-MM-dd')
136
+ }
137
+
138
+ getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
139
+ const { collection, name } = this
140
+
141
+ const viewModel = super.getViewModel(payload, errors)
142
+ let { fieldset, label } = viewModel
143
+
144
+ // Check for component errors only
145
+ const hasError = errors?.some((error) => error.name === name)
146
+
147
+ // Use the component collection to generate the subitems
148
+ const items: DateInputItem[] = collection
149
+ .getViewModel(payload, errors)
150
+ .map(({ model }) => {
151
+ let { label, type, value, classes, errorMessage } = model
152
+
153
+ if (label) {
154
+ label.toString = () => label.text // Date component uses string labels
155
+ }
156
+
157
+ if (hasError || errorMessage) {
158
+ classes = `${classes} govuk-input--error`.trim()
159
+ }
160
+
161
+ // Allow any `toString()`-able value so non-numeric
162
+ // values are shown alongside their error messages
163
+ if (!isFormValue(value)) {
164
+ value = undefined
165
+ }
166
+
167
+ return {
168
+ label,
169
+ id: model.id,
170
+ name: model.name,
171
+ type,
172
+ value,
173
+ classes
174
+ }
175
+ })
176
+
177
+ fieldset ??= {
178
+ legend: {
179
+ text: label.text,
180
+ classes: 'govuk-fieldset__legend--m'
181
+ }
182
+ }
183
+
184
+ return {
185
+ ...viewModel,
186
+ fieldset,
187
+ items
188
+ }
189
+ }
190
+
191
+ isState(value?: FormStateValue | FormState) {
192
+ return DatePartsField.isDateParts(value)
193
+ }
194
+
195
+ static isDateParts(
196
+ value?: FormStateValue | FormState
197
+ ): value is DatePartsState {
198
+ return (
199
+ isFormState(value) &&
200
+ NumberField.isNumber(value.day) &&
201
+ NumberField.isNumber(value.month) &&
202
+ NumberField.isNumber(value.year)
203
+ )
204
+ }
205
+ }
206
+
207
+ export interface DatePartsState extends Record<string, number> {
208
+ day: number
209
+ month: number
210
+ year: number
211
+ }
212
+
213
+ export function getValidatorDate(component: DatePartsField) {
214
+ const validator: CustomValidator = (payload: FormPayload, helpers) => {
215
+ const { collection, name, options } = component
216
+
217
+ const values = component.getFormValueFromState(
218
+ component.getStateFromValidForm(payload)
219
+ )
220
+
221
+ const context: Context = {
222
+ missing: collection.keys,
223
+ key: name
224
+ }
225
+
226
+ if (!component.isState(values)) {
227
+ return options.required !== false
228
+ ? helpers.error('object.required', context)
229
+ : payload
230
+ }
231
+
232
+ const date = parse(
233
+ `${values.year}-${values.month}-${values.day}`,
234
+ 'yyyy-MM-dd',
235
+ new Date()
236
+ )
237
+
238
+ if (!isValid(date)) {
239
+ return helpers.error('date.format', context)
240
+ }
241
+
242
+ // Minimum date from today
243
+ const dateMin = options.maxDaysInPast
244
+ ? sub(startOfToday(), { days: options.maxDaysInPast })
245
+ : undefined
246
+
247
+ // Maximum date from today
248
+ const dateMax = options.maxDaysInFuture
249
+ ? add(startOfToday(), { days: options.maxDaysInFuture })
250
+ : undefined
251
+
252
+ if (dateMin && date < dateMin) {
253
+ return helpers.error('date.min', { ...context, limit: dateMin })
254
+ }
255
+
256
+ if (dateMax && date > dateMax) {
257
+ return helpers.error('date.max', { ...context, limit: dateMax })
258
+ }
259
+
260
+ return payload
261
+ }
262
+
263
+ return validator
264
+ }
@@ -0,0 +1,49 @@
1
+ import { ComponentType, type DetailsComponent } from '@defra/forms-model'
2
+
3
+ import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'
4
+ import { type Guidance } from '~/src/server/plugins/engine/components/helpers.js'
5
+ import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
6
+ import definition from '~/test/form/definitions/basic.js'
7
+
8
+ describe('Details', () => {
9
+ let model: FormModel
10
+
11
+ beforeEach(() => {
12
+ model = new FormModel(definition, {
13
+ basePath: 'test'
14
+ })
15
+ })
16
+
17
+ describe('Defaults', () => {
18
+ let def: DetailsComponent
19
+ let collection: ComponentCollection
20
+ let guidance: Guidance
21
+
22
+ beforeEach(() => {
23
+ def = {
24
+ title: 'Details guidance',
25
+ name: 'myComponent',
26
+ type: ComponentType.Details,
27
+ content: 'Lorem ipsum dolor sit amet',
28
+ options: {}
29
+ } satisfies DetailsComponent
30
+
31
+ collection = new ComponentCollection([def], { model })
32
+ guidance = collection.guidance[0]
33
+ })
34
+
35
+ describe('View model', () => {
36
+ it('sets Nunjucks component defaults', () => {
37
+ const viewModel = guidance.getViewModel()
38
+
39
+ expect(viewModel).toEqual(
40
+ expect.objectContaining({
41
+ attributes: {},
42
+ html: def.content,
43
+ summaryHtml: def.title
44
+ })
45
+ )
46
+ })
47
+ })
48
+ })
49
+ })
@@ -0,0 +1,30 @@
1
+ import { type DetailsComponent } from '@defra/forms-model'
2
+
3
+ import { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'
4
+
5
+ export class Details extends ComponentBase {
6
+ declare options: DetailsComponent['options']
7
+ content: DetailsComponent['content']
8
+
9
+ constructor(
10
+ def: DetailsComponent,
11
+ props: ConstructorParameters<typeof ComponentBase>[1]
12
+ ) {
13
+ super(def, props)
14
+
15
+ const { content, options } = def
16
+
17
+ this.content = content
18
+ this.options = options
19
+ }
20
+
21
+ getViewModel() {
22
+ const { content, title, viewModel } = this
23
+
24
+ return {
25
+ ...viewModel,
26
+ html: content,
27
+ summaryHtml: title
28
+ }
29
+ }
30
+ }