@ukhomeoffice/cop-react-form-renderer 5.23.0 → 5.24.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.
@@ -1,19 +1,37 @@
1
1
  "use strict";
2
2
 
3
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.default = void 0;
7
8
  var _copReactComponents = require("@ukhomeoffice/cop-react-components");
8
9
  var _models = require("../../models");
9
- function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
10
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
11
  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; }
12
12
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
13
13
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
14
- function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } // Global imports
14
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
15
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
16
+ 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."); }
17
+ 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); }
18
+ 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; }
19
+ function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
20
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // Global imports
15
21
  // Local imports
22
+ /**
23
+ * Gets an action object that triggers editing of an entry in a page collection.
24
+ *
25
+ * @param {object} page The page that the action belongs to.
26
+ * @param {object} item The item in the collection that is to be edited.
27
+ * @param {function} onAction The onAction callback passed in to the CYA page from FormRenderer.
28
+ * @param {string} labelCount The item's index in the collection plus one (for displaying to the user).
29
+ * @param {object} action The action's config from the form definition.
30
+ * @param {array} activeIds A list of active Ids that must be set to make Item the active entry.
31
+ * @returns The resulting action object.
32
+ */
16
33
  var getCYACollectionChangeAction = function getCYACollectionChangeAction(page, item, _onAction, labelCount, action) {
34
+ var activeIds = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
17
35
  var label = (action === null || action === void 0 ? void 0 : action.label) || _models.CollectionLabels.change;
18
36
  return {
19
37
  pageId: page.id,
@@ -24,16 +42,19 @@ var getCYACollectionChangeAction = function getCYACollectionChangeAction(page, i
24
42
  onAction: function onAction(row) {
25
43
  var changeCallback = function changeCallback(cyaData) {
26
44
  var data = cyaData;
27
- data["".concat(page.collection.name, "ActiveId")] = item.id;
45
+ // Apply the activeIds to make sure we're editing the right item.
46
+ // Not using the spread syntax as data could be a huge object.
47
+ Object.entries(activeIds).forEach(function (entry) {
48
+ var _entry = _slicedToArray(entry, 2),
49
+ activeIdKey = _entry[0],
50
+ activeId = _entry[1];
51
+ data[activeIdKey] = activeId;
52
+ });
28
53
  return data;
29
54
  };
30
- var nextPage = row;
31
- if (action.page) {
32
- nextPage = {
33
- pageId: action.page
34
- };
35
- }
36
- _onAction(nextPage, changeCallback);
55
+ _onAction(action.page ? {
56
+ pageId: action.page
57
+ } : row, changeCallback);
37
58
  },
38
59
  label: _copReactComponents.Utils.interpolateString(label, _objectSpread(_objectSpread({}, item), {}, {
39
60
  index: labelCount
@@ -36,13 +36,102 @@ describe('utils', function () {
36
36
  expect(row.id).toEqual(2);
37
37
  TEST_DATA = callback(TEST_DATA);
38
38
  };
39
- var action = (0, _getCYACollectionChangeAction.default)(PAGE, ITEM, ON_ACTION, 0, {});
39
+ var action = (0, _getCYACollectionChangeAction.default)(PAGE, ITEM, ON_ACTION, 0, {}, {
40
+ collectionNameActiveId: 2
41
+ });
40
42
  action.action.onAction(PAGE);
41
43
  expect(TEST_DATA.collectionNameActiveId).toEqual(2);
42
44
  });
45
+ it('should change all necessary activeIds when moving to edit a nested collection entry', function () {
46
+ var NESTED_COLLECTION_PAGE = {
47
+ id: 'pageid',
48
+ collection: {
49
+ name: 'parent.child.grandchild'
50
+ }
51
+ };
52
+ var NESTED_ITEM = {
53
+ id: '001'
54
+ };
55
+ var NESTED_TEST_DATA = {
56
+ parentActiveId: '000',
57
+ childActiveId: '000',
58
+ grandchildActiveId: '000',
59
+ parent: [{
60
+ id: '000'
61
+ }, {
62
+ id: '001',
63
+ child: [{
64
+ id: '000'
65
+ }, {
66
+ id: '001',
67
+ grandchild: [{
68
+ id: '000'
69
+ }, {
70
+ id: '001'
71
+ }]
72
+ }]
73
+ }]
74
+ };
75
+ var ACTIVE_IDS = {
76
+ parentActiveId: '001',
77
+ childActiveId: '001',
78
+ grandchildActiveId: '001'
79
+ };
80
+ var ON_ACTION = function ON_ACTION(row, callback) {
81
+ expect(row.id).toEqual(2);
82
+ NESTED_TEST_DATA = callback(NESTED_TEST_DATA);
83
+ };
84
+ var action = (0, _getCYACollectionChangeAction.default)(NESTED_COLLECTION_PAGE, NESTED_ITEM, ON_ACTION, 0, {}, ACTIVE_IDS);
85
+ action.action.onAction(PAGE);
86
+ expect(NESTED_TEST_DATA.parentActiveId).toEqual('001');
87
+ expect(NESTED_TEST_DATA.childActiveId).toEqual('001');
88
+ expect(NESTED_TEST_DATA.grandchildActiveId).toEqual('001');
89
+ });
90
+ it('should not change any active IDs if they are not provided', function () {
91
+ var NESTED_COLLECTION_PAGE = {
92
+ id: 'pageid',
93
+ collection: {
94
+ name: 'parent.child.grandchild'
95
+ }
96
+ };
97
+ var NESTED_ITEM = {
98
+ id: '001'
99
+ };
100
+ var NESTED_TEST_DATA = {
101
+ parentActiveId: '000',
102
+ childActiveId: '000',
103
+ grandchildActiveId: '000',
104
+ parent: [{
105
+ id: '000'
106
+ }, {
107
+ id: '001',
108
+ child: [{
109
+ id: '000'
110
+ }, {
111
+ id: '001',
112
+ grandchild: [{
113
+ id: '000'
114
+ }, {
115
+ id: '001'
116
+ }]
117
+ }]
118
+ }]
119
+ };
120
+ var ON_ACTION = function ON_ACTION(row, callback) {
121
+ expect(row.id).toEqual(2);
122
+ NESTED_TEST_DATA = callback(NESTED_TEST_DATA);
123
+ };
124
+ var action = (0, _getCYACollectionChangeAction.default)(NESTED_COLLECTION_PAGE, NESTED_ITEM, ON_ACTION, 0, {});
125
+ action.action.onAction(PAGE);
126
+ expect(NESTED_TEST_DATA.parentActiveId).toEqual('000');
127
+ expect(NESTED_TEST_DATA.childActiveId).toEqual('000');
128
+ expect(NESTED_TEST_DATA.grandchildActiveId).toEqual('000');
129
+ });
43
130
  it('should get label to custom value', function () {
44
131
  var action = (0, _getCYACollectionChangeAction.default)(PAGE, ITEM, function () {}, 0, {
45
132
  label: 'customName'
133
+ }, {
134
+ collectionNameActiveId: 2
46
135
  });
47
136
  expect(action.action.label).toEqual('customName');
48
137
  });
@@ -62,7 +151,9 @@ describe('utils', function () {
62
151
  expect(page.pageId).toEqual('confirmDelete');
63
152
  TEST_DATA = callback(TEST_DATA);
64
153
  };
65
- var action = (0, _getCYACollectionChangeAction.default)(PAGE_WITH_CUSTOM_DESTINATION, ITEM, ON_ACTION, 0, PAGE_WITH_CUSTOM_DESTINATION.collection.actions[0]);
154
+ var action = (0, _getCYACollectionChangeAction.default)(PAGE_WITH_CUSTOM_DESTINATION, ITEM, ON_ACTION, 0, PAGE_WITH_CUSTOM_DESTINATION.collection.actions[0], {
155
+ collectionNameActiveId: 2
156
+ });
66
157
  action.action.onAction({});
67
158
  expect(TEST_DATA.collectionNameActiveId).toEqual(2);
68
159
  });
@@ -1,19 +1,42 @@
1
1
  "use strict";
2
2
 
3
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.default = void 0;
7
8
  var _copReactComponents = require("@ukhomeoffice/cop-react-components");
9
+ var _CollectionPage = _interopRequireDefault(require("../CollectionPage"));
8
10
  var _models = require("../../models");
9
- function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
11
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
12
  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
13
  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; }
12
14
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
13
15
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
14
- function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } // Global imports
16
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
17
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
18
+ 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."); }
19
+ 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); }
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
+ function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
22
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // Global imports
15
23
  // Local imports
