@ukhomeoffice/cop-react-form-renderer 3.0.3 → 3.2.2

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 (27) hide show
  1. package/dist/components/FormComponent/Collection.js +1 -5
  2. package/dist/components/FormComponent/Collection.test.js +322 -0
  3. package/dist/components/FormRenderer/FormRenderer.js +36 -13
  4. package/dist/components/FormRenderer/helpers/cleanHiddenNestedData.js +38 -0
  5. package/dist/components/FormRenderer/helpers/cleanHiddenNestedData.test.js +50 -0
  6. package/dist/components/FormRenderer/helpers/index.js +3 -0
  7. package/dist/context/HooksContext/HooksContext.js +8 -2
  8. package/dist/utils/CheckYourAnswers/getCYARow.js +3 -1
  9. package/dist/utils/CheckYourAnswers/getCYARow.test.js +3 -3
  10. package/dist/utils/Component/cleanAttributes.js +1 -1
  11. package/dist/utils/Component/getComponent.js +38 -20
  12. package/dist/utils/Component/getComponentTests/getComponent.nested.test.js +49 -26
  13. package/dist/utils/Component/getComponentTests/getComponent.time.test.js +106 -0
  14. package/dist/utils/Component/showComponent.js +6 -0
  15. package/dist/utils/Component/showComponent.test.js +63 -0
  16. package/dist/utils/Component/wrapInFormGroup.js +5 -2
  17. package/dist/utils/Condition/index.js +3 -0
  18. package/dist/utils/Condition/meetsOneCondition.js +40 -0
  19. package/dist/utils/Condition/meetsOneCondition.test.js +101 -0
  20. package/dist/utils/Condition/setupConditions.js +5 -4
  21. package/dist/utils/Container/showContainer.js +4 -0
  22. package/dist/utils/Container/showContainer.test.js +51 -0
  23. package/dist/utils/FormPage/showFormPage.js +4 -0
  24. package/dist/utils/FormPage/showFormPage.test.js +51 -0
  25. package/dist/utils/Validate/validateComponent.js +8 -15
  26. package/dist/utils/Validate/validateComponent.test.js +13 -14
  27. package/package.json +2 -2
