@ukhomeoffice/cop-react-form-renderer 4.33.1 → 4.34.0

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.
@@ -159,7 +159,7 @@ var CheckYourAnswers = function CheckYourAnswers(_ref) {
159
159
  });
160
160
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("h3", {
161
161
  className: "govuk-heading-m govuk-!-margin-top-8 govuk-!-margin-bottom-0"
162
- }, filterPages.length > 0 && task.name), filterPages.map(function (page, pageIndex, array) {
162
+ }, filterPages.length > 0 && task.name), filterPages.map(function (page, pageIndex) {
163
163
  var hideActionButtons;
164
164
  isGroup(page.id) ? hideActionButtons = true : hideActionButtons = noChangeAction;
165
165
  return /*#__PURE__*/_react.default.createElement(_react.Fragment, {
@@ -203,7 +203,7 @@ var CheckYourAnswers = function CheckYourAnswers(_ref) {
203
203
  CheckYourAnswers.propTypes = {
204
204
  title: _propTypes.default.string.isRequired,
205
205
  pages: _propTypes.default.arrayOf(_propTypes.default.object).isRequired,
206
- actions: _propTypes.default.arrayOf(_propTypes.default.object),
206
+ actions: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.string])),
207
207
  onAction: _propTypes.default.func.isRequired,
208
208
  onRowAction: _propTypes.default.func.isRequired,
209
209
  hide_page_titles: _propTypes.default.bool,
@@ -73,14 +73,13 @@ var FormPage = function FormPage(_ref) {
73
73
  _useState4 = _slicedToArray(_useState3, 2),
74
74
  patchLabel = _useState4[0],
75
75
  setPatchLabel = _useState4[1];
76
-
77
- var docTitle = (0, _react.useState)(document.title);
78
76
  /**
79
77
  * Handle the state of the data directly within the page.
80
78
  * This is so that the overall form data isn't affected until such
81
79
  * time as the onAction handler is invoked.
82
80
  */
83
81
 
82
+
84
83
  var onPageChange = function onPageChange(_ref2) {
85
84
  var target = _ref2.target;
86
85
  page.formData[target.name] = target.value;
@@ -93,8 +92,9 @@ var FormPage = function FormPage(_ref) {
93
92
  };
94
93
 
95
94
  (0, _react.useEffect)(function () {
96
- document.title = errors.length > 0 ? 'Error: ' + docTitle : docTitle;
97
- }, [errors, docTitle]);
95
+ var coreDocTitle = document.title.replace('Error: ', '');
96
+ document.title = errors.length > 0 ? 'Error: ' + coreDocTitle : coreDocTitle;
97
+ }, [errors]);
98
98
 
99
99
  var classes = _utils.default.classBuilder(classBlock, classModifiers, className);
100
100
 
@@ -258,7 +258,9 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
258
258
  setData(submitted.data);
259
259
  setSubmitted(undefined);
260
260
  }
261
- }, [submitted, setData, setSubmitted]); // Update task list pages with form data and update states
261
+ }, [submitted, setData, setSubmitted]);
262
+ var theSections = _hub === null || _hub === void 0 ? void 0 : _hub.sections;
263
+ var nonSequential = _hub === null || _hub === void 0 ? void 0 : _hub.nonSequential; // Update task list pages with form data and update states
262
264
 
263
265
  (0, _react.useEffect)(function () {
264
266
  var pages = currentTask.fullPages;
@@ -268,8 +270,6 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
268
270
  if (page) {
269
271
  page.formData = data;
270
272
  }
271
-
272
- ;
273
273
  });
274
274
  setCurrentTask(function (prev) {
275
275
  return _objectSpread(_objectSpread({}, prev), {}, {
@@ -278,18 +278,20 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
278
278
  });
279
279
  }
280
280
 
281
- if (hubDetails !== null && hubDetails !== void 0 && hubDetails.sections) {
281
+ if (theSections) {
282
282
  var _data$formStatus2;
283
283
 
284
284
  var tasks = (data === null || data === void 0 ? void 0 : (_data$formStatus2 = data.formStatus) === null || _data$formStatus2 === void 0 ? void 0 : _data$formStatus2.tasks) || {};
285
285
 
286
- var updatedSections = _helpers.default.getUpdatedSectionStates(hubDetails.sections, tasks, hubDetails.nonSequential);
286
+ var updatedSections = _helpers.default.getUpdatedSectionStates(theSections, tasks, nonSequential);
287
287
 
288
288
  setHubDetails(function (prev) {
289
- return _objectSpread(_objectSpread({}, prev), updatedSections);
289
+ return _objectSpread(_objectSpread({}, prev), {}, {
290
+ sections: [].concat(updatedSections)
291
+ });
290
292
  });
291
293
  }
292
- }, [currentTask.fullPages, data, hubDetails === null || hubDetails === void 0 ? void 0 : hubDetails.sections, hubDetails === null || hubDetails === void 0 ? void 0 : hubDetails.nonSequential]);
294
+ }, [currentTask.fullPages, data, theSections, nonSequential]);
293
295
 