16
- var getCYACollectionDeleteAction = function getCYACollectionDeleteAction(page, item, _onAction, labelCount, action) {
24
+ var isValidIndex = function isValidIndex(value) {
25
+ return typeof value === 'number' && value >= 0;
26
+ };
27
+
28
+ /**
29
+ * Gets an action object that triggers the removal of an item from a page Collection.
30
+ *
31
+ * @param {object} page The page that the action belongs to.
32
+ * @param {object} item The item in the collection that is being removed.
33
+ * @param {function} onAction The onAction callback passed in to the CYA page from FormRenderer.
34
+ * @param {string} labelCount The item's index in the collection plus one (for displaying to the user).
35
+ * @param {object} action The action's config from the form definition.
36
+ * @param {array} activeIds A list of active Ids that must be set to make Item the active entry.
37
+ * @returns The resulting action object.
38
+ */
39
+ var getCYACollectionDeleteAction = function getCYACollectionDeleteAction(page, item, _onAction, labelCount, action, activeIds) {
17
40
  var label = (action === null || action === void 0 ? void 0 : action.label) || _models.CollectionLabels.remove;
18
41
  return {
19
42
  pageId: page.id,
@@ -24,9 +47,24 @@ var getCYACollectionDeleteAction = function getCYACollectionDeleteAction(page, i
24
47
  onAction: function onAction() {
25
48
  var deleteCallback = function deleteCallback(cyaData) {
26
49
  var data = cyaData;
27
- data["".concat(page.collection.name)] = data["".concat(page.collection.name)].filter(function (i) {
28
- return i.id !== item.id;
50
+ if (!activeIds) {
51
+ return data;
52
+ }
53
+ // Apply the activeIds to make sure we're deleting the right item.
54
+ // Not using the spread syntax as data could be a huge object.
55
+ Object.entries(activeIds).forEach(function (entry) {
56
+ var _entry = _slicedToArray(entry, 2),
57
+ activeIdKey = _entry[0],
58
+ activeId = _entry[1];
59
+ data[activeIdKey] = activeId;
60
+ });
61
+ var collectionData = _CollectionPage.default.getData(page.collection.name, data);
62
+ var indexToDelete = collectionData === null || collectionData === void 0 ? void 0 : collectionData.findIndex(function (entry) {
63
+ return entry.id === item.id;
29
64
  });
65
+ if (isValidIndex(indexToDelete)) {
66
+ collectionData.splice(indexToDelete, 1);
67
+ }
30
68
  return data;
31
69
  };
32
70
  _onAction(null, deleteCallback);
@@ -11,43 +11,186 @@ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input ==
11
11
  describe('utils', function () {
12
12
  describe('CheckYourAnswers', function () {
13
13
  describe('getCYACollectionDeleteAction', function () {
14
- var PAGE = {
15
- id: 'pageid',
16
- collection: {
17
- name: 'collectionName',
18
- labels: {
19
- remove: 'customName'
14
+ it('should remove selected item from the form data', function () {
15
+ var PAGE = {
16
+ id: 'pageid',
17
+ collection: {
18
+ name: 'collectionName',
19
+ labels: {
20
+ remove: 'customName'
21
+ }
20
22
  }
21
- }
22
- };
23
- var ITEM = {
24
- id: 2
25
- };
26
- var TEST_DATA = {
27
- page: _objectSpread({}, PAGE),
28
- collectionName: [{
29
- id: 1
30
- }, {
23
+ };
24
+ var ITEM = {
31
25
  id: 2
32
- }, {
33
- id: 3
34
- }]
35
- };
36
- it('should remove selected item from the form data', function () {
26
+ };
27
+ var TEST_DATA = {
28
+ page: _objectSpread({}, PAGE),
29
+ collectionName: [{
30
+ id: 1
31
+ }, {
32
+ id: 2
33
+ }, {
34
+ id: 3
35
+ }]
36
+ };
37
37
  var data = null;
38
38
  var ON_ACTION = function ON_ACTION(_, callback) {
39
39
  data = callback(TEST_DATA);
40
40
  };
41
- var action = (0, _getCYACollectionDeleteAction.default)(PAGE, ITEM, ON_ACTION, 0, {});
41
+ var action = (0, _getCYACollectionDeleteAction.default)(PAGE, ITEM, ON_ACTION, 0, {}, {});
42
42
  action.action.onAction();
43
43
  expect(data.collectionName.length).toEqual(2);
44
44
  expect(data.collectionName[0].id).toEqual(1);
45
45
  expect(data.collectionName[1].id).toEqual(3);
46
46
  });
47
+ it('should remove nested item from the form data', function () {
48
+ var PAGE = {
49
+ id: 'pageid',
50
+ collection: {
51
+ name: 'parent.child.grandchild'
52
+ }
53
+ };
54
+ var ITEM = {
55
+ id: '001'
56
+ };
57
+ var TEST_DATA = {
58
+ parentActiveId: '000',
59
+ childActiveId: '000',
60
+ grandchildActiveId: '000',
61
+ parent: [{
62
+ id: '000'
63
+ }, {
64
+ id: '001',
65
+ child: [{
66
+ id: '000'
67
+ }, {
68
+ id: '001',
69
+ grandchild: [{
70
+ id: '000'
71
+ }, {
72
+ id: '001'
73
+ }]
74
+ }]
75
+ }]
76
+ };
77
+ var ACTIVE_IDS = {
78
+ parentActiveId: '001',
79
+ childActiveId: '001',
80
+ grandchildActiveId: '001'
81
+ };
82
+ var data = null;
83
+ var ON_ACTION = function ON_ACTION(_, callback) {
84
+ data = callback(TEST_DATA);
85
+ };
86
+ var action = (0, _getCYACollectionDeleteAction.default)(PAGE, ITEM, ON_ACTION, 0, {}, ACTIVE_IDS);
87
+ action.action.onAction();
88
+ expect(data.parentActiveId).toEqual('001');
89
+ expect(data.childActiveId).toEqual('001');
90
+ expect(data.grandchildActiveId).toEqual('001');
91
+ expect(data.parent[1].child[1].grandchild.length).toEqual(1);
92
+ expect(data.parent[1].child[1].grandchild[0].id).toEqual('000');
93
+ });
94
+ it('should do nothing if activeIds are not provided', function () {
95
+ var PAGE = {
96
+ id: 'pageid',
97
+ collection: {
98
+ name: 'parent.child.grandchild'
99
+ }
100
+ };
101
+ var ITEM = {
102
+ id: '001'
103
+ };
104
+ var TEST_DATA = {
105
+ parentActiveId: '000',
106
+ childActiveId: '000',
107
+ grandchildActiveId: '000',
108
+ parent: [{
109
+ id: '000'
110
+ }, {
111
+ id: '001',
112
+ child: [{
113
+ id: '000'
114
+ }, {
115
+ id: '001',
116
+ grandchild: [{
117
+ id: '000'
118
+ }, {
119
+ id: '001'
120
+ }]
121
+ }]
122
+ }]
123
+ };
124
+ var data = null;
125
+ var ON_ACTION = function ON_ACTION(_, callback) {
126
+ data = callback(TEST_DATA);
127
+ };
128
+ var action = (0, _getCYACollectionDeleteAction.default)(PAGE, ITEM, ON_ACTION, 0, {});
129
+ action.action.onAction();
130
+ expect(data.parentActiveId).toEqual('000');
131
+ expect(data.childActiveId).toEqual('000');
132
+ expect(data.grandchildActiveId).toEqual('000');
133
+ expect(data.parent[1].child[1].grandchild.length).toEqual(2);
134
+ });
135
+ it('should do nothing if the activeIds point to an non-existant entry', function () {
136
+ var PAGE = {
137
+ id: 'pageid',
138
+ collection: {
139
+ name: 'parent.child.grandchild'
140
+ }
141
+ };
142
+ var ITEM = {
143
+ id: '001'
144
+ };
145
+ var TEST_DATA = {
146
+ parentActiveId: '000',
147
+ childActiveId: '000',
148
+ grandchildActiveId: '000',
149
+ parent: [{
150
+ id: '000'
151
+ }, {
152
+ id: '001',
153
+ child: [{
154
+ id: '000'
155
+ }, {
156
+ id: '001',
157
+ grandchild: [{
158
+ id: '000'
159
+ }, {
160
+ id: '001'
161
+ }]
162
+ }]
163
+ }]
164
+ };
165
+ var ACTIVE_IDS = {
166
+ parentActiveId: 'wrong',
167
+ childActiveId: 'bad',
168
+ grandchildActiveId: 'no'
169
+ };
170
+ var data = null;
171
+ var ON_ACTION = function ON_ACTION(_, callback) {
172
+ data = callback(TEST_DATA);
173
+ };
174
+ var action = (0, _getCYACollectionDeleteAction.default)(PAGE, ITEM, ON_ACTION, 0, {}, ACTIVE_IDS);
175
+ action.action.onAction();
176
+ expect(data.parent[1].child[1].grandchild.length).toEqual(2);
177
+ });
47
178
  it('should get label to custom value', function () {
179
+ var PAGE = {
180
+ id: 'pageid',
181
+ collection: {
182
+ name: 'collectionName',
183
+ labels: {
184
+ remove: 'customName'
185
+ }
186
+ }
187
+ };
188
+ var ITEM = {
189
+ id: 2
190
+ };
48
191
  var action = (0, _getCYACollectionDeleteAction.default)(PAGE, ITEM, function () {}, 0, {
49
192
  label: "customName"
50
- });
193
+ }, {});
51
194
  expect(action.action.label).toEqual('customName');
52
195
  });
53
196
  });
@@ -13,6 +13,12 @@ var _getCYACollectionChangeAction = _interopRequireDefault(require("./getCYAColl
13
13
  var _getCYARowsForContainer = _interopRequireDefault(require("./getCYARowsForContainer"));
14
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
15
  function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
16
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
17
+ 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."); }
18
+ 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); }
19
+ 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; }
20
+ function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
21
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
16
22
  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; }
17
23
  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; }
18
24
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -62,14 +68,25 @@ var getHeadingRow = function getHeadingRow(config, pageId, labelCount) {
62
68
  size: config.size || 's'
63
69
  };
64
70
  };
71
+ var getCollectionNameHeading = function getCollectionNameHeading(page, titleName) {
72
+ return {
73
+ pageId: page.id,
74
+ fieldId: "".concat(page.collection.name, "Title"),
75
+ full_path: "".concat(page.collection.name, "Title"),
76
+ key: titleName.charAt(0).toUpperCase() + titleName.slice(1),
77
+ type: 'heading',
78
+ size: 'm'
79
+ };
80
+ };
65
81
  var getActionRows = function getActionRows(page, item, onAction, labelCount) {
66
82
  var _page$collection;
83
+ var activeIds = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
67
84
  return (_page$collection = page.collection) === null || _page$collection === void 0 || (_page$collection = _page$collection.actions) === null || _page$collection === void 0 ? void 0 : _page$collection.map(function (action) {
68
85
  if (action.type === 'remove') {
69
- return (0, _getCYACollectionDeleteAction.default)(page, item, onAction, labelCount, action);
86
+ return (0, _getCYACollectionDeleteAction.default)(page, item, onAction, labelCount, action, activeIds);
70
87
  }
71
88
  if (action.type === 'change') {
72
- return (0, _getCYACollectionChangeAction.default)(page, item, onAction, labelCount, action);
89
+ return (0, _getCYACollectionChangeAction.default)(page, item, onAction, labelCount, action, activeIds);
73
90
  }
74
91
  return null;
75
92
  }).filter(function (action) {
@@ -78,11 +95,20 @@ var getActionRows = function getActionRows(page, item, onAction, labelCount) {
78
95
  };
79
96
 
80
97
  // eslint-disable-next-line arrow-body-style
81
- var getChangeActionForPage = function getChangeActionForPage(page, item, onAction) {
98
+ var getChangeActionForPage = function getChangeActionForPage(page, onAction) {
99
+ var activeIds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
82
100
  return function () {
83
101
  var changeCallback = function changeCallback(changeData) {
84
102
  var data = changeData;
85
- data["".concat(page.collection.name, "ActiveId")] = item.id;
103
+ // Looping over the keys here as applying the changes
104
+ // as 'let data = { ...data, ...activeIds }' seemed wasteful,
105
+ // data could be a huge object.
106
+ Object.entries(activeIds).forEach(function (entry) {
107
+ var _entry = _slicedToArray(entry, 2),
108
+ activeIdKey = _entry[0],
109
+ activeId = _entry[1];
110
+ data[activeIdKey] = activeId;
111
+ });
86
112
  return data;
87
113
  };
88
114
  onAction({
@@ -90,50 +116,93 @@ var getChangeActionForPage = function getChangeActionForPage(page, item, onActio
90
116
  }, changeCallback);
91
117
  };
92
118
  };
93
- var getCYARowsForCollectionPage = function getCYARowsForCollectionPage(page, onAction, fnOverride) {
94
- var _page$formData, _page$formData2;
95
- if (!((_page$formData = page.formData) !== null && _page$formData !== void 0 && (_page$formData = _page$formData[page.collection.name]) !== null && _page$formData !== void 0 && _page$formData.length)) {
119
+
120
+ /**
121
+ * Gets the rows for all pages in an array of child pages. This array of pages
122
+ * should come from a collection's master page.
123
+ *
124
+ * @param {Array} childPages The array of child page objects.
125
+ * @param {Object} item The data for the current item in the collection.
126
+ * @param {Function} onAction The onAction callback passed in from FormRenderer.
127
+ * @param {Function} fnOverride Function used to override the creation of container rows.
128
+ * @param {String} labelCount The index of the current item in the collection, plus one.
129
+ * @param {String} fullPath The full path to the current item in the collection, written as 'COLLECTION_NAME[INDEX]'.
130
+ * @param {Object} activeIds The active IDs that must be set for the current item to be active.
131
+ * @returns An array of CYA rows for all child pages.
132
+ */
133
+ var getCYARowsForChildPages = function getCYARowsForChildPages(childPages, item, onAction, fnOverride, labelCount, fullPath, activeIds) {
134
+ var rows = [];
135
+ childPages.forEach(function (p) {
136
+ var childPage = p;
137
+ // If the child page is itself a master page, then we should produce the
138
+ // rows for it and it's children.
139
+ if (childPage.collection.masterPage) {
140
+ // eslint-disable-next-line no-use-before-define
141
+ rows = rows.concat(getCYARowsForCollectionPage(childPage, onAction, fnOverride, item, activeIds));
142
+ } else {
143
+ // Routes were an old way of adding show_when functionality to collection
144
+ // pages. Regular show_whens can now be used and this code should be removed
145
+ // at some point.
146
+ if (childPage.collection.route) {
147
+ var pageWithRoute = (0, _addShowWhen.default)(childPage, childPage.collection.route);
148
+ childPage = pageWithRoute || childPage;
149
+ }
150
+ // Check that the child page was actually shown to the user. This has
151
+ // to be done here as the show_when checks could rely upon item-level
152
+ // data.
153
+ if ((0, _showFormPageCYA.default)(childPage, _objectSpread(_objectSpread({}, childPage.formData), item))) {
154
+ if (childPage.collection.heading) {
155
+ var headingRow = getHeadingRow(childPage.collection.heading, childPage.id, labelCount);
156
+ rows = rows.concat(headingRow);
157
+ }
158
+ var container = getContainerForPage(childPage, item, labelCount, fullPath);
159
+ var rowChangeAction = getChangeActionForPage(childPage, item, onAction, activeIds);
160
+ var containerRows = (0, _getCYARowsForContainer.default)(childPage, container, item, rowChangeAction, fnOverride);
161
+ rows = rows.concat(containerRows);
162
+ }
163
+ }
164
+ });
165
+ return rows;
166
+ };
167
+
168
+ /**
169
+ * Get the CYA rows for a collection's master page.
170
+ *
171
+ * @param {Object} page The master page object.
172
+ * @param {Object} data The data at this master page's level.
173
+ * @param {Function} onAction The onAction callback passed in from FormRenderer.
174
+ * @param {Function} fnOverride Function used to override the creation of container rows.
175
+ * @param {Object} activeIds The active IDs that must be set for the current item to be active.
176
+ * @returns An array of CYA rows.
177
+ */
178
+ var getCYARowsForCollectionPage = function getCYARowsForCollectionPage(page, onAction, fnOverride, data) {
179
+ var activeIds = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
180
+ var collectionName = page.collection.name.split('.').pop();
181
+ var collectionData = data[collectionName] || null;
182
+ if (!collectionData || collectionData.length === 0) {
96
183
  return [];
97
184
  }
98
185
  var rows = [];
99
186
  if (!page.collection.hideNameFromCYA) {
100
- rows.push({
101
- pageId: page.id,
102
- fieldId: "".concat(page.collection.name, "Title"),
103
- full_path: "".concat(page.collection.name, "Title"),
104
- key: page.collection.name.charAt(0).toUpperCase() + page.collection.name.slice(1),
105
- type: 'heading',
106
- size: 'm'
107
- });
187
+ rows.push(getCollectionNameHeading(page, collectionName));
108
188
  }
109
- (_page$formData2 = page.formData) === null || _page$formData2 === void 0 || (_page$formData2 = _page$formData2[page.collection.name]) === null || _page$formData2 === void 0 ? void 0 : _page$formData2.forEach(function (item, index) {
189
+ collectionData.forEach(function (item, index) {
110
190
  var _page$collection2;
191
+ // Keep track of the active entry in each collection.
192
+ // This helps us make sure the right entry is being affected
193
+ // by change/remove links.
194
+ // eslint-disable-next-line no-param-reassign
195
+ activeIds = _objectSpread(_objectSpread({}, activeIds), {}, _defineProperty({}, "".concat(collectionName, "ActiveId"), item.id));
111
196
  var labelCount = index + 1;
112
197
  var actionPosition = ((_page$collection2 = page.collection) === null || _page$collection2 === void 0 ? void 0 : _page$collection2.actionPosition) || 'top';
113
198
  var fullPath = "".concat(page.collection.name, "[").concat(index, "]");
114
199
  var titleRow = getTitleRowForItem(page, item, page.id, labelCount, fullPath);
115
- var actionRows = getActionRows(page, item, onAction, labelCount);
200
+ var actionRows = getActionRows(page, item, onAction, labelCount, activeIds);
116
201
  rows = rows.concat(titleRow);
117
202
  if (actionPosition === 'top') {
118
203
  rows = rows.concat(actionRows);
119
204
  }
120
- page.collectionPages.forEach(function (p) {
121
- var collectionPage = p;
122
- if (collectionPage.collection.route) {
123
- var pageWithRoute = (0, _addShowWhen.default)(collectionPage, p.collection.route);
124
- collectionPage = pageWithRoute || collectionPage;
125
- }
126
- if ((0, _showFormPageCYA.default)(collectionPage, _objectSpread(_objectSpread({}, collectionPage.formData), item))) {
127
- if (collectionPage.collection.heading) {
128
- var headingRow = getHeadingRow(collectionPage.collection.heading, collectionPage.id, labelCount);
129
- rows = rows.concat(headingRow);
130
- }
131
- var container = getContainerForPage(collectionPage, item, labelCount, fullPath);
132
- var rowChangeAction = getChangeActionForPage(collectionPage, item, onAction);
133
- var containerRows = (0, _getCYARowsForContainer.default)(collectionPage, container, item, rowChangeAction, fnOverride);
134
- rows = rows.concat(containerRows);
135
- }
136
- });
205
+ rows = rows.concat(getCYARowsForChildPages(page.childPages, item, onAction, fnOverride, labelCount, fullPath, activeIds));
137
206
  if (actionPosition === 'bottom') {
138
207
  rows = rows.concat(actionRows);
139
208
  }
@@ -53,14 +53,14 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
53
53
  page: 'confirmDelete'
54
54
  }]
55
55
  },
56
- collectionPages: PAGES
56
+ childPages: PAGES
57
57
  };
58
58
  it('should return no rows for a collection if it does not exist in formData', function () {
59
59
  var FORM_DATA = {};
60
60
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
61
61
  formData: FORM_DATA
62
62
  });
63
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
63
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
64
64
  expect(ROWS.length).toEqual(0);
65
65
  });
66
66
  it('should return no rows for a collection if it has no entries', function () {
@@ -70,7 +70,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
70
70
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
71
71
  formData: FORM_DATA
72
72
  });
73
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
73
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
74
74
  expect(ROWS.length).toEqual(0);
75
75
  });
76
76
  it('should accept the hideNameFromCYA collection flag', function () {
@@ -86,7 +86,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
86
86
  })
87
87
  });
88
88
  var TITLE_FIELD_ID = "".concat(PAGE.collection.name, "Title");
89
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
89
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
90
90
  expect(ROWS[0].fieldId).not.toEqual(TITLE_FIELD_ID);
91
91
  });
92
92
  it('should format titles correctly when collection.labels.item is specified', function () {
@@ -99,7 +99,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
99
99
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
100
100
  formData: FORM_DATA
101
101
  });
102
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
102
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
103
103
  expect(ROWS.length).toEqual(7); // Collection title, item title, action rows & component rows
104
104
  expect(ROWS[1].key).toEqual('Collection entry 1');
105
105
  });
@@ -116,7 +116,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
116
116
  }),
117
117
  formData: FORM_DATA
118
118
  });
119
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
119
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
120
120
  expect(ROWS.length).toEqual(7); // Collection title, item title, action rows & component rows
121
121
  expect(ROWS[1].key).toEqual('Item 1');
122
122
  });
