@defra/forms-engine-plugin 2.1.3 → 2.1.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 (52) hide show
  1. package/.server/server/plugins/engine/models/FormModel.js +1 -1
  2. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  3. package/.server/server/plugins/engine/outputFormatters/adapter/v1.d.ts +6 -0
  4. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +23 -0
  5. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -0
  6. package/.server/server/plugins/engine/outputFormatters/human/v1.d.ts +2 -2
  7. package/.server/server/plugins/engine/outputFormatters/human/v1.js +1 -1
  8. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  9. package/.server/server/plugins/engine/outputFormatters/index.d.ts +4 -3
  10. package/.server/server/plugins/engine/outputFormatters/index.js +4 -0
  11. package/.server/server/plugins/engine/outputFormatters/index.js.map +1 -1
  12. package/.server/server/plugins/engine/outputFormatters/machine/v1.d.ts +2 -2
  13. package/.server/server/plugins/engine/outputFormatters/machine/v1.js +1 -1
  14. package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -1
  15. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +4 -1
  16. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  17. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +5 -4
  18. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  19. package/.server/server/plugins/engine/services/localFormsService.d.ts +1 -1
  20. package/.server/server/plugins/engine/services/notifyService.d.ts +7 -2
  21. package/.server/server/plugins/engine/services/notifyService.js +11 -2
  22. package/.server/server/plugins/engine/services/notifyService.js.map +1 -1
  23. package/.server/server/plugins/engine/types/index.d.ts +10 -0
  24. package/.server/server/plugins/engine/types/index.js +4 -0
  25. package/.server/server/plugins/engine/types/index.js.map +1 -0
  26. package/.server/server/plugins/engine/types/schema.d.ts +5 -0
  27. package/.server/server/plugins/engine/types/schema.js +24 -0
  28. package/.server/server/plugins/engine/types/schema.js.map +1 -0
  29. package/.server/server/plugins/engine/types.d.ts +37 -1
  30. package/.server/server/plugins/engine/types.js +4 -0
  31. package/.server/server/plugins/engine/types.js.map +1 -1
  32. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  33. package/.server/server/plugins/nunjucks/filters/page.d.ts +1 -1
  34. package/.server/server/types.d.ts +1 -1
  35. package/.server/server/types.js.map +1 -1
  36. package/package.json +6 -1
  37. package/src/server/plugins/engine/models/FormModel.test.ts +64 -0
  38. package/src/server/plugins/engine/models/FormModel.ts +5 -1
  39. package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +506 -0
  40. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +53 -0
  41. package/src/server/plugins/engine/outputFormatters/human/v1.ts +6 -2
  42. package/src/server/plugins/engine/outputFormatters/index.ts +11 -3
  43. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +6 -2
  44. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +1 -1
  45. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -4
  46. package/src/server/plugins/engine/services/notifyService.test.ts +156 -1
  47. package/src/server/plugins/engine/services/notifyService.ts +24 -3
  48. package/src/server/plugins/engine/types/index.ts +96 -0
  49. package/src/server/plugins/engine/types/schema.test.ts +152 -0
  50. package/src/server/plugins/engine/types/schema.ts +45 -0
  51. package/src/server/plugins/engine/types.ts +51 -1
  52. package/src/server/types.ts +2 -1