294
296
  var onPageChange = function onPageChange(newPageId) {
295
297
  var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -7,9 +7,23 @@ exports.default = void 0;
7
7
 
8
8
  var _models = require("../../../models");
9
9
 
10
- var getCurrentTaskState = function getCurrentTaskState(_ref, defaultState) {
10
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
11
+
12
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
13
+
14
+ 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; }
15
+
16
+ /**
17
+ *
18
+ * @param {boolean} complete - true if task complete
19
+ * @param {boolean} currentPage - true if current page
20
+ * @param {TaskStates.TYPES|string} defaultState - default state to set task
21
+ * @returns {TaskStates.TYPES|string} current task state
22
+ */
23
+ var getCurrentTaskState = function getCurrentTaskState(_ref) {
11
24
  var complete = _ref.complete,
12
25
  currentPage = _ref.currentPage;
26
+ var defaultState = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _models.TaskStates.TYPES.NOT_STARTED;
13
27
 
14
28
  if (complete) {
15
29
  return _models.TaskStates.TYPES.COMPLETE;
@@ -21,6 +35,13 @@ var getCurrentTaskState = function getCurrentTaskState(_ref, defaultState) {
21
35
 
22
36
  return defaultState;
23
37
  };
38
+ /**
39
+ * check if dependent tasks have been completed
40
+ * @param tasks - list of tasks
41
+ * @param mustBeComplete - tasks which are depended on
42
+ * @returns {boolean} true if dependent tasks complete
43
+ */
44
+
24
45
 
25
46
  var allDependentTasksComplete = function allDependentTasksComplete(tasks, mustBeComplete) {
26
47
  return mustBeComplete.reduce(function (allComplete, taskName) {
@@ -30,66 +51,73 @@ var allDependentTasksComplete = function allDependentTasksComplete(tasks, mustBe
30
51
  }, true);
31
52
  };
32
53
  /**
33
- * Updates the given task list sections with the latest states
34
- * @param {object} sections The JSON defining the sections in the task list
35
- * @param {object} tasks object with entry for each task containing currentPage and complete boolean flag
36
- * {
37
- "TaskName": {
38
- "complete": true,
39
- "currentPage": "pageId"
40
- }
41
- }
42
- * @returns An JSON representation of the task list sections with up to date states
54
+ * return updated task state
55
+ * @param {object} task - current task object
56
+ * @param {number} taskIndex - order number of task in list
57
+ * @param {object[]} taskList - list of tasks (associated with section)
58
+ * @param tasks - list of task state
59
+ * @param {boolean} nonSequential - set if tasks can be performed out of order
60
+ * @param {boolean} allowFirst true if first task in list can be accepted
61
+ * @returns {TYPES|string} new state
43
62
  */
44
63
 
45
64
 
46
- var getUpdatedSequentialStates = function getUpdatedSequentialStates(sections, tasks) {
47
- return sections.map(function (section, sectionIndex, sectionArray) {
48
- return section.tasks.map(function (task, taskIndex, taskArray) {
49
- if (tasks[task.name]) {
50
- task.state = getCurrentTaskState(tasks[task.name], task.state);
51
- } else {
52
- var _taskArray, _sectionArray, _sectionArray$tasks$s;
53
-
54
- if (taskIndex === 0 && sectionIndex === 0 || //First task in tasklist
55
- ((_taskArray = taskArray[taskIndex - 1]) === null || _taskArray === void 0 ? void 0 : _taskArray.state) === _models.TaskStates.TYPES.COMPLETE || //any task after a complete task in same section
56
- taskIndex === 0 && ((_sectionArray = sectionArray[sectionIndex - 1]) === null || _sectionArray === void 0 ? void 0 : (_sectionArray$tasks$s = _sectionArray.tasks.slice(-1)[0]) === null || _sectionArray$tasks$s === void 0 ? void 0 : _sectionArray$tasks$s.state) === _models.TaskStates.TYPES.COMPLETE //any task after a complete task in the preceeding section
57
- ) {
58
- task.state = _models.TaskStates.TYPES.NOT_STARTED;
59
- } else {
60
- task.state = _models.TaskStates.TYPES.CANNOT_START_YET;
61
- }
62
- }
63
-
64
- return task;
65
- });
66
- });
65
+ var updateTaskState = function updateTaskState(task, taskIndex, taskList, tasks) {
66
+ var _taskList;
67
+
68
+ var nonSequential = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
69
+ var allowFirst = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true;
70
+
71
+ if (tasks[task.name]) {
72
+ return getCurrentTaskState(tasks[task.name], task.state);
73
+ }
74
+
75
+ return nonSequential ? task.depends_on && !allDependentTasksComplete(tasks, task.depends_on) ? _models.TaskStates.TYPES.CANNOT_START_YET : _models.TaskStates.TYPES.NOT_STARTED : ( // First task in taskList
76
+ taskIndex ? // any task after a complete task in same section
77
+ ((_taskList = taskList[taskIndex - 1]) === null || _taskList === void 0 ? void 0 : _taskList.state) === _models.TaskStates.TYPES.COMPLETE : allowFirst) ? _models.TaskStates.TYPES.NOT_STARTED : _models.TaskStates.TYPES.CANNOT_START_YET;
67
78
  };
79
+ /**
80
+ * update all tasks in section with new state.
81
+ * note use of clone and forEach as some tasks depend on previous update
82
+ * @param {object} section - section to be processed
83
+ * @param {number} sectionIndex - index number of current section
84
+ * @param tasks - task updates
85
+ * @param nonSequential - true if non-sequential task performance allowed
86
+ * @param allowFirst - true if first task can be started
87
+ * @returns {object} - updated section
88
+ */
68
89
 
69
- var getUpdatedNonSequentialStates = function getUpdatedNonSequentialStates(sections, tasks) {
70
- return sections.map(function (section) {
71
- return section.tasks.map(function (task) {
72
- if (tasks[task.name]) {
73
- task.state = getCurrentTaskState(tasks[task.name], task.state);
74
- } else if (task.depends_on && !allDependentTasksComplete(tasks, task.depends_on)) {
75
- task.state = _models.TaskStates.TYPES.CANNOT_START_YET;
76
- } else {
77
- task.state = _models.TaskStates.TYPES.NOT_STARTED;
78
- }
79
-
80
- return task;
81
- });
90
+
91
+ var updateTasks = function updateTasks(section, sectionIndex, tasks, nonSequential, allowFirst) {
92
+ var clone = section.tasks.map(function (a) {
93
+ return _objectSpread({}, a);
94
+ });
95
+ clone.forEach(function (task, taskIndex, taskList) {
96
+ task.state = updateTaskState(task, taskIndex, taskList, tasks, nonSequential, allowFirst);
82
97
  });
98
+ return clone;
83
99
  };
100
+ /**
101
+ * update task states in sections
102
+ * @param {object[]} sections - array of sections
103
+ * @param {object} tasks - update task states
104
+ * @param {boolean} nonSequential - true if tasks can be performed non-sequentially
105
+ * @returns {object[]} - updated sections - note this is a clone
106
+ */
107
+
84
108
 
85
109
  var getUpdatedSectionStates = function getUpdatedSectionStates(sections, tasks) {
86
110
  var nonSequential = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
111
+ var clone = sections.map(function (a) {
112
+ return _objectSpread({}, a);
113
+ });
114
+ clone.forEach(function (section, sectionIndex, sectionList) {
115
+ var _sectionList, _sectionList$tasks$sl;
87
116
 
88
- if (nonSequential === true) {
89
- return getUpdatedNonSequentialStates(sections, tasks);
90
- }
91
-
92
- return getUpdatedSequentialStates(sections, tasks);
117
+ var allowFirst = sectionIndex === 0 || ((_sectionList = sectionList[sectionIndex - 1]) === null || _sectionList === void 0 ? void 0 : (_sectionList$tasks$sl = _sectionList.tasks.slice(-1)[0]) === null || _sectionList$tasks$sl === void 0 ? void 0 : _sectionList$tasks$sl.state) === _models.TaskStates.TYPES.COMPLETE;
118
+ section.tasks = updateTasks(section, sectionIndex, tasks, nonSequential, allowFirst);
119
+ });
120
+ return clone;
93
121
  };
94
122
 
95
123
  var _default = getUpdatedSectionStates;
@@ -33,11 +33,11 @@ describe('components.FormRenderer.helpers.getUpdatedSectionStates', function ()
33
33
  }]
34
34
  }];
35
35
  var updatedSections = (0, _getUpdatedSectionStates.default)(SECTIONS, {});
36
- expect(updatedSections[0][0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED);
37
- expect(updatedSections[0][1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
38
- expect(updatedSections[1][0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
39
- expect(updatedSections[1][1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
40
- expect(updatedSections[1][2].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
36
+ expect(updatedSections[0].tasks[0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED);
37
+ expect(updatedSections[0].tasks[1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
38
+ expect(updatedSections[1].tasks[0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
39
+ expect(updatedSections[1].tasks[1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
40
+ expect(updatedSections[1].tasks[2].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
41
41
  });
42
42
  it("should set tasks after any '".concat(_models.TaskStates.TYPES.COMPLETE, "' ones to '").concat(_models.TaskStates.TYPES.NOT_STARTED, "'"), function () {
43
43
  var SECTIONS = [{
@@ -56,8 +56,8 @@ describe('components.FormRenderer.helpers.getUpdatedSectionStates', function ()
56
56
  }
57
57
  };
58
58
  var updatedSections = (0, _getUpdatedSectionStates.default)(SECTIONS, TASKS);
59
- expect(updatedSections[0][0].state).toEqual(_models.TaskStates.TYPES.COMPLETE);
60
- expect(updatedSections[0][1].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED);
59
+ expect(updatedSections[0].tasks[0].state).toEqual(_models.TaskStates.TYPES.COMPLETE);
60
+ expect(updatedSections[0].tasks[1].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED);
61
61
  });
62
62
  it("should set tasks after any '".concat(_models.TaskStates.TYPES.COMPLETE, "' ones to '").concat(_models.TaskStates.TYPES.NOT_STARTED, " across different sections'"), function () {
63
63
  var SECTIONS = [{
@@ -88,10 +88,10 @@ describe('components.FormRenderer.helpers.getUpdatedSectionStates', function ()
88
88
  }
89
89
  };
90
90
  var updatedSections = (0, _getUpdatedSectionStates.default)(SECTIONS, TASKS);
91
- expect(updatedSections[0][0].state).toEqual(_models.TaskStates.TYPES.COMPLETE);
92
- expect(updatedSections[0][1].state).toEqual(_models.TaskStates.TYPES.COMPLETE);
93
- expect(updatedSections[1][0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED);
94
- expect(updatedSections[1][1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
91
+ expect(updatedSections[0].tasks[0].state).toEqual(_models.TaskStates.TYPES.COMPLETE);
92
+ expect(updatedSections[0].tasks[1].state).toEqual(_models.TaskStates.TYPES.COMPLETE);
93
+ expect(updatedSections[1].tasks[0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED);
94
+ expect(updatedSections[1].tasks[1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
95
95
  });
96
96
  it("should set tasks to '".concat(_models.TaskStates.TYPES.IN_PROGRESS, "' if they have a current page but are not complete"), function () {
97
97
  var SECTIONS = [{
@@ -111,8 +111,8 @@ describe('components.FormRenderer.helpers.getUpdatedSectionStates', function ()
111
111
  }
112
112
  };
113
113
  var updatedSections = (0, _getUpdatedSectionStates.default)(SECTIONS, TASKS);
114
- expect(updatedSections[0][0].state).toEqual(_models.TaskStates.TYPES.IN_PROGRESS);
115
- expect(updatedSections[0][1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
114
+ expect(updatedSections[0].tasks[0].state).toEqual(_models.TaskStates.TYPES.IN_PROGRESS);
115
+ expect(updatedSections[0].tasks[1].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET);
116
116
  });
117
117
  });
118
118
  describe('non-sequential tasks', function () {
@@ -138,13 +138,13 @@ describe('components.FormRenderer.helpers.getUpdatedSectionStates', function ()
138
138
  }];
139
139
  it("should set all states to '".concat(_models.TaskStates.TYPES.NOT_STARTED, "', except any that depend on others"), function () {
140
140
  var RESULT = (0, _getUpdatedSectionStates.default)(SECTIONS, {}, NON_SEQUENTIAL);
141
- expect(RESULT[0][0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Alpha
141
+ expect(RESULT[0].tasks[0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Alpha
142
142
 
143
- expect(RESULT[0][1].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Bravo
143
+ expect(RESULT[0].tasks[1].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Bravo
144
144
 
145
- expect(RESULT[1][0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET); // Charlie
145
+ expect(RESULT[1].tasks[0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET); // Charlie
146
146
 
147
- expect(RESULT[2][0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Delta
147
+ expect(RESULT[2].tasks[0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Delta
148
148
  });
149
149
  it('should keep dependent state unable to start if any dependencies are not complete', function () {
150
150
  var ALPHA_COMPLETE = (0, _getUpdatedSectionStates.default)(SECTIONS, {
@@ -152,14 +152,14 @@ describe('components.FormRenderer.helpers.getUpdatedSectionStates', function ()
152
152
  complete: true
153
153
  }
154
154
  }, NON_SEQUENTIAL);
155
- expect(ALPHA_COMPLETE[1][0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET); // Charlie
155
+ expect(ALPHA_COMPLETE[1].tasks[0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET); // Charlie
156
156
 
157
157
  var BRAVO_COMPLETE = (0, _getUpdatedSectionStates.default)(SECTIONS, {
158
158
  Bravo: {
159
159
  complete: true
160
160
  }
161
161
  }, NON_SEQUENTIAL);
162
- expect(BRAVO_COMPLETE[1][0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET); // Charlie
162
+ expect(BRAVO_COMPLETE[1].tasks[0].state).toEqual(_models.TaskStates.TYPES.CANNOT_START_YET); // Charlie
163
163
  });
164
164
  it('should allow dependent state to start if all dependencies are complete', function () {
165
165
  var TASKS = {
@@ -172,9 +172,9 @@ describe('components.FormRenderer.helpers.getUpdatedSectionStates', function ()
172
172
  'Delta': {}
173
173
  };
174
174
  var RESULT = (0, _getUpdatedSectionStates.default)(SECTIONS, TASKS, NON_SEQUENTIAL);
175
- expect(RESULT[1][0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Charlie
175
+ expect(RESULT[1].tasks[0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Charlie
176
176
 
177
- expect(RESULT[2][0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Delta
177
+ expect(RESULT[2].tasks[0].state).toEqual(_models.TaskStates.TYPES.NOT_STARTED); // Delta
178
178
  });
179
179
  });
180
180
  });
@@ -31,6 +31,18 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
31
31
 
32
32
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
33
33
 
34
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
35
+
36
+ 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."); }
37
+
38
+ 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); }
39
+
40
+ 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; }
41
+
42
+ 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; }
43
+
44
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
45
+
34
46
  function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
35
47
 
36
48
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
@@ -55,14 +67,16 @@ var TaskList = function TaskList(_ref) {
55
67
  var classes = _copReactComponents.Utils.classBuilder(classBlock, classModifiers, className); //TODO state will be retrieved from a document in S3 rather than given in the component definition, covered under COP-9885
56
68
 
57
69
 
58
- var numberOfCompleteSections = sections.reduce(function (totalComplete, currentSection) {
59
- return totalComplete + currentSection.tasks.filter(function (t) {
70
+ var _sections$reduce = sections.reduce(function (acc, current) {
71
+ var _current$tasks$filter, _current$tasks, _current$tasks$length, _current$tasks2;
72
+
73
+ return [acc[0] + ((_current$tasks$filter = (_current$tasks = current.tasks) === null || _current$tasks === void 0 ? void 0 : _current$tasks.filter(function (t) {
60
74
  return t.state === _models.TaskStates.TYPES.COMPLETE;
61
- }).length;
62
- }, 0);
63
- var numberOfSections = sections.reduce(function (totalSections, current) {
64
- return totalSections + current.tasks.length;
65
- }, 0);
75
+ }).length) !== null && _current$tasks$filter !== void 0 ? _current$tasks$filter : 0), acc[1] + ((_current$tasks$length = (_current$tasks2 = current.tasks) === null || _current$tasks2 === void 0 ? void 0 : _current$tasks2.length) !== null && _current$tasks$length !== void 0 ? _current$tasks$length : 0)];
76
+ }, [0, 0]),
77
+ _sections$reduce2 = _slicedToArray(_sections$reduce, 2),
78
+ completeSections = _sections$reduce2[0],
79
+ totalSections = _sections$reduce2[1];
66
80
 
67
81
  var onClick = function onClick(task) {
68
82
  if (typeof onTaskAction === 'function') {
@@ -78,13 +92,13 @@ var TaskList = function TaskList(_ref) {
78
92
  className: "tasklist-summary"
79
93
  }, "".concat(refTitle))), /*#__PURE__*/_react.default.createElement("p", {
80
94
  className: "govuk-body govuk-!-font-weight-regular"
81
- }, "".concat(refNumber))), numberOfSections !== numberOfCompleteSections && /*#__PURE__*/_react.default.createElement("p", {
95
+ }, "".concat(refNumber))), totalSections !== completeSections && /*#__PURE__*/_react.default.createElement("p", {
82
96
  className: "govuk-body govuk-!-margin-bottom-0"
83
97
  }, /*#__PURE__*/_react.default.createElement("strong", {
84
98
  className: "tasklist-summary"
85
99
  }, incompleteTitle)), /*#__PURE__*/_react.default.createElement("p", {
86
100
  className: "govuk-body govuk-!-margin-bottom-7"
87
- }, "You have completed ".concat(numberOfCompleteSections, " of ").concat(numberOfSections, " sections")), sections.map(function (section, index) {
101
+ }, "You have completed ".concat(completeSections, " of ").concat(totalSections, " sections")), sections.map(function (section, index) {
88
102
  return /*#__PURE__*/_react.default.createElement(_react.Fragment, {
89
103
  key: "".concat(section.name)
90
104
  }, /*#__PURE__*/_react.default.createElement("h2", {
@@ -14,8 +14,18 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
14
14
 
15
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
16
 
17
- // Global imports
18
- // Local imports
17
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
18
+
19
+ 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."); }
20
+
21
+ 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); }
22
+
23
+ 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; }
24
+
25
+ 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; }
26
+
27
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
28
+
19
29
  describe('components', function () {
20
30
  describe('TaskList', function () {
21
31
  it('should render a TaskList', function () {
@@ -62,33 +72,49 @@ describe('components', function () {
62
72
  })),
63
73
  container = _render.container;
64
74
 
65
- expect(container.childNodes.length).toEqual(1);
66
- var referenceHeading = container.childNodes[0].childNodes[0];
67
- expect(referenceHeading.tagName).toEqual('P');
68
- expect(referenceHeading.textContent).toEqual('COP reference number');
69
- var referenceNumber = container.childNodes[0].childNodes[1];
70
- expect(referenceNumber.tagName).toEqual('P');
71
- expect(referenceNumber.textContent).toEqual('123');
72
- var incompleteForm = container.childNodes[0].childNodes[2];
73
- expect(incompleteForm.tagName).toEqual('P');
74
- expect(incompleteForm.textContent).toEqual(_TaskList.DEFAULT_INCOMPLETE_TITLE);
75
- var numComplete = container.childNodes[0].childNodes[3];
76
- expect(numComplete.tagName).toEqual('P');
77
- expect(numComplete.textContent).toEqual('You have completed 2 of 6 sections');
78
- expect(container.childNodes[0].childNodes.length).toEqual(8);
79
- var subSectionOneHeading = container.childNodes[0].childNodes[4];
80
- expect(subSectionOneHeading.tagName).toEqual('H2');
81
- expect(subSectionOneHeading.textContent).toEqual('1. These are your tasks');
82
- var subSectionOneList = container.childNodes[0].childNodes[5];
75
+ var childNodes = container.childNodes;
76
+ expect(childNodes.length).toEqual(1);
77
+ expect(childNodes[0].childNodes.length).toEqual(8);
78
+
79
+ var _childNodes$0$childNo = _slicedToArray(childNodes[0].childNodes, 8),
80
+ referenceHeading = _childNodes$0$childNo[0],
81
+ referenceNumber = _childNodes$0$childNo[1],
82
+ incompleteForm = _childNodes$0$childNo[2],
83
+ numComplete = _childNodes$0$childNo[3],
84
+ subSectionOneHeading = _childNodes$0$childNo[4],
85
+ subSectionOneList = _childNodes$0$childNo[5],
86
+ subSectionTwoHeading = _childNodes$0$childNo[6],
87
+ subSectionTwoList = _childNodes$0$childNo[7];
88
+
89
+ expect(referenceHeading).toMatchObject({
90
+ tagName: 'P',
91
+ textContent: 'COP reference number'
92
+ });
93
+ expect(referenceNumber).toMatchObject({
94
+ tagName: 'P',
95
+ textContent: '123'
96
+ });
97
+ expect(incompleteForm).toMatchObject({
98
+ tagName: 'P',
99
+ textContent: _TaskList.DEFAULT_INCOMPLETE_TITLE
100
+ });
101
+ expect(numComplete).toMatchObject({
102
+ tagName: 'P',
103
+ textContent: 'You have completed 2 of 6 sections'
104
+ });
105
+ expect(subSectionOneHeading).toMatchObject({
106
+ tagName: 'H2',
107
+ textContent: '1. These are your tasks'
108
+ });
83
109
  expect(subSectionOneList.childNodes.length).toEqual(4);
84
- var subSectionTwoHeading = container.childNodes[0].childNodes[6];
85
- expect(subSectionTwoHeading.tagName).toEqual('H2');
86
- expect(subSectionTwoHeading.textContent).toEqual('2. These are your extra bonus tasks');
87
- var subSectionTwoList = container.childNodes[0].childNodes[7];
110
+ expect(subSectionTwoHeading).toMatchObject({
111
+ tagName: 'H2',
112
+ textContent: '2. These are your extra bonus tasks'
113
+ });
88
114
  expect(subSectionTwoList.childNodes.length).toEqual(4);
89
- var subSectionOneLabel = container.childNodes[0].childNodes[5].firstChild;
115
+ var subSectionOneLabel = childNodes[0].childNodes[5].firstChild;
90
116
  expect(subSectionOneLabel.textContent).toEqual('This is the label for your first tasks');
91
- var subSectionTwoLabel = container.childNodes[0].childNodes[7].firstChild;
117
+ var subSectionTwoLabel = childNodes[0].childNodes[7].firstChild;
92
118
  expect(subSectionTwoLabel.textContent).toEqual('This is the label for your extra tasks');
93
119
  });
94
120
  it('should not show incomplete title if form is complete', function () {
@@ -133,16 +159,26 @@ describe('components', function () {
133
159
  })),
134
160
  container = _render2.container;
135
161
 
136
- expect(container.childNodes[0].childNodes.length).toEqual(7);
137
- var referenceHeading = container.childNodes[0].childNodes[0];
138
- expect(referenceHeading.tagName).toEqual('P');
139
- expect(referenceHeading.textContent).toEqual('COP reference number');
140
- var referenceNumber = container.childNodes[0].childNodes[1];
141
- expect(referenceNumber.tagName).toEqual('P');
142
- expect(referenceNumber.textContent).toEqual('123');
143
- var numComplete = container.childNodes[0].childNodes[2];
144
- expect(numComplete.tagName).toEqual('P');
145
- expect(numComplete.textContent).toEqual('You have completed 6 of 6 sections');
162
+ var childNodes = container.childNodes;
163
+ expect(childNodes[0].childNodes.length).toEqual(7);
164
+
165
+ var _childNodes$0$childNo2 = _slicedToArray(childNodes[0].childNodes, 3),
166
+ referenceHeading = _childNodes$0$childNo2[0],
167
+ referenceNumber = _childNodes$0$childNo2[1],
168
+ numComplete = _childNodes$0$childNo2[2];
169
+
170
+ expect(referenceHeading).toMatchObject({
171
+ tagName: 'P',
172
+ textContent: 'COP reference number'
173
+ });
174
+ expect(referenceNumber).toMatchObject({
175
+ tagName: 'P',
176
+ textContent: '123'
177
+ });
178
+ expect(numComplete).toMatchObject({
179
+ tagName: 'P',
180
+ textContent: 'You have completed 6 of 6 sections'
181
+ });
146
182
  });
147
183
  it('should not show numbers on section headings if there is only one section', function () {
148
184
  var COP_REF = '123';
@@ -171,7 +207,8 @@ describe('components', function () {
171
207
  })),
172
208
  container = _render3.container;
173
209
 
174
- var subSectionOne = container.childNodes[0].childNodes[4];
210
+ var childNodes = container.childNodes;
211
+ var subSectionOne = childNodes[0].childNodes[4];
175
212
  expect(subSectionOne.childNodes[0].textContent).toEqual('');
176
213
  expect(subSectionOne.childNodes[1].textContent).toEqual('These are your tasks');
177
214
  });
@@ -215,12 +252,15 @@ describe('components', function () {
215
252
  })),
216
253
  container = _render4.container;
217
254
 
218
- expect(container.childNodes.length).toEqual(1);
219
- expect(container.childNodes[0].childNodes.length).toEqual(6); // The first child is now the incomplete text.
255
+ var childNodes = container.childNodes;
256
+ expect(childNodes.length).toEqual(1);
257
+ expect(childNodes[0].childNodes.length).toEqual(6); // The first child is now the incomplete text.
220
258
 
221
- var incompleteForm = container.childNodes[0].childNodes[0];
222
- expect(incompleteForm.tagName).toEqual('P');
223
- expect(incompleteForm.textContent).toEqual(_TaskList.DEFAULT_INCOMPLETE_TITLE);
259
+ var incompleteForm = childNodes[0].childNodes[0];
260
+ expect(incompleteForm).toMatchObject({
261
+ tagName: 'P',
262
+ textContent: _TaskList.DEFAULT_INCOMPLETE_TITLE
263
+ });
224
264
  });
225
265
  it('should show the correct incomplete title', function () {
226
266
  var INCOMPLETE_TITLE = 'Alpha Bravo';
@@ -262,10 +302,11 @@ describe('components', function () {
262
302
  sections: sections,
263
303
  incompleteTitle: INCOMPLETE_TITLE
264
304
  })),
265
- container = _render5.container; // The first child is now the incomplete text.
305
+ container = _render5.container;
266
306
 
307
+ var childNodes = container.childNodes; // The first child is now the incomplete text.
267
308
 
268
- var incompleteForm = container.childNodes[0].childNodes[0];
309
+ var incompleteForm = childNodes[0].childNodes[0];
269
310
  expect(incompleteForm.textContent).toEqual(INCOMPLETE_TITLE);
270
311
  });
271
312
  });
@@ -303,9 +344,10 @@ describe('components', function () {
303
344
  })),
304
345
  container = _render6.container;
305
346
 
306
- var firstTask = container.childNodes[0].childNodes[5].childNodes[1].childNodes[0].childNodes[0];
307
- var secondTask = container.childNodes[0].childNodes[5].childNodes[2].childNodes[0].childNodes[0];
308
- var thirdTask = container.childNodes[0].childNodes[5].childNodes[3].childNodes[0].childNodes[0];
347
+ var taskList = container.childNodes[0].childNodes[5].childNodes;
348
+ var firstTask = taskList[1].childNodes[0].childNodes[0];
349
+ var secondTask = taskList[2].childNodes[0].childNodes[0];
350
+ var thirdTask = taskList[3].childNodes[0].childNodes[0];
309
351
 
310
352
  _react.fireEvent.click(firstTask.childNodes[0]);
311
353
 
@@ -11,6 +11,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
11
11
  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; }
12
12
 
13
13
  describe('utils.CheckYourAnswers.getCYARowsForContainer', function () {
14
+ var OUTER_ID = 'a';
15
+ var INNER_ID = 'b';
14
16
  it('should get an appropriate row for a container with a single readonly text component', function () {
15
17
  var FORM_DATA = {
16
18
  container: {
@@ -252,9 +254,6 @@ describe('utils.CheckYourAnswers.getCYARowsForContainer', function () {
252
254
  });
253
255
  });
254
256
  it('should get an appropriate row for a collection with a single text component inside a container', function () {
255
- var OUTER_ID = 'a';
256
- var INNER_ID = 'b';
257
-
258
257
  var FORM_DATA = _defineProperty({}, OUTER_ID, [_defineProperty({}, INNER_ID, 'Bravo'), _defineProperty({}, INNER_ID, 'Charlie')]);
259
258
 
260
259
  var PAGE = {
@@ -321,8 +320,6 @@ describe('utils.CheckYourAnswers.getCYARowsForContainer', function () {
321
320
  checkValueRow(1, ROWS[3], 'Charlie');
322
321
  });
323
322
  it('should conditionally show an appropriate row for a single text component inside a container belonging to a partial-collection', function () {
324
- var OUTER_ID = 'a';
325
- var INNER_ID = 'b';
326
323
  var FORM_DATA = {
327
324
  collectionName: [{
328
325
  container: _defineProperty({}, INNER_ID, 'Bravo'),
@@ -50,6 +50,12 @@ var getPageActions = function getPageActions(page) {
50
50
  }
51
51
 
52
52
  if (a && _typeof(a) === 'object') {
53
+ var _PageAction$DEFAULTS$;
54
+
55
+ if ((_PageAction$DEFAULTS$ = _models.PageAction.DEFAULTS[a.type]) !== null && _PageAction$DEFAULTS$ !== void 0 && _PageAction$DEFAULTS$.validate && !a.hasOwnProperty('validate')) {
56
+ a.validate = true;
57
+ }
58
+
53
59
  return standardiseAction(a);
54
60
  }
55
61
 
@@ -84,6 +84,33 @@ describe('utils', function () {
84
84
  actions: actions
85
85
  })).toEqual(actions);
86
86
  });
87
+ it('should add a default validation prop if none are present', function () {
88
+ var actions = [{
89
+ type: 'saveAndContinue',
90
+ label: 'Charlie'
91
+ }];
92
+ expect((0, _getPageActions.default)({
93
+ actions: actions
94
+ })).toEqual([{
95
+ type: 'saveAndContinue',
96
+ label: 'Charlie',
97
+ validate: true
98
+ }]);
99
+ });
100
+ it('should not overwrite a validation prop when one exists', function () {
101
+ var actions = [{
102
+ type: 'submit',
103
+ label: 'Charlie',
104
+ validate: false
105
+ }];
106
+ expect((0, _getPageActions.default)({
107
+ actions: actions
108
+ })).toEqual([{
109
+ type: 'submit',
110
+ label: 'Charlie',
111
+ validate: false
112
+ }]);
113
+ });
87
114
  });
88
115
  });
89
116
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukhomeoffice/cop-react-form-renderer",
3
- "version": "4.33.1",
3
+ "version": "4.34.0",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "clean": "rimraf dist",