@@ -133,7 +133,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
133
133
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
134
134
  formData: FORM_DATA
135
135
  });
136
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
136
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
137
137
  expect(ROWS.length).toEqual(13); // Title row + component row for each item
138
138
  expect(ROWS[0]).toMatchObject({
139
139
  type: 'heading',
@@ -187,7 +187,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
187
187
  name: 'collection'
188
188
  },
189
189
  formData: FD,
190
- collectionPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
190
+ childPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
191
191
  components: [{
192
192
  id: 'testText',
193
193
  fieldId: 'testText',
@@ -201,7 +201,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
201
201
  }]
202
202
  })]
203
203
  });
204
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
204
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FD);
205
205
  expect(ROWS.length).toEqual(4);
206
206
  expect(ROWS[0]).toMatchObject({
207
207
  type: 'heading',
@@ -233,7 +233,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
233
233
  name: 'collection'
234
234
  },
235
235
  formData: FD,
236
- collectionPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
236
+ childPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
237
237
  show_when: {
238
238
  field: "otherField",
239
239
  op: "!=",
@@ -241,7 +241,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
241
241
  }
242
242
  }), PAGES[1]]
243
243
  });
244
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
244
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FD);
245
245
  expect(ROWS.length).toEqual(3); // Missing the page with the text component on.