@@ -67,15 +67,11 @@ var Collection = function Collection(_ref) {
67
67
  onChange = _ref.onChange,
68
68
  wrap = _ref.wrap;
69
69
 
70
- var _useState = (0, _react.useState)(),
70
+ var _useState = (0, _react.useState)(_value),
71
71
  _useState2 = _slicedToArray(_useState, 2),
72
72
  value = _useState2[0],
73
73
  setValue = _useState2[1];
74
74
 
75
- (0, _react.useEffect)(function () {
76
- setValue(_value || []);
77
- }, [_value, setValue]);
78
-
79
75
  var reportChange = function reportChange(newValue) {
80
76
  setValue(newValue);
81
77
 
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+
3
+ var _react = require("@testing-library/react");
4
+
5
+ var _react2 = _interopRequireDefault(require("react"));
6
+
7
+ var _testUtils = require("react-dom/test-utils");
8
+
9
+ var _models = require("../../models");
10
+
11
+ var _setupTests = require("../../setupTests");
12
+
13
+ var _utils = _interopRequireDefault(require("../../utils"));
14
+
15
+ var _Collection = require("./Collection");
16
+
17
+ var _Container = require("./Container");
18
+
19
+ var _FormComponent = _interopRequireDefault(require("./FormComponent"));
20
+
21
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
+
23
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
24
+
25
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
26
+
27
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
28
+
29
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
30
+
31
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
32
+
33
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
34
+
35
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
36
+
37
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
38
+
39
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
40
+
41
+ describe('components.FormComponent.Collection', function () {
42
+ var ID = 'collection';
43
+ var TEXT_ID = 'text';
44
+ var TEXT_VALUE = 'alpha';
45
+
46
+ var FORM_DATA = _defineProperty({}, ID, [_defineProperty({
47
+ id: '1'
48
+ }, TEXT_ID, TEXT_VALUE)]);
49
+
50
+ var TEXT_COMPONENT = {
51
+ id: TEXT_ID,
52
+ fieldId: TEXT_ID,
53
+ type: _models.ComponentTypes.TEXT,
54
+ label: 'Text component',
55
+ hint: 'Text hint'
56
+ };
57
+ it('should render a collection component appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
58
+ var COLLECTION, _renderWithValidation, container, c, item, _item$childNodes, title, itemContainer, formGroup, label, hint, input;
59
+
60
+ return regeneratorRuntime.wrap(function _callee$(_context) {
61
+ while (1) {
62
+ switch (_context.prev = _context.next) {
63
+ case 0:
64
+ COLLECTION = {
65
+ id: ID,
66
+ fieldId: ID,
67
+ type: _models.ComponentTypes.COLLECTION,
68
+ item: [TEXT_COMPONENT]
69
+ };
70
+ _renderWithValidation = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
71
+ component: COLLECTION,
72
+ value: FORM_DATA[ID],
73
+ formData: FORM_DATA
74
+ })), container = _renderWithValidation.container; // Check the container itself.
75
+
76
+ c = container.childNodes[0];
77
+ expect(c.tagName).toEqual('DIV');
78
+ expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now check the single text component within it.
79
+
80
+ item = c.childNodes[0];
81
+ expect(item.tagName).toEqual('DIV');
82
+ expect(item.classList).toContain("".concat(_Collection.DEFAULT_CLASS, "__item"));
83
+ _item$childNodes = _slicedToArray(item.childNodes, 2), title = _item$childNodes[0], itemContainer = _item$childNodes[1];
84
+ expect(title.tagName).toEqual('LABEL');
85
+ expect(title.classList).toContain("".concat(_Collection.DEFAULT_CLASS, "__item-title"));
86
+ expect(itemContainer.tagName).toEqual('DIV');
87
+ expect(itemContainer.classList).toContain(_Container.DEFAULT_CLASS);
88
+ formGroup = itemContainer.childNodes[0];
89
+ expect(formGroup.tagName).toEqual('DIV');
90
+ expect(formGroup.classList).toContain('govuk-form-group');
91
+ label = formGroup.childNodes[0];
92
+ expect(label.tagName).toEqual('LABEL');
93
+ expect(label.classList).toContain('govuk-label');
94
+ expect(label.textContent).toEqual("".concat(TEXT_COMPONENT.label, " (optional)"));
95
+ expect(label.getAttribute('for')).toEqual("".concat(ID, "[0].").concat(TEXT_ID));
96
+ hint = formGroup.childNodes[1];
97
+ expect(hint.tagName).toEqual('SPAN');
98
+ expect(hint.classList).toContain('govuk-hint');
99
+ expect(hint.textContent).toEqual(TEXT_COMPONENT.hint);
100
+ input = formGroup.childNodes[2];
101
+ expect(input.tagName).toEqual('INPUT');
102
+ expect(input.classList).toContain('govuk-input');
103
+ expect(input.id).toEqual("".concat(ID, "[0].").concat(TEXT_ID));
104
+ expect(input.value).toEqual(TEXT_VALUE);
105
+
106
+ case 30:
107
+ case "end":
108
+ return _context.stop();
109
+ }
110
+ }
111
+ }, _callee);
112
+ })));
113
+ it('should handle a change to a component appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
114
+ var ON_CHANGE_EVENTS, ON_CHANGE, COLLECTION, _renderWithValidation2, container, c, item, formGroup, input, NEW_TEXT_VALUE, EVENT;
115
+
116
+ return regeneratorRuntime.wrap(function _callee2$(_context2) {
117
+ while (1) {
118
+ switch (_context2.prev = _context2.next) {
119
+ case 0:
120
+ ON_CHANGE_EVENTS = [];
121
+
122
+ ON_CHANGE = function ON_CHANGE(e) {
123
+ ON_CHANGE_EVENTS.push(e);
124
+ };
125
+
126
+ COLLECTION = {
127
+ id: ID,
128
+ fieldId: ID,
129
+ type: _models.ComponentTypes.COLLECTION,
130
+ item: [{
131
+ id: TEXT_ID,
132
+ fieldId: TEXT_ID,
133
+ type: _models.ComponentTypes.TEXT,
134
+ label: 'Text component'
135
+ }]
136
+ };
137
+ _renderWithValidation2 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
138
+ component: COLLECTION,
139
+ value: FORM_DATA[ID],
140
+ formData: FORM_DATA,
141
+ onChange: ON_CHANGE
142
+ })), container = _renderWithValidation2.container; // Get hold of the text input.
143
+
144
+ c = container.childNodes[0];
145
+ item = c.childNodes[0];
146
+ formGroup = item.childNodes[1].childNodes[0];
147
+ input = formGroup.childNodes[2];
148
+ NEW_TEXT_VALUE = 'bravo';
149
+ EVENT = {
150
+ target: {
151
+ name: TEXT_ID,
152
+ value: NEW_TEXT_VALUE
153
+ }
154
+ };
155
+
156
+ _react.fireEvent.change(input, EVENT); // And confirm the formData has been changed.
157
+
158
+
159
+ expect(ON_CHANGE_EVENTS.length).toEqual(1);
160
+ expect(ON_CHANGE_EVENTS[0].target.name).toEqual(ID);
161
+ expect(ON_CHANGE_EVENTS[0].target.value[0][TEXT_ID]).toEqual(NEW_TEXT_VALUE);
162
+
163
+ case 14:
164
+ case "end":
165
+ return _context2.stop();
166
+ }
167
+ }
168
+ }, _callee2);
169
+ })));
170
+ it('should handle a null value appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
171
+ var COLLECTION, _renderWithValidation3, container, c, buttonGroup, button;
172
+
173
+ return regeneratorRuntime.wrap(function _callee3$(_context3) {
174
+ while (1) {
175
+ switch (_context3.prev = _context3.next) {
176
+ case 0:
177
+ COLLECTION = {
178
+ id: ID,
179
+ fieldId: ID,
180
+ type: _models.ComponentTypes.COLLECTION,
181
+ item: [TEXT_COMPONENT]
182
+ };
183
+ _renderWithValidation3 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
184
+ component: COLLECTION
185
+ })), container = _renderWithValidation3.container; // Check the container itself.
186
+
187
+ c = container.childNodes[0];
188
+ expect(c.tagName).toEqual('DIV');
189
+ expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now make sure it has no children OTHER than the button to add an item.
190
+
191
+ expect(c.childNodes.length).toEqual(1);
192
+ buttonGroup = c.childNodes[0];
193
+ expect(buttonGroup.tagName).toEqual('DIV');
194
+ expect(buttonGroup.classList).toContain('hods-button-group');
195
+ button = buttonGroup.childNodes[0];
196
+ expect(button.tagName).toEqual('BUTTON');
197
+ expect(button.classList).toContain('hods-button');
198
+ expect(button.classList).toContain('hods-button--secondary');
199
+ expect(button.textContent).toContain(_models.CollectionLabels.add);
200
+
201
+ case 14:
202
+ case "end":
203
+ return _context3.stop();
204
+ }
205
+ }
206
+ }, _callee3);
207
+ })));
208
+ it('should handle a collection label appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
209
+ var LABEL, COLLECTION, _renderWithValidation4, container, c, _c$childNodes, title, buttonGroup, button;
210
+
211
+ return regeneratorRuntime.wrap(function _callee4$(_context4) {
212
+ while (1) {
213
+ switch (_context4.prev = _context4.next) {
214
+ case 0:
215
+ LABEL = 'Alpha Collection';
216
+ COLLECTION = {
217
+ id: ID,
218
+ fieldId: ID,
219
+ type: _models.ComponentTypes.COLLECTION,
220
+ item: [TEXT_COMPONENT],
221
+ label: LABEL
222
+ };
223
+ _renderWithValidation4 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
224
+ component: COLLECTION
225
+ })), container = _renderWithValidation4.container; // Check the container itself.
226
+
227
+ c = container.childNodes[0];
228
+ expect(c.tagName).toEqual('DIV');
229
+ expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now make sure it has no children OTHER than the button to add an item.
230
+
231
+ expect(c.childNodes.length).toEqual(2);
232
+ _c$childNodes = _slicedToArray(c.childNodes, 2), title = _c$childNodes[0], buttonGroup = _c$childNodes[1];
233
+ expect(title.tagName).toEqual('LABEL');
234
+ expect(title.classList).toContain("".concat(_Collection.DEFAULT_CLASS, "__title"));
235
+ expect(title.getAttribute('for')).toEqual(ID);
236
+ expect(title.textContent).toContain(LABEL);
237
+ expect(buttonGroup.tagName).toEqual('DIV');
238
+ expect(buttonGroup.classList).toContain('hods-button-group');
239
+ button = buttonGroup.childNodes[0];
240
+ expect(button.tagName).toEqual('BUTTON');
241
+ expect(button.classList).toContain('hods-button');
242
+ expect(button.classList).toContain('hods-button--secondary');
243
+ expect(button.textContent).toContain(_models.CollectionLabels.add);
244
+
245
+ case 19:
246
+ case "end":
247
+ return _context4.stop();
248
+ }
249
+ }
250
+ }, _callee4);
251
+ })));
252
+ it('should handle the addition and removal of an item', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() {
253
+ var COLLECTION, container, c, addButton, item, label, removeButton;
254
+ return regeneratorRuntime.wrap(function _callee6$(_context6) {
255
+ while (1) {
256
+ switch (_context6.prev = _context6.next) {
257
+ case 0:
258
+ COLLECTION = {
259
+ id: ID,
260
+ fieldId: ID,
261
+ type: _models.ComponentTypes.COLLECTION,
262
+ item: [TEXT_COMPONENT]
263
+ };
264
+ container = document.createElement('div');
265
+ document.body.appendChild(container);
266
+ _context6.next = 5;
267
+ return (0, _testUtils.act)( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
268
+ return regeneratorRuntime.wrap(function _callee5$(_context5) {
269
+ while (1) {
270
+ switch (_context5.prev = _context5.next) {
271
+ case 0:
272
+ (0, _setupTests.renderDomWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormComponent.default, {
273
+ component: COLLECTION
274
+ }), container);
275
+
276
+ case 1:
277
+ case "end":
278
+ return _context5.stop();
279
+ }
280
+ }
281
+ }, _callee5);
282
+ })));
283
+
284
+ case 5:
285
+ // Check the container itself.
286
+ c = container.childNodes[0];
287
+ expect(c.tagName).toEqual('DIV');
288
+ expect(c.classList).toContain(_Collection.DEFAULT_CLASS); // And now make sure it has no children OTHER than the button to add an item.
289
+
290
+ expect(c.childNodes.length).toEqual(1); // Get hold of that "Add another" button and click it.
291
+
292
+ addButton = c.childNodes[0].childNodes[0];
293
+
294
+ _react.fireEvent.click(addButton, {}); // Make sure an item has been added.
295
+
296
+
297
+ expect(c.childNodes.length).toEqual(2);
298
+ item = c.childNodes[0];
299
+ label = item.childNodes[0];
300
+ expect(label.textContent).toContain(_utils.default.interpolateString(_models.CollectionLabels.item, {
301
+ index: 1
302
+ })); // Get hold of the newly-add item's "Remove" button.
303
+
304
+ removeButton = label.childNodes[1];
305
+ expect(removeButton.tagName).toEqual('BUTTON');
306
+ expect(removeButton.classList).toContain('hods-button--secondary');
307
+ expect(removeButton.textContent).toContain(_models.CollectionLabels.remove); // Click the "Remove" button
308
+
309
+ _react.fireEvent.click(removeButton, {}); // Make sure the item has been removed.
310
+
311
+
312
+ expect(c.childNodes.length).toEqual(1);
313
+ expect(c.childNodes[0].classList).toContain('hods-button-group');
314
+
315
+ case 22:
316
+ case "end":
317
+ return _context6.stop();
318
+ }
319
+ }
320
+ }, _callee6);
321
+ })));
322
+ });
@@ -246,20 +246,43 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
246
246
  var onPageAction = function onPageAction(action, patch) {
247
247
  // Check to see whether the action is able to proceed, which in
248
248
  // in the case of a submission will validate the fields in the page.
249
+ if (action.type === _models.PageAction.TYPES.SUBMIT) {
250
+ if (_helpers.default.canCYASubmit(pages, validate.pages)) {
251
+ // Submit.
252
+ var submissionData = _utils.default.Format.form({
253
+ pages: pages,
254
+ components: components
255
+ }, _objectSpread({}, data), _models.EventTypes.SUBMIT);
256
+
257
+ submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, submissionData, currentTask, true);
258
+ setData(submissionData); // Now submit the data to the backend...
259
+
260
+ hooks.onSubmit(action.type, submissionData, function () {
261
+ return hooks.onFormComplete();
262
+ }, function (errors) {
263
+ return _handlers.default.submissionError(errors, addErrors);
264
+ });
265
+ }
266
+ } // Check to see whether the action is able to proceed, which in
267
+ // in the case of a submission will validate the fields in the page.
268
+
269
+
249
270
  if (_helpers.default.canActionProceed(action, formState.page, validate.page)) {
271
+ patch = _helpers.default.cleanHiddenNestedData(patch, formState.page);
272
+
250
273
  if (action.type === _models.PageAction.TYPES.NAVIGATE) {
251
274
  _handlers.default.navigate(action, pageId, onPageChange);
252
275
  } else {
253
276
  // Save draft or submit.
254
- var submissionData = _utils.default.Format.form({
277
+ var _submissionData = _utils.default.Format.form({
255
278
  pages: pages,
256
279
  components: components
257
280
  }, _objectSpread(_objectSpread({}, data), patch), _models.EventTypes.SUBMIT);
258
281
 
259
- submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, submissionData, currentTask, true);
282
+ _submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, _submissionData, currentTask, true);
260
283
 
261
284
  if (patch) {
262
- setData(submissionData);
285
+ setData(_submissionData);
263
286
  }
264
287
 
265
288
  var pageUpdate = function pageUpdate(next) {
@@ -275,10 +298,10 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
275
298
  } // Now submit the data to the backend...
276
299
 
277
300
 
278
- hooks.onSubmit(action.type, submissionData, function (response) {
301
+ hooks.onSubmit(action.type, _submissionData, function (response) {
279
302
  // The backend response may well contain data we need so apply it...
280
303
  // ... but this needs to happen in a useEffect, not right away.
281
- var sData = _objectSpread(_objectSpread({}, submissionData), response);
304
+ var sData = _objectSpread(_objectSpread({}, _submissionData), response);
282
305
 
283
306
  setSubmitted({
284
307
  data: sData
@@ -341,14 +364,14 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
341
364
 
342
365
  if (action.type === _models.PageAction.TYPES.SAVE_AND_CONTINUE && hub === _models.HubFormats.TASK) {
343
366
  if (_helpers.default.canCYASubmit(currentTask.fullPages, validate.pages)) {
344
- var _submissionData = _utils.default.Format.form({
367
+ var _submissionData2 = _utils.default.Format.form({
345
368
  pages: pages,
346
369
  components: components
347
370
  }, _objectSpread({}, data), _models.EventTypes.SUBMIT);
348
371
 
349
- _submissionData.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, _submissionData, currentTask, true);
350
- setData(_submissionData);
351
- hooks.onSubmit(action.type, _submissionData, function () {
372
+ _submissionData2.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, _submissionData2, currentTask, true);
373
+ setData(_submissionData2);
374
+ hooks.onSubmit(action.type, _submissionData2, function () {
352
375
  return onPageChange(_models.FormPages.HUB);
353
376
  }, function (errors) {
354
377
  return _handlers.default.submissionError(errors, addErrors);
@@ -358,14 +381,14 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
358
381
 
359
382
  if (action.type === _models.PageAction.TYPES.SAVE_AND_RETURN) {
360
383
  if (_helpers.default.canCYASubmit(currentTask.fullPages, validate.pages)) {
361
- var _submissionData2 = _utils.default.Format.form({
384
+ var _submissionData3 = _utils.default.Format.form({
362
385
  pages: pages,
363
386
  components: components
364
387
  }, _objectSpread({}, data), _models.EventTypes.SUBMIT);
365
388
 
366
- _submissionData2.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, _submissionData2, currentTask);
367
- setData(_submissionData2);
368
- hooks.onSubmit(action.type, _submissionData2, function () {
389
+ _submissionData3.formStatus = _helpers.default.getSubmissionStatus(type, pages, pageId, action, _submissionData3, currentTask);
390
+ setData(_submissionData3);
391
+ hooks.onSubmit(action.type, _submissionData3, function () {
369
392
  if (type === _models.FormTypes.TASK) {
370
393
  onPageChange(undefined);
371
394
  } else {
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var parentComponents = ['radios'];
8
+
9
+ var cleanHiddenNestedData = function cleanHiddenNestedData(patch, page) {
10
+ page.components.forEach(function (component) {
11
+ if (!parentComponents.includes(component.type)) {
12
+ return;
13
+ }
14
+
15
+ var idsToDelete = getIdsToDelete(component, patch[component.id]);
16
+ idsToDelete.forEach(function (id) {
17
+ delete patch[id];
18
+ });
19
+ });
20
+ return patch;
21
+ };
22
+
23
+ function getIdsToDelete(component, selectedValue) {
24
+ var _component$data, _component$data$optio;
25
+
26
+ var idsToDelete = [];
27
+ component === null || component === void 0 ? void 0 : (_component$data = component.data) === null || _component$data === void 0 ? void 0 : (_component$data$optio = _component$data.options) === null || _component$data$optio === void 0 ? void 0 : _component$data$optio.forEach(function (option) {
28
+ if (option.value !== selectedValue && option.nested) {
29
+ option.nested.forEach(function (nested) {
30
+ idsToDelete.push(nested.id);
31
+ });
32
+ }
33
+ });
34
+ return idsToDelete;
35
+ }
36
+
37
+ var _default = cleanHiddenNestedData;
38
+ exports.default = _default;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ var _cleanHiddenNestedData = _interopRequireDefault(require("./cleanHiddenNestedData"));
4
+
5
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6
+
7
+ // Local imports
8
+ describe('components', function () {
9
+ describe('FormRenderer', function () {
10
+ describe('helpers', function () {
11
+ describe('cleanHiddenNestedData', function () {
12
+ it('remove data corresponding to hidden nested components', function () {
13
+ var patch = {
14
+ parent: 'option2',
15
+ nested1: 'should not be included',
16
+ nested2: 'should be included'
17
+ };
18
+ var page = {
19
+ id: 'page',
20
+ name: 'page',
21
+ title: 'Page',
22
+ components: [{
23
+ id: 'parent',
24
+ fieldId: 'parent',
25
+ type: 'radios',
26
+ data: {
27
+ options: [{
28
+ value: 'option1',
29
+ nested: [{
30
+ id: 'nested1',
31
+ fieldId: 'nested1'
32
+ }]
33
+ }, {
34
+ value: 'option2',
35
+ nested: [{
36
+ id: 'nested2',
37
+ fieldId: 'nested2'
38
+ }]
39
+ }]
40
+ }
41
+ }]
42
+ };
43
+ var updatedPatch = (0, _cleanHiddenNestedData.default)(patch, page);
44
+ expect(updatedPatch['nested1']).toBeFalsy();
45
+ expect(updatedPatch['nested2']).toBeTruthy();
46
+ });
47
+ });
48
+ });
49
+ });
50
+ });
@@ -9,6 +9,8 @@ var _canActionProceed = _interopRequireDefault(require("./canActionProceed"));
9
9
 
10
10
  var _canCYASubmit = _interopRequireDefault(require("./canCYASubmit"));
11
11
 
12
+ var _cleanHiddenNestedData = _interopRequireDefault(require("./cleanHiddenNestedData"));
13
+
12
14
  var _getFormState = _interopRequireDefault(require("./getFormState"));
13
15
 
14
16
  var _getNextPageId = _interopRequireDefault(require("./getNextPageId"));
@@ -25,6 +27,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
25
27
  var helpers = {
26
28
  canActionProceed: _canActionProceed.default,
27
29
  canCYASubmit: _canCYASubmit.default,
30
+ cleanHiddenNestedData: _cleanHiddenNestedData.default,
28
31
  getFormState: _getFormState.default,
29
32
  getNextPageId: _getNextPageId.default,
30
33
  getPage: _getPage.default,
@@ -1,11 +1,17 @@
1
1
  "use strict";
2
2
 
3
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
+
3
5
  Object.defineProperty(exports, "__esModule", {
4
6
  value: true
5
7
  });
6
8
  exports.default = exports.HooksContext = exports.ALLOWED_HOOKS = void 0;
7
9
 
8
- var _react = require("react");
10
+ var _react = _interopRequireWildcard(require("react"));
11
+
12
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
13
+
14
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
9
15
 
10
16
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
11
17
 
@@ -78,7 +84,7 @@ var HooksContextProvider = function HooksContextProvider(_ref) {
78
84
  }
79
85
  };
80
86
 
81
- return /*#__PURE__*/React.createElement(HooksContext.Provider, {
87
+ return /*#__PURE__*/_react.default.createElement(HooksContext.Provider, {
82
88
  value: {
83
89
  hooks: hooks,
84
90
  addHook: addHook,
@@ -49,7 +49,9 @@ var setNestedValue = function setNestedValue(component, page) {
49
49
  (_component$data = component.data) === null || _component$data === void 0 ? void 0 : (_component$data$optio = _component$data.options) === null || _component$data$optio === void 0 ? void 0 : _component$data$optio.forEach(function (option, index) {
50
50
  //check if option is selected and has nested component
51
51
  if (page.formData[component.id] === option.value && option.nested) {
52
- component.data.options[index].nested.value = page.formData[option.nested.id];
52
+ option.nested.forEach(function (child) {
53
+ child.value = page.formData[child.id];
54
+ });
53
55
  }
54
56
  });
55
57
  };
@@ -162,14 +162,14 @@ describe('utils', function () {
162
162
  data: {
163
163
  options: [{
164
164
  value: SELECTED_VALUE,
165
- nested: {
165
+ nested: [{
166
166
  id: NESTED_ID
167
- }
167
+ }]
168
168
  }]
169
169
  }
170
170
  };
171
171
  var ROW = (0, _getCYARow.default)(PAGE, COMPONENT, function () {});
172
- expect(ROW.component.data.options[0].nested.value).toEqual(NESTED_VALUE);
172
+ expect(ROW.component.data.options[0].nested[0].value).toEqual(NESTED_VALUE);
173
173
  });
174
174
  });
175
175
  });
@@ -19,7 +19,7 @@ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToAr
19
19
 
20
20
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
21
21
 
22
- var JSON_ONLY_PROPERTIES = ['source', 'use', 'show_when', 'options', 'additionalValidation', 'full_path', 'shown', 'formData'];
22
+ var JSON_ONLY_PROPERTIES = ['source', 'use', 'show_when', 'options', 'additionalValidation', 'full_path', 'formData'];
23
23
  /**
24
24
  * This method removes and properties that are entirely specific to the JSON
25
25
  * configuration and that should not be used as HTML attributes.