@ukhomeoffice/cop-react-form-renderer 6.15.15 → 6.15.16

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 (13) hide show
  1. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-component-with-nested-questions-visible-elsewhere.json +118 -0
  2. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-nested-answers-hidden-by-option-visible-elsewhere.json +113 -0
  3. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-page-nested-component.json +26003 -0
  4. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-component-with-nested-questions-visible-elsewhere.json +12 -0
  5. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-nested-answers-hidden-by-option-visible-elsewhere.json +12 -0
  6. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-page-nested-component.json +63 -0
  7. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-component-with-nested-questions-visible-elsewhere-removed.json +11 -0
  8. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-nested-answers-hidden-by-option-visible-elsewhere-removed.json +12 -0
  9. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-page-nested-component.json +63 -0
  10. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.js +17 -14
  11. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.test.js +31 -0
  12. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutesUtils.js +44 -35
  13. package/package.json +1 -1
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "Example form",
3
+ "alpha": "alpha-value",
4
+ "bravo": "bravo-value",
5
+ "person": {
6
+ "telephoneKnown": "yes",
7
+ "telephone": "telephone-value",
8
+ "name":"name-value"
9
+ },
10
+ "gamma": "gamma-value",
11
+ "epsilon": "epsilon-value"
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "Example form",
3
+ "alpha": "alpha-value",
4
+ "bravo": "bravo-value",
5
+ "person": {
6
+ "telephoneKnown": "no",
7
+ "telephone": "telephone-value",
8
+ "name":"name-value"
9
+ },
10
+ "gamma": "gamma-value",
11
+ "epsilon": "epsilon-value"
12
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "id": "aa767e34-3624-11f0-a073-1a2af3427453",
3
+ "businessKey": "DEV-20250521-906",
4
+ "port": {
5
+ "id": 1639,
6
+ "name": "Dover",
7
+ "sea": true,
8
+ "air": false,
9
+ "land": false,
10
+ "rail": false,
11
+ "countryid": 234,
12
+ "iata": null,
13
+ "value": "1639",
14
+ "label": "Dover",
15
+ "hint": ""
16
+ },
17
+ "modeOfTransport": {
18
+ "id": 9,
19
+ "mode": "RoRo Tourist",
20
+ "modecode": "rorotour",
21
+ "crossingtype": [
22
+ "sea"
23
+ ],
24
+ "value": "RoRo Tourist",
25
+ "label": "RoRo Tourist"
26
+ },
27
+ "whatHappened": "roroItemsFootPassenger",
28
+ "peopleActiveId": "16cfee4e-f345-4b29-883f-0ad6877d492c",
29
+ "people": [
30
+ {
31
+ "id": "16cfee4e-f345-4b29-883f-0ad6877d492c",
32
+ "hasIdentityDocuments": [
33
+ "no"
34
+ ],
35
+ "arrested": "yes",
36
+ "claimedGivenNames": "Robert",
37
+ "claimedSurname": "test",
38
+ "estimatedDob": "27-8-1982",
39
+ "claimedCountryOfBirth": {
40
+ "id": 2,
41
+ "name": "Afghanistan",
42
+ "iso31661alpha3": "AFG",
43
+ "value": "2",
44
+ "label": "Afghanistan",
45
+ "hint": ""
46
+ },
47
+ "howDidYouVerifyTheirIdentity": "TEST",
48
+ "noAddresses": "Person has no addresses",
49
+ "noAddressDetails": [
50
+ "none"
51
+ ],
52
+ "travellingRole": {
53
+ "id": 6,
54
+ "roletype": "Driver",
55
+ "value": "6",
56
+ "label": "Driver",
57
+ "hint": ""
58
+ },
59
+ "governmentOrBorderForceEmployee": "no",
60
+ "personSearched": "no"
61
+ }
62
+ ]
63
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "type": "Example form",
3
+ "alpha": "alpha-value",
4
+ "bravo": "bravo-value",
5
+ "person": {
6
+ "telephone": "telephone-value",
7
+ "name":"name-value"
8
+ },
9
+ "gamma": "gamma-value",
10
+ "epsilon": "epsilon-value"
11
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "Example form",
3
+ "alpha": "alpha-value",
4
+ "bravo": "bravo-value",
5
+ "person": {
6
+ "telephoneKnown": "no",
7
+ "telephone": "telephone-value",
8
+ "name":"name-value"
9
+ },
10
+ "gamma": "gamma-value",
11
+ "epsilon": "epsilon-value"
12
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "id": "aa767e34-3624-11f0-a073-1a2af3427453",
3
+ "businessKey": "DEV-20250521-906",
4
+ "port": {
5
+ "id": 1639,
6
+ "name": "Dover",
7
+ "sea": true,
8
+ "air": false,
9
+ "land": false,
10
+ "rail": false,
11
+ "countryid": 234,
12
+ "iata": null,
13
+ "value": "1639",
14
+ "label": "Dover",
15
+ "hint": ""
16
+ },
17
+ "modeOfTransport": {
18
+ "id": 9,
19
+ "mode": "RoRo Tourist",
20
+ "modecode": "rorotour",
21
+ "crossingtype": [
22
+ "sea"
23
+ ],
24
+ "value": "RoRo Tourist",
25
+ "label": "RoRo Tourist"
26
+ },
27
+ "whatHappened": "roroItemsFootPassenger",
28
+ "peopleActiveId": "16cfee4e-f345-4b29-883f-0ad6877d492c",
29
+ "people": [
30
+ {
31
+ "id": "16cfee4e-f345-4b29-883f-0ad6877d492c",
32
+ "hasIdentityDocuments": [
33
+ "no"
34
+ ],
35
+ "arrested": "yes",
36
+ "claimedGivenNames": "Robert",
37
+ "claimedSurname": "test",
38
+ "estimatedDob": "27-8-1982",
39
+ "claimedCountryOfBirth": {
40
+ "id": 2,
41
+ "name": "Afghanistan",
42
+ "iso31661alpha3": "AFG",
43
+ "value": "2",
44
+ "label": "Afghanistan",
45
+ "hint": ""
46
+ },
47
+ "howDidYouVerifyTheirIdentity": "TEST",
48
+ "noAddresses": "Person has no addresses",
49
+ "noAddressDetails": [
50
+ "none"
51
+ ],
52
+ "travellingRole": {
53
+ "id": 6,
54
+ "roletype": "Driver",
55
+ "value": "6",
56
+ "label": "Driver",
57
+ "hint": ""
58
+ },
59
+ "governmentOrBorderForceEmployee": "no",
60
+ "personSearched": "no"
61
+ }
62
+ ]
63
+ }
@@ -42,6 +42,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
42
42
  const createComponentMapsFromForm = (condensedPages, componentByIdMap, componentByFieldIdMap, formData) => {
43
43
  const allComponents = new Map();
44
44
  const componentsToKeep = {};
45
+ const unselectedOptionsNestedPaths = [];
45
46
  const allCollections = new Map();
46
47
 
47
48
  /*
@@ -68,20 +69,14 @@ const createComponentMapsFromForm = (condensedPages, componentByIdMap, component
68
69
  var _component$data2;
69
70
  component === null || component === void 0 || (_component$data2 = component.data) === null || _component$data2 === void 0 || (_component$data2 = _component$data2.options) === null || _component$data2 === void 0 || _component$data2.forEach(option => {
70
71
  if (option.nested) {
71
- // in container need to use the JPath for the data since the field that the component is looking at is nested in the container.
72
- if (!(0, _optionIsSelected.default)((0, _getSourceData.default)(formData, path), option)) {
73
- option.nested.forEach(nestedComponent => {
74
- // delete hidden nested question payload items when the parent option is not selected
75
- Utils.deleteNodeByPath(formData, Utils.getNestedQuestionPath(path, nestedComponent.fieldId));
76
- });
77
- } else {
78
- // If the option is selected, then add any nested components to the allComponents list. If the nested block has a show_when, pass it down to the child questions
79
- const blockShowWhen = option.show_when;
80
- option.nested.forEach(nestedComponent => {
81
- if (blockShowWhen) nestedComponent.show_when = blockShowWhen;
82
- recursivelyMapFieldsAndDeleteHiddenNested(page, nestedComponent, Utils.getImmediateParent(path), allComponents, componentsToKeep, formData);
83
- });
84
- }
72
+ const unselectedOption = !(0, _optionIsSelected.default)((0, _getSourceData.default)(formData, path), option);
73
+ const blockShowWhen = option.show_when;
74
+ option.nested.forEach(nestedComponent => {
75
+ // prepare to delete hidden nested question payload items when the parent option is not selected
76
+ if (unselectedOption) unselectedOptionsNestedPaths.push(Utils.getNestedQuestionPath(path, nestedComponent.fieldId));
77
+ if (blockShowWhen) nestedComponent.show_when = blockShowWhen;
78
+ recursivelyMapFieldsAndDeleteHiddenNested(page, nestedComponent, Utils.getImmediateParent(path), allComponents, componentsToKeep, formData);
79
+ });
85
80
  }
86
81
  });
87
82
  }
@@ -100,6 +95,14 @@ const createComponentMapsFromForm = (condensedPages, componentByIdMap, component
100
95
  });
101
96
  }
102
97
  });
98
+ // Now delete all the unselected options, if they are not used elsewhere
99
+ unselectedOptionsNestedPaths.forEach(path => {
100
+ if (componentsToKeep[path] > 1) {
101
+ componentsToKeep[path] -= 1;
102
+ } else {
103
+ Utils.deleteNodeByPath(formData, path);
104
+ }
105
+ });
103
106
  return {
104
107
  allComponents,
105
108
  componentsToKeep,
@@ -31,9 +31,15 @@ var _dataHiddenOptionsRemoved = _interopRequireDefault(require("../clear-uncompl
31
31
  var _formHiddenComponentWithNestedQuestions = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-component-with-nested-questions.json"));
32
32
  var _dataHiddenComponentWithNestedQuestions = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-component-with-nested-questions.json"));
33
33
  var _dataHiddenComponentWithNestedQuestionsRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-component-with-nested-questions-removed.json"));
34
+ var _formHiddenComponentWithNestedQuestionsVisibleElsewhere = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-component-with-nested-questions-visible-elsewhere.json"));
35
+ var _dataHiddenComponentWithNestedQuestionsVisibleElsewhere = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-component-with-nested-questions-visible-elsewhere.json"));
36
+ var _dataHiddenComponentWithNestedQuestionsVisibleElsewhereRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-component-with-nested-questions-visible-elsewhere-removed.json"));
34
37
  var _formNestedAnswersHiddenByOption = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-nested-answers-hidden-by-option.json"));
35
38
  var _dataNestedAnswersHiddenByOption = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-nested-answers-hidden-by-option.json"));
36
39
  var _dataNestedAnswersHiddenByOptionRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-nested-answers-hidden-by-option-removed.json"));
40
+ var _formNestedAnswersHiddenByOptionVisibleElsewhere = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-nested-answers-hidden-by-option-visible-elsewhere.json"));
41
+ var _dataNestedAnswersHiddenByOptionVisibleElsewhere = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-nested-answers-hidden-by-option-visible-elsewhere.json"));
42
+ var _dataNestedAnswersHiddenByOptionVisibleElsewhereRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-nested-answers-hidden-by-option-visible-elsewhere-removed.json"));
37
43
  var _formHiddenPage = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-page.json"));
38
44
  var _dataHiddenPage = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-page.json"));
39
45
  var _dataHiddenPageRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-page-removed.json"));
@@ -99,6 +105,9 @@ var _copAirpaxCarrier = _interopRequireDefault(require("../clear-uncompleted-rou
99
105
  var _formPageNestedRadioComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-page-nested-radio-component.json"));
100
106
  var _dataPageNestedRadioComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-page-nested-radio-component.json"));
101
107
  var _dataPageNestedRadioComponentRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-page-nested-radio-component-removed.json"));
108
+ var _formPageNestedComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-page-nested-component.json"));
109
+ var _dataPageNestedComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-page-nested-component.json"));
110
+ var _dataPageNestedComponent2 = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-page-nested-component.json"));
102
111
  var _formVarianceBreach = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-variance-breach.json"));
103
112
  var _copVarianceBreachWithUploadFiles = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/cop-variance-breach-with-upload-files.json"));
104
113
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -122,8 +131,12 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
122
131
 
123
132
  // Nested questions within options inside a hidden component
124
133
 
134
+ // Nested questions within options inside a hidden component, but one nested path visible elsewhere
135
+
125
136
  // Nested options inside a visible component, but answers don't align with option selected
126
137
 
138
+ // Nested options inside a visible component, answers don't align with option selected, but path visible elsewhere
139
+
127
140
  // Hidden page
128
141
 
129
142
  // Hidden page containing same component reused
@@ -243,12 +256,24 @@ describe('FormRenderer', () => {
243
256
  const result = _index.default.clearOutUncompletedRoutes(true, form, submissionData);
244
257
  expect(result).toEqual(_dataHiddenComponentWithNestedQuestionsRemoved.default);
245
258
  });
259
+ it('should NOT remove hidden component with nested questions in options when same path is visible elsewhere.', () => {
260
+ const submissionData = JSON.parse(JSON.stringify(_dataHiddenComponentWithNestedQuestionsVisibleElsewhere.default));
261
+ const form = JSON.parse(JSON.stringify(_formHiddenComponentWithNestedQuestionsVisibleElsewhere.default));
262
+ const result = _index.default.clearOutUncompletedRoutes(true, form, submissionData);
263
+ expect(result).toEqual(_dataHiddenComponentWithNestedQuestionsVisibleElsewhereRemoved.default);
264
+ });
246
265
  it('should remove answers associated with unselected options in a containerised component.', () => {
247
266
  const submissionData = JSON.parse(JSON.stringify(_dataNestedAnswersHiddenByOption.default));
248
267
  const form = JSON.parse(JSON.stringify(_formNestedAnswersHiddenByOption.default));
249
268
  const result = _index.default.clearOutUncompletedRoutes(true, form, submissionData);
250
269
  expect(result).toEqual(_dataNestedAnswersHiddenByOptionRemoved.default);
251
270
  });
271
+ it('should NOT remove answers associated with unselected options in a containerised component if component visible elsewhere.', () => {
272
+ const submissionData = JSON.parse(JSON.stringify(_dataNestedAnswersHiddenByOptionVisibleElsewhere.default));
273
+ const form = JSON.parse(JSON.stringify(_formNestedAnswersHiddenByOptionVisibleElsewhere.default));
274
+ const result = _index.default.clearOutUncompletedRoutes(true, form, submissionData);
275
+ expect(result).toEqual(_dataNestedAnswersHiddenByOptionVisibleElsewhereRemoved.default);
276
+ });
252
277
  it('should remove hidden page.', () => {
253
278
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenPage.default));
254
279
  const form = JSON.parse(JSON.stringify(_formHiddenPage.default));
@@ -397,6 +422,12 @@ describe('FormRenderer', () => {
397
422
  const result = _index.default.clearOutUncompletedRoutes(true, form, submissionData);
398
423
  expect(result).toEqual(_dataPageNestedRadioComponentRemoved.default);
399
424
  });
425
+ it('should handle not removing the field if its used both nested option and a separate component.', () => {
426
+ const submissionData = JSON.parse(JSON.stringify(_dataPageNestedComponent.default));
427
+ const form = JSON.parse(JSON.stringify(_formPageNestedComponent.default));
428
+ const result = _index.default.clearOutUncompletedRoutes(true, form, submissionData);
429
+ expect(result).toEqual(_dataPageNestedComponent2.default);
430
+ });
400
431
  });
401
432
  });
402
433
  });
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.toArray = exports.removeObjectWithOnlySingleIdField = exports.removeEmptyArraysAndUnusedCollectionIDs = exports.pruneCollectionEntry = exports.isShowEntity = exports.getNestedQuestionPath = exports.getImmediateParent = exports.getDependencyObjectFromPath = exports.getDependencies = exports.findComponentDefinitionInForm = exports.deleteNodeByPath = exports.deleteNodeAndOptions = exports.deleteCorrespondingMetaInfo = exports.deleteComponentData = exports.addValue = void 0;
6
+ exports.toArray = exports.removeObjectWithOnlySingleIdField = exports.removeEmptyArraysAndUnusedCollectionIDs = exports.pruneCollectionEntry = exports.iterateOptions = exports.isShowEntity = exports.getNestedQuestionPath = exports.getImmediateParent = exports.getDependencyObjectFromPath = exports.getDependencies = exports.findComponentDefinitionInForm = exports.deleteNodeByPath = exports.deleteCorrespondingMetaInfo = exports.deleteComponentData = exports.addValue = void 0;
7
7
  var _Condition = _interopRequireDefault(require("../../../utils/Condition"));
8
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
9
  /* eslint-disable no-param-reassign */
@@ -85,36 +85,6 @@ const getNestedQuestionPath = (optionPath, nestedFieldId) => {
85
85
  return parentPath ? "".concat(parentPath, ".").concat(nestedFieldId) : nestedFieldId;
86
86
  };
87
87
 
88
- /**
89
- * If the component has options, go through each option removing the data for any nested fields.
90
- * Required as nested options are in the payload at the same heirarchical level.
91
- *
92
- * There are occasions when a field shouldn't be removed from the payload, eg if a form is being used for 2 purposes
93
- * eg the cop-reassign-task-to-rcc.json, and the field is only being hidden for display purposes. Allow these fields
94
- * to be preserved with a property on the component.
95
-
96
- * @param {Object} payload Javascript object from which the node will be deleted. Updated by the method.
97
- * @param {String} path A string containing a decimal point delimited path specifying the node to delete.
98
- * @param {Object} component The form component representing the path being deleted
99
- * @return {void}, obj above updated.
100
- */
101
- exports.getNestedQuestionPath = getNestedQuestionPath;
102
- const deleteNodeAndOptions = (payload, path, component) => {
103
- var _component$data;
104
- if (component.preserveInPayload) return;
105
- deleteNodeByPath(payload, path);
106
- // If the component has options, go through each option removing the data for any nested fields. Required as nested options are in the payload at the same heirarchical level.
107
- if (component !== null && component !== void 0 && (_component$data = component.data) !== null && _component$data !== void 0 && _component$data.options) {
108
- var _component$data2;
109
- component === null || component === void 0 || (_component$data2 = component.data) === null || _component$data2 === void 0 || (_component$data2 = _component$data2.options) === null || _component$data2 === void 0 || _component$data2.forEach(option => {
110
- var _option$nested;
111
- (_option$nested = option.nested) === null || _option$nested === void 0 || _option$nested.forEach(nested => {
112
- deleteNodeByPath(payload, getNestedQuestionPath(path, nested.fieldId));
113
- });
114
- });
115
- }
116
- };
117
-
118
88
  /**
119
89
  * Pruning a collection payload may have resulted in objects that are only left with their 'id' field, which isn't data
120
90
  * but added by the renderer to find the activeId. If so, remove these objects entirely as they have been pruned.
@@ -122,7 +92,7 @@ const deleteNodeAndOptions = (payload, path, component) => {
122
92
  * @param {Array} array Array of objects. Each object which has only 1 remaining field called 'id' should be removed.
123
93
  * @return {void}, array above updated.
124
94
  */
125
- exports.deleteNodeAndOptions = deleteNodeAndOptions;
95
+ exports.getNestedQuestionPath = getNestedQuestionPath;
126
96
  const removeObjectWithOnlySingleIdField = array => {
127
97
  for (let i = array.length - 1; i >= 0; i -= 1) {
128
98
  const obj = array[i];
@@ -333,6 +303,24 @@ const removeEmptyArraysAndUnusedCollectionIDs = payload => {
333
303
  }
334
304
  };
335
305
 
306
+ /**
307
+ * Helper method to go through each option calling a passed in function for any nested fields.
308
+ * @param {Object} component The form component representing the path being deleted
309
+ * @param {Function} action The action to perform on each nested question. Varies for collections and non-collections
310
+ * @return {void}, obj above updated.
311
+ */
312
+ exports.removeEmptyArraysAndUnusedCollectionIDs = removeEmptyArraysAndUnusedCollectionIDs;
313
+ const iterateOptions = (component, action) => {
314
+ var _component$data;
315
+ if (component !== null && component !== void 0 && (_component$data = component.data) !== null && _component$data !== void 0 && _component$data.options) {
316
+ var _component$data2;
317
+ component === null || component === void 0 || (_component$data2 = component.data) === null || _component$data2 === void 0 || (_component$data2 = _component$data2.options) === null || _component$data2 === void 0 || _component$data2.forEach(option => {
318
+ var _option$nested;
319
+ (_option$nested = option.nested) === null || _option$nested === void 0 || _option$nested.forEach(action);
320
+ });
321
+ }
322
+ };
323
+
336
324
  /**
337
325
  * Delete a component's payload item from the overall payload.
338
326
  * A component can be defined in >1 places in the form spec. To cater for this,
@@ -348,12 +336,23 @@ const removeEmptyArraysAndUnusedCollectionIDs = payload => {
348
336
  * @param {*} component The component whose data we should attempt to delete
349
337
  * @param {*} componentsToKeep A list of all components with a count of their number of uses in the form
350
338
  */
351
- exports.removeEmptyArraysAndUnusedCollectionIDs = removeEmptyArraysAndUnusedCollectionIDs;
339
+ exports.iterateOptions = iterateOptions;
352
340
  const deleteComponentData = (payload, path, component, componentsToKeep) => {
353
341
  if (componentsToKeep[path] > 1) {
354
342
  componentsToKeep[path] -= 1;
355
343
  } else {
356
- deleteNodeAndOptions(payload, path, component);
344
+ if (component.preserveInPayload) return;
345
+ deleteNodeByPath(payload, path);
346
+
347
+ // If the component has options, go through each option removing the data for any nested fields. Required as nested options are in the payload at the same heirarchical level.
348
+ iterateOptions(component, nested => {
349
+ const nestedQuestionPath = getNestedQuestionPath(path, nested.fieldId);
350
+ if (componentsToKeep[nestedQuestionPath] > 1) {
351
+ componentsToKeep[nestedQuestionPath] -= 1;
352
+ } else {
353
+ deleteNodeByPath(payload, nestedQuestionPath);
354
+ }
355
+ });
357
356
  }
358
357
  };
359
358
 
@@ -361,6 +360,7 @@ const deleteComponentData = (payload, path, component, componentsToKeep) => {
361
360
  *
362
361
  * Takes a single page collection payload object and removes the payload items specified in the componentsToPrune list
363
362
  * as long as they don't appear in the componentsToKeep list.
363
+ *
364
364
  * Additionally, if the component type is multifile, remove the corresponding data entries that will have been created
365
365
  * in the meta section of the payload by the form renderer.
366
366
  *
@@ -376,7 +376,16 @@ const pruneCollectionEntry = (pathsToKeep, componentsToPrune, collectionDataObje
376
376
  if (component.type === "multifile") {
377
377
  deleteCorrespondingMetaInfo(component, collectionDataObject, formData);
378
378
  }
379
- deleteNodeAndOptions(collectionDataObject, component.fieldId, component);
379
+ if (component.preserveInPayload) return;
380
+ deleteNodeByPath(collectionDataObject, component.fieldId);
381
+
382
+ // If the component has options, go through each option removing the data for any nested fields. Required as nested options are in the payload at the same heirarchical level.
383
+ iterateOptions(component, nested => {
384
+ const nestedQuestionPath = getNestedQuestionPath(component.fieldId, nested.fieldId);
385
+ if (!pathsToKeep.has(nestedQuestionPath)) {
386
+ deleteNodeByPath(collectionDataObject, nestedQuestionPath);
387
+ }
388
+ });
380
389
  }
381
390
  });
382
391
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukhomeoffice/cop-react-form-renderer",
3
- "version": "6.15.15",
3
+ "version": "6.15.16",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "clean": "rimraf dist",