246
246
  expect(ROWS[0]).toMatchObject({
247
247
  type: 'heading',
@@ -265,7 +265,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
265
265
  };
266
266
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
267
267
  formData: FORM_DATA,
268
- collectionPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
268
+ childPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
269
269
  collection: _objectSpread(_objectSpread({}, PAGES[0].collection), {}, {
270
270
  heading: {
271
271
  size: 'm',
@@ -274,7 +274,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
274
274
  })
275
275
  })]
276
276
  });
277
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
277
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
278
278
  expect(ROWS.length).toEqual(7);
279
279
  expect(ROWS[0]).toMatchObject({
280
280
  type: 'heading',
@@ -306,7 +306,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
306
306
  };
307
307
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
308
308
  formData: FORM_DATA,
309
- collectionPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
309
+ childPages: [_objectSpread(_objectSpread({}, PAGES[0]), {}, {
310
310
  collection: _objectSpread(_objectSpread({}, PAGES[0].collection), {}, {
311
311
  heading: {
312
312
  text: 'Custom page heading'
@@ -314,7 +314,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
314
314
  })
315
315
  })]
316
316
  });
317
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
317
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
318
318
  expect(ROWS[5]).toMatchObject({
319
319
  type: 'heading',
320
320
  key: 'Custom page heading',
@@ -331,7 +331,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
331
331
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
332
332
  formData: FORM_DATA
333
333
  });