@@ -0,0 +1,506 @@
1
+ import { type FormMetadata } from '@defra/forms-model'
2
+
3
+ import { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'
4
+ import { type Field } from '~/src/server/plugins/engine/components/helpers.js'
5
+ import { FormModel } from '~/src/server/plugins/engine/models/index.js'
6
+ import {
7
+ type DetailItem,
8
+ type DetailItemField,
9
+ type DetailItemRepeat
10
+ } from '~/src/server/plugins/engine/models/types.js'
11
+ import { format } from '~/src/server/plugins/engine/outputFormatters/adapter/v1.js'
12
+ import { buildFormContextRequest } from '~/src/server/plugins/engine/pageControllers/__stubs__/request.js'
13
+ import {
14
+ FileStatus,
15
+ FormAdapterSubmissionSchemaVersion,
16
+ UploadStatus,
17
+ type FileState,
18
+ type FormAdapterSubmissionMessagePayload
19
+ } from '~/src/server/plugins/engine/types.js'
20
+ import { FormStatus } from '~/src/server/routes/types.js'
21
+ import definition from '~/test/form/definitions/repeat-mixed.js'
22
+
23
+ const submitResponse = {
24
+ message: 'Submit completed',
25
+ result: {
26
+ files: {
27
+ main: '00000000-0000-0000-0000-000000000000',
28
+ repeaters: {
29
+ pizza: '11111111-1111-1111-1111-111111111111'
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ const model = new FormModel(definition, {
36
+ basePath: 'test'
37
+ })
38
+
39
+ const dummyField: Field = {
40
+ getFormValueFromState: (_) => 'hello world'
41
+ } as Field
42
+
43
+ const itemId1 = 'abc-123'
44
+ const itemId2 = 'xyz-987'
45
+
46
+ const state = {
47
+ $$__referenceNumber: 'foobar',
48
+ orderType: 'delivery',
49
+ pizza: [
50
+ {
51
+ toppings: 'Ham',
52
+ quantity: 2,
53
+ itemId: itemId1
54
+ },
55
+ {
56
+ toppings: 'Pepperoni',
57
+ quantity: 1,
58
+ itemId: itemId2
59
+ }
60
+ ]
61
+ }
62
+
63
+ const pageUrl = new URL('http://example.com/repeat/pizza-order/summary')
64
+
65
+ const request = buildFormContextRequest({
66
+ method: 'get',
67
+ url: pageUrl,
68
+ path: pageUrl.pathname,
69
+ params: {
70
+ path: 'pizza-order',
71
+ slug: 'repeat'
72
+ },
73
+ query: {},
74
+ app: { model }
75
+ })
76
+
77
+ const context = model.getFormContext(request, state)
78
+
79
+ const testDetailItemField: DetailItemField = {
80
+ name: 'exampleField',
81
+ label: 'Example Field',
82
+ href: '/example-field',
83
+ title: 'Example Field Title',
84
+ field: dummyField,
85
+ value: 'Example Value'
86
+ } as DetailItemField
87
+
88
+ const testDetailItemField2: DetailItemField = {
89
+ name: 'exampleField2',
90
+ label: 'Example Field 2',
91
+ href: '/example-field-2',
92
+ title: 'Example Field 2 Title',
93
+ field: dummyField,
94
+ value: 'Example Value 2'
95
+ } as DetailItemField
96
+
97
+ const testDetailItemRepeat: DetailItemRepeat = {
98
+ name: 'exampleRepeat',
99
+ label: 'Example Repeat',
100
+ href: '/example-repeat',
101
+ title: 'Example Repeat Title',
102
+ value: 'Example Repeat Value',
103
+ subItems: [
104
+ [
105
+ {
106
+ name: 'subItem1_1',
107
+ label: 'Sub Item 1 1',
108
+ field: dummyField,
109
+ href: '/sub-item-1-1',
110
+ title: 'Sub Item 1 1 Title',
111
+ value: 'Sub Item 1 1 Value'
112
+ } as DetailItemField,
113
+ {
114
+ name: 'subItem1_2',
115
+ label: 'Sub Item 1 2',
116
+ field: dummyField,
117
+ href: '/sub-item-1-2',
118
+ title: 'Sub Item 1 2 Title',
119
+ value: 'Sub Item 1 2 Value'
120
+ } as DetailItemField
121
+ ],
122
+ [
123
+ {
124
+ name: 'subItem2_1',
125
+ label: 'Sub Item 2 1',
126
+ field: dummyField,
127
+ href: '/sub-item-2-1',
128
+ title: 'Sub Item 2 1 Title',
129
+ value: 'Sub Item 2 1 Value'
130
+ } as DetailItemField
131
+ ]
132
+ ]
133
+ } as DetailItemRepeat
134
+
135
+ const fileState: FileState = {
136
+ uploadId: '123',
137
+ status: {
138
+ form: {
139
+ file: {
140
+ fileId: '123-456-789',
141
+ contentLength: 1,
142
+ filename: 'foobar.txt',
143
+ fileStatus: FileStatus.complete
144
+ }
145
+ },
146
+ uploadStatus: UploadStatus.ready,
147
+ numberOfRejectedFiles: 0,
148
+ metadata: {
149
+ retrievalKey: '123'
150
+ }
151
+ }
152
+ }
153
+
154
+ const fileState2: FileState = {
155
+ uploadId: '456',
156
+ status: {
157
+ form: {
158
+ file: {
159
+ fileId: '456-789-123',
160
+ contentLength: 1,
161
+ filename: 'bazbuzz.txt',
162
+ fileStatus: FileStatus.complete
163
+ }
164
+ },
165
+ uploadStatus: UploadStatus.ready,
166
+ numberOfRejectedFiles: 0,
167
+ metadata: {
168
+ retrievalKey: '456'
169
+ }
170
+ }
171
+ }
172
+
173
+ const testDetailItemFile1: DetailItemField = Object.create(
174
+ FileUploadField.prototype
175
+ )
176
+ Object.assign(testDetailItemFile1, {
177
+ name: 'exampleFile1',
178
+ label: 'Example File Field',
179
+ href: '/example-file',
180
+ title: 'Example File Field Title',
181
+ field: testDetailItemFile1,
182
+ value: 'Example File Value',
183
+ state: {
184
+ exampleFile1: [fileState, fileState2]
185
+ }
186
+ })
187
+
188
+ const items: DetailItem[] = [
189
+ testDetailItemField,
190
+ testDetailItemField2,
191
+ testDetailItemRepeat,
192
+ testDetailItemFile1
193
+ ]
194
+
195
+ describe('Adapter v1 formatter', () => {
196
+ beforeEach(() => {
197
+ jest.clearAllMocks()
198
+ jest.useFakeTimers()
199
+ jest.setSystemTime(new Date('2024-01-15T10:30:00.000Z'))
200
+ })
201
+
202
+ afterEach(() => {
203
+ jest.useRealTimers()
204
+ })
205
+
206
+ it('should return the adapter v1 output with complete formMetadata', () => {
207
+ const formMetadata: FormMetadata = {
208
+ id: 'form-123',
209
+ slug: 'test-form',
210
+ title: 'Test Form',
211
+ notificationEmail: 'test@example.com'
212
+ } as FormMetadata
213
+
214
+ const formStatus = {
215
+ isPreview: false,
216
+ state: FormStatus.Live
217
+ }
218
+
219
+ const body = format(
220
+ context,
221
+ items,
222
+ model,
223
+ submitResponse,
224
+ formStatus,
225
+ formMetadata
226
+ )
227
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
228
+
229
+ expect(parsedBody.meta).toEqual({
230
+ schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
231
+ timestamp: '2024-01-15T10:30:00.000Z',
232
+ referenceNumber: 'foobar',
233
+ formName: definition.name,
234
+ formId: 'form-123',
235
+ formSlug: 'test-form',
236
+ status: FormStatus.Live,
237
+ isPreview: false,
238
+ notificationEmail: 'test@example.com'
239
+ })
240
+
241
+ expect(parsedBody.data).toEqual({
242
+ main: {
243
+ exampleField: 'hello world',
244
+ exampleField2: 'hello world'
245
+ },
246
+ repeaters: {
247
+ exampleRepeat: [
248
+ {
249
+ subItem1_1: 'hello world',
250
+ subItem1_2: 'hello world'
251
+ },
252
+ {
253
+ subItem2_1: 'hello world'
254
+ }
255
+ ]
256
+ },
257
+ files: {
258
+ exampleFile1: [
259
+ {
260
+ fileId: '123-456-789',
261
+ userDownloadLink: 'https://forms-designer/file-download/123-456-789'
262
+ },
263
+ {
264
+ fileId: '456-789-123',
265
+ userDownloadLink: 'https://forms-designer/file-download/456-789-123'
266
+ }
267
+ ]
268
+ }
269
+ })
270
+ })
271
+
272
+ it('should handle preview form status correctly', () => {
273
+ const formMetadata: FormMetadata = {
274
+ id: 'form-123',
275
+ slug: 'test-form',
276
+ title: 'Test Form',
277
+ notificationEmail: 'test@example.com'
278
+ } as FormMetadata
279
+
280
+ const formStatus = {
281
+ isPreview: true,
282
+ state: FormStatus.Draft
283
+ }
284
+
285
+ const body = format(
286
+ context,
287
+ items,
288
+ model,
289
+ submitResponse,
290
+ formStatus,
291
+ formMetadata
292
+ )
293
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
294
+
295
+ expect(parsedBody.meta.status).toBe(FormStatus.Draft)
296
+ expect(parsedBody.meta.isPreview).toBe(true)
297
+ })
298
+
299
+ it('should handle missing formMetadata with empty strings', () => {
300
+ const formStatus = {
301
+ isPreview: false,
302
+ state: FormStatus.Live
303
+ }
304
+
305
+ const body = format(context, items, model, submitResponse, formStatus)
306
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
307
+
308
+ expect(parsedBody.meta.formId).toBe('')
309
+ expect(parsedBody.meta.formSlug).toBe('')
310
+ expect(parsedBody.meta.notificationEmail).toBe('')
311
+ expect(parsedBody.meta.formName).toBe(definition.name)
312
+ expect(parsedBody.meta.referenceNumber).toBe('foobar')
313
+ })
314
+
315
+ it('should handle partial formMetadata', () => {
316
+ const formMetadata: FormMetadata = {
317
+ id: 'form-456',
318
+ slug: 'partial-form',
319
+ title: 'Partial Form'
320
+ } as FormMetadata
321
+
322
+ const formStatus = {
323
+ isPreview: true,
324
+ state: FormStatus.Draft
325
+ }
326
+
327
+ const body = format(
328
+ context,
329
+ items,
330
+ model,
331
+ submitResponse,
332
+ formStatus,
333
+ formMetadata
334
+ )
335
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
336
+
337
+ expect(parsedBody.meta.formId).toBe('form-456')
338
+ expect(parsedBody.meta.formSlug).toBe('partial-form')
339
+ expect(parsedBody.meta.notificationEmail).toBe('')
340
+ expect(parsedBody.meta.status).toBe(FormStatus.Draft)
341
+ expect(parsedBody.meta.isPreview).toBe(true)
342
+ })
343
+
344
+ it('should use correct schema version', () => {
345
+ const formStatus = {
346
+ isPreview: false,
347
+ state: FormStatus.Live
348
+ }
349
+
350
+ const body = format(context, items, model, submitResponse, formStatus)
351
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
352
+
353
+ expect(parsedBody.meta.schemaVersion).toBe(
354
+ FormAdapterSubmissionSchemaVersion.V1
355
+ )
356
+ expect(parsedBody.meta.schemaVersion).toBe(1)
357
+ })
358
+
359
+ it('should generate valid timestamp', () => {
360
+ const formStatus = {
361
+ isPreview: false,
362
+ state: FormStatus.Live
363
+ }
364
+
365
+ const body = format(context, items, model, submitResponse, formStatus)
366
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
367
+
368
+ expect(parsedBody.meta.timestamp).toBe('2024-01-15T10:30:00.000Z')
369
+ expect(typeof parsedBody.meta.timestamp).toBe('string')
370
+
371
+ expect(new Date(parsedBody.meta.timestamp)).toEqual(
372
+ new Date('2024-01-15T10:30:00.000Z')
373
+ )
374
+ })
375
+
376
+ it('should handle empty items array', () => {
377
+ const formStatus = {
378
+ isPreview: false,
379
+ state: FormStatus.Live
380
+ }
381
+
382
+ const body = format(context, [], model, submitResponse, formStatus)
383
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
384
+
385
+ expect(parsedBody.data.main).toEqual({})
386
+ expect(parsedBody.data.repeaters).toEqual({})
387
+ expect(parsedBody.data.files).toEqual({})
388
+ })
389
+
390
+ it('should handle different form statuses', () => {
391
+ const testCases = [
392
+ {
393
+ isPreview: false,
394
+ state: FormStatus.Live,
395
+ expectedStatus: FormStatus.Live
396
+ },
397
+ {
398
+ isPreview: true,
399
+ state: FormStatus.Draft,
400
+ expectedStatus: FormStatus.Draft
401
+ },
402
+ {
403
+ isPreview: true,
404
+ state: FormStatus.Live,
405
+ expectedStatus: FormStatus.Draft
406
+ }
407
+ ]
408
+
409
+ testCases.forEach(({ isPreview, state, expectedStatus }) => {
410
+ const formStatus = { isPreview, state }
411
+ const body = format(context, items, model, submitResponse, formStatus)
412
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
413
+
414
+ expect(parsedBody.meta.status).toBe(expectedStatus)
415
+ expect(parsedBody.meta.isPreview).toBe(isPreview)
416
+ })
417
+ })
418
+
419
+ it('should return valid JSON string', () => {
420
+ const formStatus = {
421
+ isPreview: false,
422
+ state: FormStatus.Live
423
+ }
424
+
425
+ const body = format(context, items, model, submitResponse, formStatus)
426
+
427
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
428
+ expect(() => JSON.parse(body)).not.toThrow()
429
+ expect(typeof body).toBe('string')
430
+ })
431
+
432
+ it('should handle formMetadata with only id', () => {
433
+ const formMetadata: FormMetadata = {
434
+ id: 'only-id-form'
435
+ } as FormMetadata
436
+
437
+ const formStatus = {
438
+ isPreview: false,
439
+ state: FormStatus.Live
440
+ }
441
+
442
+ const body = format(
443
+ context,
444
+ items,
445
+ model,
446
+ submitResponse,
447
+ formStatus,
448
+ formMetadata
449
+ )
450
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
451
+
452
+ expect(parsedBody.meta.formId).toBe('only-id-form')
453
+ expect(parsedBody.meta.formSlug).toBe('')
454
+ expect(parsedBody.meta.notificationEmail).toBe('')
455
+ })
456
+
457
+ it('should handle formMetadata with only slug', () => {
458
+ const formMetadata: FormMetadata = {
459
+ slug: 'only-slug-form'
460
+ } as FormMetadata
461
+
462
+ const formStatus = {
463
+ isPreview: false,
464
+ state: FormStatus.Live
465
+ }
466
+
467
+ const body = format(
468
+ context,
469
+ items,
470
+ model,
471
+ submitResponse,
472
+ formStatus,
473
+ formMetadata
474
+ )
475
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
476
+
477
+ expect(parsedBody.meta.formId).toBe('')
478
+ expect(parsedBody.meta.formSlug).toBe('only-slug-form')
479
+ expect(parsedBody.meta.notificationEmail).toBe('')
480
+ })
481
+
482
+ it('should handle formMetadata with only notificationEmail', () => {
483
+ const formMetadata: FormMetadata = {
484
+ notificationEmail: 'only-email@example.com'
485
+ } as FormMetadata
486
+
487
+ const formStatus = {
488
+ isPreview: false,
489
+ state: FormStatus.Live
490
+ }
491
+
492
+ const body = format(
493
+ context,
494
+ items,
495
+ model,
496
+ submitResponse,
497
+ formStatus,
498
+ formMetadata
499
+ )
500
+ const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
501
+
502
+ expect(parsedBody.meta.formId).toBe('')
503
+ expect(parsedBody.meta.formSlug).toBe('')
504
+ expect(parsedBody.meta.notificationEmail).toBe('only-email@example.com')
505
+ })
506
+ })
@@ -0,0 +1,53 @@
1
+ import {
2
+ type FormMetadata,
3
+ type SubmitResponsePayload
4
+ } from '@defra/forms-model'
5
+
6
+ import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
7
+ import { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
8
+ import { type DetailItem } from '~/src/server/plugins/engine/models/types.js'
9
+ import { format as machineV2 } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'
10
+ import {
11
+ FormAdapterSubmissionSchemaVersion,
12
+ type FormAdapterSubmissionMessageData,
13
+ type FormAdapterSubmissionMessagePayload,
14
+ type FormContext
15
+ } from '~/src/server/plugins/engine/types.js'
16
+ import { FormStatus } from '~/src/server/routes/types.js'
17
+
18
+ export function format(
19
+ context: FormContext,
20
+ items: DetailItem[],
21
+ model: FormModel,
22
+ submitResponse: SubmitResponsePayload,
23
+ formStatus: ReturnType<typeof checkFormStatus>,
24
+ formMetadata?: FormMetadata
25
+ ): string {
26
+ const v2DataString = machineV2(
27
+ context,
28
+ items,
29
+ model,
30
+ submitResponse,
31
+ formStatus
32
+ )
33
+ const v2DataParsed = JSON.parse(v2DataString) as {
34
+ data: FormAdapterSubmissionMessageData
35
+ }
36
+
37
+ const payload: FormAdapterSubmissionMessagePayload = {
38
+ meta: {
39
+ schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
40
+ timestamp: new Date(),
41
+ referenceNumber: context.referenceNumber,
42
+ formName: model.name,
43
+ formId: formMetadata?.id ?? '',
44
+ formSlug: formMetadata?.slug ?? '',
45
+ status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
46
+ isPreview: formStatus.isPreview,
47
+ notificationEmail: formMetadata?.notificationEmail ?? ''
48
+ },
49
+ data: v2DataParsed.data
50
+ }
51
+
52
+ return JSON.stringify(payload)
53
+ }
@@ -1,4 +1,7 @@
1
- import { type SubmitResponsePayload } from '@defra/forms-model'
1
+ import {
2
+ type FormMetadata,
3
+ type SubmitResponsePayload
4
+ } from '@defra/forms-model'
2
5
  import { addDays, format as dateFormat } from 'date-fns'
3
6
 
4
7
  import { config } from '~/src/config/index.js'
@@ -18,7 +21,8 @@ export function format(
18
21
  items: DetailItem[],
19
22
  model: FormModel,
20
23
  submitResponse: SubmitResponsePayload,
21
- formStatus: ReturnType<typeof checkFormStatus>
24
+ formStatus: ReturnType<typeof checkFormStatus>,
25
+ _formMetadata?: FormMetadata
22
26
  ) {
23
27
  const { files } = submitResponse.result
24
28
 
@@ -1,8 +1,12 @@
1
- import { type SubmitResponsePayload } from '@defra/forms-model'
1
+ import {
2
+ type FormMetadata,
3
+ type SubmitResponsePayload
4
+ } from '@defra/forms-model'
2
5
 
3
6
  import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
4
7
  import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
5
8
  import { type DetailItem } from '~/src/server/plugins/engine/models/types.js'
9
+ import { format as formatAdapterV1 } from '~/src/server/plugins/engine/outputFormatters/adapter/v1.js'
6
10
  import { format as formatHumanV1 } from '~/src/server/plugins/engine/outputFormatters/human/v1.js'
7
11
  import { format as formatMachineV1 } from '~/src/server/plugins/engine/outputFormatters/machine/v1.js'
8
12
  import { format as formatMachineV2 } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'
@@ -13,12 +17,13 @@ type Formatter = (
13
17
  items: DetailItem[],
14
18
  model: FormModel,
15
19
  submitResponse: SubmitResponsePayload,
16
- formStatus: ReturnType<typeof checkFormStatus>
20
+ formStatus: ReturnType<typeof checkFormStatus>,
21
+ formMetadata?: FormMetadata
17
22
  ) => string
18
23
 
19
24
  const formatters: Record<
20
25
  string,
21
- Record<string, Formatter | undefined> | undefined
26
+ Record<string, Formatter | typeof formatAdapterV1 | undefined> | undefined
22
27
  > = {
23
28
  human: {
24
29
  '1': formatHumanV1
@@ -26,6 +31,9 @@ const formatters: Record<
26
31
  machine: {
27
32
  '1': formatMachineV1,
28
33
  '2': formatMachineV2
34
+ },
35
+ adapter: {
36
+ '1': formatAdapterV1
29
37
  }
30
38
  }
31
39
 
@@ -1,4 +1,7 @@
1
- import { type SubmitResponsePayload } from '@defra/forms-model'
1
+ import {
2
+ type FormMetadata,
3
+ type SubmitResponsePayload
4
+ } from '@defra/forms-model'
2
5
 
3
6
  import { config } from '~/src/config/index.js'
4
7
  import { getAnswer } from '~/src/server/plugins/engine/components/helpers.js'
@@ -19,7 +22,8 @@ export function format(
19
22
  items: DetailItem[],
20
23
  model: FormModel,
21
24
  _submitResponse: SubmitResponsePayload,
22
- _formStatus: ReturnType<typeof checkFormStatus>
25
+ _formStatus: ReturnType<typeof checkFormStatus>,
26
+ _formMetadata?: FormMetadata
23
27
  ) {
24
28
  const now = new Date()
25
29
 
@@ -150,7 +150,7 @@ type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {
150
150
  field: FileUploadField
151
151
  }
152
152
 
153
- type RichFormValue =
153
+ export type RichFormValue =
154
154
  | FormValue
155
155
  | FormPayload
156
156
  | DatePartsState
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  hasComponentsEvenIfNoNext,
3
+ type FormMetadata,
3
4
  type Page,
4
5
  type SubmitPayload
5
6
  } from '@defra/forms-model'
@@ -111,7 +112,8 @@ export class SummaryPageController extends QuestionPageController {
111
112
  const { getFormMetadata } = formsService
112
113
 
113
114
  // Get the form metadata using the `slug` param
114
- const { notificationEmail } = await getFormMetadata(params.slug)
115
+ const formMetadata = await getFormMetadata(params.slug)
116
+ const { notificationEmail } = formMetadata
115
117
  const { isPreview } = checkFormStatus(request.params)
116
118
  const emailAddress = notificationEmail ?? this.model.def.outputEmail
117
119
 
@@ -120,7 +122,14 @@ export class SummaryPageController extends QuestionPageController {
120
122
  // Send submission email
121
123
  if (emailAddress) {
122
124
  const viewModel = this.getSummaryViewModel(request, context)
123
- await submitForm(context, request, viewModel, model, emailAddress)
125
+ await submitForm(
126
+ context,
127
+ request,
128
+ viewModel,
129
+ model,
130
+ emailAddress,
131
+ formMetadata
132
+ )
124
133
  }
125
134
 
126
135
  await cacheService.setConfirmationState(request, { confirmed: true })
@@ -150,7 +159,8 @@ async function submitForm(
150
159
  request: FormRequestPayload,
151
160
  summaryViewModel: SummaryViewModel,
152
161
  model: FormModel,
153
- emailAddress: string
162
+ emailAddress: string,
163
+ formMetadata: FormMetadata
154
164
  ) {
155
165
  await extendFileRetention(model, context.state, emailAddress)
156
166
 
@@ -184,7 +194,8 @@ async function submitForm(
184
194
  model,
185
195
  emailAddress,
186
196
  items,
187
- submitResponse
197
+ submitResponse,
198
+ formMetadata
188
199
  )
189
200
  }
190
201