334
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
334
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
335
335
  expect(ROWS[2].action.label).toEqual('Change');
336
336
  expect(ROWS[3].action.label).toEqual('custom remove label');
337
337
  expect(ROWS[4].action.label).toEqual('custom change label');
@@ -349,7 +349,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
349
349
  }),
350
350
  formData: FORM_DATA
351
351
  });
352
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
352
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
353
353
  expect(ROWS[2].action.label).toEqual('Change');
354
354
  expect(ROWS[3].action.label).toEqual('custom remove label');
355
355
  expect(ROWS[4].action.label).toEqual('custom change label');
@@ -367,7 +367,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
367
367
  }),
368
368
  formData: FORM_DATA
369
369
  });
370
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null);
370
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, FORM_DATA);
371
371
  expect(ROWS[ROWS.length - 3].action.label).toEqual('Change');
372
372
  expect(ROWS[ROWS.length - 2].action.label).toEqual('custom remove label');
373
373
  expect(ROWS[ROWS.length - 1].action.label).toEqual('custom change label');
@@ -384,7 +384,7 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
384
384
  });
385
385
  var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, function () {
386
386
  return null;
387
- });
387
+ }, FORM_DATA);
388
388
  expect(ROWS.length).toEqual(7); // Collection title, item title, action rows & component rows
389
389
  expect(ROWS[5].key).toEqual("Test text");
390
390
  });
@@ -407,8 +407,91 @@ describe('utils.CheckYourAnswers.getCYARowsForCollectionPage', function () {
407
407
  var PAGE = _objectSpread(_objectSpread({}, MASTER_PAGE), {}, {
408
408
  formData: FORM_DATA
409
409
  });
410
- var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, OVERRIDE);
410
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, OVERRIDE, FORM_DATA);
411
411
  expect(ROWS.length).toEqual(7); // Collection title, item title, action rows & component rows
412
412
  expect(ROWS[5].key).toEqual("CustomRowFor".concat(TEXT_COMP.label));
413
413
  });
414
+ it('should create rows for nested collections correctly', function () {
415
+ var CUSTOM_FORM_DATA = {
416
+ parentActiveId: '001',
417
+ childActiveId: '001',
418
+ parent: [{
419
+ id: '001',
420
+ testText: 'alpha',
421
+ child: [{
422
+ id: '001',
423
+ testText: 'bravo'
424
+ }]
425
+ }]
426
+ };
427
+ var CHILD_MASTER_PAGE = {
428
+ id: 'childPage',
429
+ collection: {
430
+ name: 'parent.child',
431
+ masterPage: true,
432
+ labels: {
433
+ // eslint-disable-next-line no-template-curly-in-string
434
+ item: 'Child number ${index}'
435
+ },
436
+ actions: [{
437
+ type: 'change'
438
+ }, {
439
+ type: 'remove',
440
+ label: 'custom remove label'
441
+ }]
442
+ },
443
+ childPages: [{
444
+ id: 'childPage',
445
+ collection: {
446
+ name: 'parent.child'
447
+ },
448
+ components: [TEXT_COMP]
449
+ }]
450
+ };
451
+ var PARENT_MASTER_PAGE = {
452
+ id: 'parentPage',
453
+ collection: {
454
+ name: 'parent',
455
+ masterPage: true
456
+ },
457
+ childPages: [{
458
+ id: 'parentPage',
459
+ collection: {
460
+ name: 'parent'
461
+ },
462
+ components: [TEXT_COMP]
463
+ }, CHILD_MASTER_PAGE]
464
+ };
465
+ var PAGE = _objectSpread(_objectSpread({}, PARENT_MASTER_PAGE), {}, {
466
+ formData: CUSTOM_FORM_DATA
467
+ });
468
+ var ROWS = (0, _getCYARowsForCollectionPage.default)(PAGE, null, null, CUSTOM_FORM_DATA);
469
+ expect(ROWS.length).toEqual(8);
470
+ expect(ROWS[0]).toMatchObject({
471
+ type: 'heading',
472
+ key: 'Parent'
473
+ });
474
+ expect(ROWS[1]).toMatchObject({
475
+ type: 'heading',
476
+ key: 'Item 1'
477
+ });
478
+ expect(ROWS[2]).toMatchObject({
479
+ value: 'alpha',
480
+ key: 'Test text'
481
+ });
482
+ expect(ROWS[3]).toMatchObject({
483
+ type: 'heading',
484
+ key: 'Child'
485
+ });
486
+ expect(ROWS[4]).toMatchObject({
487
+ type: 'heading',
488
+ key: 'Child number 1'
489
+ });
490
+ expect(ROWS[5].action.label).toEqual('Change');
491
+ expect(ROWS[6].action.label).toEqual('custom remove label');
492
+ expect(ROWS[7]).toMatchObject({
493
+ value: 'bravo',
494
+ key: 'Test text'
495
+ });
496
+ });
414
497
  });
@@ -30,7 +30,7 @@ var getCYARowsForPage = function getCYARowsForPage(page, onAction) {
30
30
  if (_FormPage.default.showCYA(page, page.formData)) {
31
31
  var _page$groups;
32
32
  if (page.collection) {
33
- return (0, _getCYARowsForCollectionPage.default)(page, onAction, fnOverride);
33
+ return (0, _getCYARowsForCollectionPage.default)(page, onAction, fnOverride, page.formData);
34
34
  }
35
35
  var allComponents = (0, _elevateNestedComponents.default)(page.components, page.formData);
36
36
  var rows = allComponents.filter(function (c) {
@@ -12,6 +12,22 @@ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _ty
12
12
  function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
13
13
  /* eslint-disable no-param-reassign */
14
14
 
15
+ /*
16
+ * Why is a master page needed?
17
+ *
18
+ * When creating CYA rows for a collection, we need to know what pages
19
+ * belong to that collection. In the case of nested collections, we also
20
+ * need to know the same information for them.
21
+ *
22
+ * What does a master page look like?
23
+ *
24
+ * A master page is a wrapper for all the pages that make up a collection.
25
+ * These pages are stored in the 'childPages' property of a master page and
26
+ * can be one of either:
27
+ * - A regular form page.
28
+ * - The master page for a child collection, with its own array of child pages.
29
+ */
30
+
15
31
  var createMasterPage = function createMasterPage(page) {
16
32
  return {
17
33
  id: page.id,
@@ -20,13 +36,39 @@ var createMasterPage = function createMasterPage(page) {
20
36
  masterPage: true
21
37
  }, page.collection),
22
38
  formData: _objectSpread({}, page.formData),
23
- collectionPages: [page]
39
+ childPages: [page]
24
40
  };
25
41
  };
26
42
  var mergeIntoMasterPage = function mergeIntoMasterPage(page, masterPage) {
27
43
  masterPage.collection = _objectSpread(_objectSpread({}, masterPage.collection), page.collection);
28
44
  masterPage.formData = _objectSpread(_objectSpread({}, masterPage.formData), page.formData);
29
- masterPage.collectionPages = [].concat(masterPage.collectionPages, [page]);
45
+ masterPage.childPages = [].concat(masterPage.childPages, [page]);
46
+ };
47
+
48
+ /**
49
+ * Tries to nest page under the master page belonging to it's parent.
50
+ *
51
+ * @param {Object} page The child page..
52
+ * @param {Array} masterPages An array of existing master page objects.
53
+ * @returns true if page belonged to a child collection and was successfully
54
+ * nested. false if it isn't in a child collection or failed to be nested.
55
+ */
56
+ var nestUnderParent = function nestUnderParent(childPage, masterPages) {
57
+ var names = childPage.collection.name.split('.');
58
+ if (names.length === 1) {
59
+ return false;
60
+ }
61
+ names.pop();
62
+ var parentName = names.join('.');
63
+ var parentPage = masterPages[parentName] || null;
64
+ if (!parentPage) {
65
+ // Something had gone wrong if we're here - parent collection pages
66
+ // should always be defined before their children, so the parent master
67
+ // page should always exist...
68
+ return false;
69
+ }
70
+ parentPage.childPages.push(childPage);
71
+ return true;
30
72
  };
31
73
 
32
74
  /**
@@ -48,8 +90,12 @@ var mergeCollectionPages = function mergeCollectionPages(pages) {
48
90
  if (!masterPages[page.collection.name]) {
49
91
  // If no master page exists for this collection.name, then
50
92
  // we kick one off using this page as a template.
51
- masterPages[page.collection.name] = createMasterPage(page);
52
- return masterPages[page.collection.name];
93
+ var newMasterPage = createMasterPage(page);
94
+ masterPages[page.collection.name] = newMasterPage;
95
+ // We check if the new master page belongs to a child collection,
96
+ // if so then nest it under the parent master page and remove from
97
+ // the pages array. If not then treat it as a top-level collection.
98
+ return nestUnderParent(newMasterPage, masterPages) ? null : newMasterPage;
53
99
  }
54
100
  // If a master page already exists for this collection.name
55
101
  // then we just merge this page into it and remove this page
@@ -46,7 +46,53 @@ describe('utils.CollectionPage.mergeCollectionPages', function () {
46
46
  masterPage: true
47
47
  },
48
48
  formData: {},
49
- collectionPages: PAGES
49
+ childPages: PAGES
50
+ });
51
+ });
52
+ it('should correctly merge and nested child collection pages under their parents', function () {
53
+ var PAGES = [{
54
+ id: 'page1',
55
+ collection: {
56
+ name: 'parent'
57
+ },
58
+ components: [TEXT_COMP]
59
+ }, {
60
+ id: 'page2',
61
+ collection: {
62
+ name: 'parent'
63
+ },
64
+ components: [DATE_COMP]
65
+ }, {
66
+ id: 'page3',
67
+ collection: {
68
+ name: 'parent.child'
69
+ },
70
+ components: [DATE_COMP]
71
+ }, {
72
+ id: 'page4',
73
+ collection: {
74
+ name: 'parent.child'
75
+ },
76
+ components: [DATE_COMP]
77
+ }];
78
+ var RESULT = (0, _mergeCollectionPages.default)(PAGES);
79
+ expect(RESULT.length).toEqual(1);
80
+ expect(RESULT[0]).toMatchObject({
81
+ id: 'page1',
82
+ collection: {
83
+ name: 'parent',
84
+ masterPage: true
85
+ },
86
+ formData: {},
87
+ childPages: [PAGES[0], PAGES[1], {
88
+ id: 'page3',
89
+ collection: {
90
+ name: 'parent.child',
91
+ masterPage: true
92
+ },
93
+ formData: {},
94
+ childPages: [PAGES[2], PAGES[3]]
95
+ }]
50
96
  });
51
97
  });
52
98
  it('should leave non-collection pages unaffected', function () {
@@ -74,7 +120,7 @@ describe('utils.CollectionPage.mergeCollectionPages', function () {
74
120
  masterPage: true
75
121
  },
76
122
  formData: {},
77
- collectionPages: [PAGES[0], PAGES[1]]
123
+ childPages: [PAGES[0], PAGES[1]]
78
124
  });
79
125
  expect(RESULT[1]).toEqual({
80
126
  id: 'page3'
@@ -115,7 +161,7 @@ describe('utils.CollectionPage.mergeCollectionPages', function () {
115
161
  masterPage: true
116
162
  },
117
163
  formData: {},
118
- collectionPages: [PAGES[0], PAGES[1]]
164
+ childPages: [PAGES[0], PAGES[1]]
119
165
  });
120
166
  expect(RESULT[1]).toEqual({
121
167
  id: 'page3',
@@ -124,7 +170,7 @@ describe('utils.CollectionPage.mergeCollectionPages', function () {
124
170
  masterPage: true
125
171
  },
126
172
  formData: {},
127
- collectionPages: [PAGES[2], PAGES[3]]
173
+ childPages: [PAGES[2], PAGES[3]]
128
174
  });
129
175
  });
130
176
  });
@@ -29,7 +29,7 @@ _dayjs.default.extend(_customParseFormat.default);
29
29
  * the date/time component can't be found.
30
30
  */
31
31
  var mustBeEarlierDateTime = function mustBeEarlierDateTime(data, config, container) {
32
- var _container$components, _container$components2, _data$container$field, _data$container$field2;
32
+ var _container$components, _container$components2, _data$container$field, _data$container$field2, _data$container$field3, _data$container$field4;
33
33
  var date = (_container$components = container.components) === null || _container$components === void 0 ? void 0 : _container$components.find(function (c) {
34
34
  return c.fieldId === config.date;
35
35
  });
@@ -39,6 +39,11 @@ var mustBeEarlierDateTime = function mustBeEarlierDateTime(data, config, contain
39
39
  if (!date || !time || !data) {
40
40
  return false;
41
41
  }
42
+ var dateFromData = (_data$container$field = data[container.fieldId]) === null || _data$container$field === void 0 ? void 0 : _data$container$field[config.date];
43
+ var timeFromData = (_data$container$field2 = data[container.fieldId]) === null || _data$container$field2 === void 0 ? void 0 : _data$container$field2[config.time];
44
+ if (!dateFromData || !timeFromData) {
45
+ return true;
46
+ }
42
47
  // Here we return true if there are errors with the date & time components
43
48
  // individually. This is to allow them to process their errors, and to prevent
44
49
  // validation from stopping at the container level.
@@ -48,8 +53,8 @@ var mustBeEarlierDateTime = function mustBeEarlierDateTime(data, config, contain
48
53
  if ((0, _validateComponent.default)(time, data[container.fieldId], data[container.fieldId])) {
49
54
  return true;
50
55
  }
51
- var dateStr = (0, _utils.formatString)((_data$container$field = data[container.fieldId]) === null || _data$container$field === void 0 ? void 0 : _data$container$field[config.date]);
52
- var timeStr = (0, _utils.formattedTime)((_data$container$field2 = data[container.fieldId]) === null || _data$container$field2 === void 0 ? void 0 : _data$container$field2[config.time]);
56
+ var dateStr = (0, _utils.formatString)((_data$container$field3 = data[container.fieldId]) === null || _data$container$field3 === void 0 ? void 0 : _data$container$field3[config.date]);
57
+ var timeStr = (0, _utils.formattedTime)((_data$container$field4 = data[container.fieldId]) === null || _data$container$field4 === void 0 ? void 0 : _data$container$field4[config.time]);
53
58
  return (0, _dayjs.default)("".concat(dateStr, " ").concat(timeStr), "".concat(_utils.DATE_FORMAT, " HH:mm")).isBefore((0, _dayjs.default)());
54
59
  };
55
60
  var _default = mustBeEarlierDateTime;
@@ -70,6 +70,27 @@ describe('utils.Validate.additional.mustBeEarlierDateTime', function () {
70
70
  var result = (0, _mustBeEarlierDateTime.default)(EDITED_DATA, CONFIG, CONTAINER);
71
71
  expect(result).toEqual(true);
72
72
  });
73
+ test('should return true if time value is missing and optional', function () {
74
+ var EDITED_DATA = {
75
+ testContainer: {
76
+ testDate: '01-01-2000'
77
+ }
78
+ };
79
+ var EDITED_CONTAINER = {
80
+ fieldId: 'testContainer',
81
+ type: 'container',
82
+ components: [{
83
+ fieldId: 'testDate',
84
+ type: 'date',
85
+ required: true
86
+ }, {
87
+ fieldId: 'testTime',
88
+ type: 'time'
89
+ }]
90
+ };
91
+ var result = (0, _mustBeEarlierDateTime.default)(EDITED_DATA, CONFIG, EDITED_CONTAINER);
92
+ expect(result).toEqual(true);
93
+ });
73
94
  test('should return true if date has errors', function () {
74
95
  var EDITED_DATA = {
75
96
  testContainer: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukhomeoffice/cop-react-form-renderer",
3
- "version": "5.23.0",
3
+ "version": "5.24.0",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "clean": "rimraf dist",
@@ -27,7 +27,7 @@
27
27
  "@babel/eslint-parser": "^7.19.1",
28
28
  "@babel/preset-env": "^7.15.6",
29
29
  "@babel/preset-react": "^7.14.5",
30
- "@monaco-editor/react": "^4.3.1",
30
+ "@monaco-editor/react": "4.4.6",
31
31
  "@storybook/addon-a11y": "^6.3.8",
32
32
  "@storybook/addon-actions": "^6.3.8",
33
33
  "@storybook/addon-docs": "^6.3.8",