@ukhomeoffice/cop-react-form-renderer 6.0.6-peter → 6.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/components/CheckYourAnswers/CheckYourAnswers.scss +2 -2
  2. package/dist/components/CollectionPage/CollectionPage.js +8 -2
  3. package/dist/components/CollectionSummary/BannerStrip.js +3 -2
  4. package/dist/components/CollectionSummary/BannerStrip.scss +2 -2
  5. package/dist/components/CollectionSummary/BannerStrip.test.js +39 -4
  6. package/dist/components/CollectionSummary/CollectionSummary.js +82 -63
  7. package/dist/components/CollectionSummary/CollectionSummary.scss +1 -1
  8. package/dist/components/CollectionSummary/CollectionSummary.test.js +40 -80
  9. package/dist/components/CollectionSummary/Confirmation.scss +1 -1
  10. package/dist/components/CollectionSummary/RenderListView.js +23 -19
  11. package/dist/components/CollectionSummary/RenderListView.scss +11 -2
  12. package/dist/components/CollectionSummary/RenderListView.test.js +14 -4
  13. package/dist/components/CollectionSummary/SummaryCard.js +61 -40
  14. package/dist/components/CollectionSummary/SummaryCard.scss +2 -1
  15. package/dist/components/CollectionSummary/SummaryCard.test.js +193 -150
  16. package/dist/components/CollectionSummary/SummaryCardDetails.js +70 -13
  17. package/dist/components/CollectionSummary/SummaryCardDetails.scss +45 -8
  18. package/dist/components/CollectionSummary/SummaryCardDetails.test.js +174 -26
  19. package/dist/components/CollectionSummary/SummaryCardValidationContext.js +15 -5
  20. package/dist/components/CollectionSummary/SummaryCardValidationContext.test.js +5 -4
  21. package/dist/components/FormComponent/Collection.js +24 -17
  22. package/dist/components/FormComponent/Collection.test.js +138 -0
  23. package/dist/components/FormComponent/FormComponent.js +12 -0
  24. package/dist/components/FormPage/FormPage.scss +1 -1
  25. package/dist/components/FormRenderer/FormRenderer.js +7 -4
  26. package/dist/components/FormRenderer/FormRenderer.scss +1 -1
  27. package/dist/components/FormRenderer/helpers/index.js +1 -3
  28. package/dist/components/FormRenderer/onPageAction.js +7 -9
  29. package/dist/components/FormRenderer/onPageAction.test.js +18 -9
  30. package/dist/components/SummaryList/SummaryList.scss +2 -2
  31. package/dist/components/TaskList/TaskList.scss +1 -1
  32. package/dist/context/ValidationContext/ValidationContext.js +49 -5
  33. package/dist/context/ValidationContext/ValidationContext.test.js +16 -7
  34. package/dist/hooks/useRefData.js +1 -1
  35. package/dist/utils/CheckYourAnswers/showComponentCYA.js +1 -2
  36. package/dist/utils/CheckYourAnswers/showComponentCYA.test.js +5 -0
  37. package/dist/utils/CollectionPage/addCollectionPageEntry.js +1 -2
  38. package/dist/utils/CollectionPage/addCollectionPageEntry.test.js +4 -24
  39. package/dist/utils/CollectionPage/duplicateCollectionPageEntry.js +22 -2
  40. package/dist/utils/CollectionPage/duplicateCollectionPageEntry.test.js +39 -4
  41. package/dist/utils/CollectionPage/getErrorsForCollection.js +55 -0
  42. package/dist/utils/CollectionPage/getErrorsForCollection.test.js +155 -0
  43. package/dist/utils/CollectionPage/getQuickEditPage.js +14 -5
  44. package/dist/utils/CollectionPage/getQuickEditPage.test.js +14 -29
  45. package/dist/utils/CollectionPage/index.js +2 -0
  46. package/dist/utils/CollectionPage/mergeCollectionPages.js +0 -1
  47. package/dist/utils/CollectionPage/setCollectionPageData.js +9 -4
  48. package/dist/utils/CollectionPage/setCollectionPageData.test.js +18 -0
  49. package/dist/utils/Component/isEditable.js +1 -1
  50. package/dist/utils/Condition/meetsCondition.js +18 -0
  51. package/dist/utils/Condition/meetsCondition.test.js +100 -0
  52. package/dist/utils/Data/getOptions.js +10 -0
  53. package/dist/utils/Data/getOptions.test.js +73 -0
  54. package/dist/utils/Data/nestInRefdataOptions.js +49 -0
  55. package/dist/utils/Data/nestInRefdataOptions.test.js +236 -0
  56. package/dist/utils/Validate/additional/mustBeUniqueInCollection.js +4 -0
  57. package/dist/utils/Validate/additional/mustBeUniqueInCollection.test.js +36 -0
  58. package/dist/utils/Validate/validateContainer.js +3 -1
  59. package/dist/utils/Validate/validateContainer.test.js +33 -0
  60. package/dist/utils/Validate/validateEmail.js +1 -1
  61. package/dist/utils/Validate/validatePage.js +10 -1
  62. package/dist/utils/Validate/validatePage.test.js +69 -0
  63. package/package.json +4 -4
  64. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/component-used-in-multiple-pages-data.json +0 -4
  65. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/component-used-in-multiple-pages-form.json +0 -61
  66. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/data-with-collection-data-removed.json +0 -4
  67. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/data-with-collections.json +0 -8
  68. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/data-with-components-removed.json +0 -3
  69. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/data-with-components.json +0 -5
  70. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/data-with-entire-collection-removed.json +0 -3
  71. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/data-with-nested-component-removed.json +0 -10
  72. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/data-with-nested-components.json +0 -11
  73. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/form-for-nested-components.json +0 -96
  74. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/form-with-collections-delete-entire.json +0 -47
  75. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/form-with-collections.json +0 -46
  76. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/form-with-components.json +0 -48
  77. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.js +0 -175
  78. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.test.js +0 -113
  79. package/dist/components/FormRenderer/helpers/deleteNodeByPath.js +0 -20
  80. package/dist/components/FormRenderer/helpers/deleteNodeByPath.test.js +0 -56
@@ -1,5 +1,5 @@
1
- @import "node_modules/govuk-frontend/govuk/_base";
2
- @import "node_modules/govuk-frontend/govuk/overrides/spacing";
1
+ @import "govuk-frontend/dist/govuk/_base";
2
+ @import "govuk-frontend/dist/govuk/overrides/spacing";
3
3
 
4
4
  .govuk-link {
5
5
  @include govuk-font($size: 19);
@@ -29,8 +29,9 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // Global
29
29
  // Styles
30
30
  var DEFAULT_CLASS = exports.DEFAULT_CLASS = _FormPage2.DEFAULT_CLASS;
31
31
  var CollectionPage = function CollectionPage(_ref) {
32
- var _page$collection, _objectSpread4;
32
+ var _page$collection, _objectSpread5;
33
33
  var page = _ref.page,
34
+ pages = _ref.pages,
34
35
  onCollectionChange = _ref.onCollectionChange,
35
36
  onAction = _ref.onAction,
36
37
  hashLink = _ref.hashLink,
@@ -67,6 +68,9 @@ var CollectionPage = function CollectionPage(_ref) {
67
68
  var onTopLevelChange = function onTopLevelChange(_ref3) {
68
69
  var target = _ref3.target;
69
70
  currentPage.formData[target.name] = target.value;
71
+ setPatch(function (prev) {
72
+ return _objectSpread(_objectSpread({}, prev), {}, _defineProperty({}, target.name, target.value));
73
+ });
70
74
  };
71
75
  var reportChange = function reportChange(newValue) {
72
76
  onPageChange({
@@ -120,13 +124,14 @@ var CollectionPage = function CollectionPage(_ref) {
120
124
  }
121
125
  return /*#__PURE__*/_react.default.createElement(_FormPage.default, {
122
126
  page: _objectSpread(_objectSpread({}, page), {}, {
123
- formData: _objectSpread(_objectSpread(_objectSpread({}, page.formData), data[activeIndex]), {}, (_objectSpread4 = {}, _defineProperty(_objectSpread4, "".concat(currentCollectionName, "ActiveIndex"), activeIndex), _defineProperty(_objectSpread4, "".concat(currentCollectionName, "NumberedIndex"), typeof activeIndex === 'number' ? activeIndex + 1 : null), _objectSpread4)),
127
+ formData: _objectSpread(_objectSpread(_objectSpread({}, page.formData), data[activeIndex]), {}, (_objectSpread5 = {}, _defineProperty(_objectSpread5, "".concat(currentCollectionName, "ActiveIndex"), activeIndex), _defineProperty(_objectSpread5, "".concat(currentCollectionName, "NumberedIndex"), typeof activeIndex === 'number' ? activeIndex + 1 : null), _objectSpread5)),
124
128
  components: page.components.map(function (component) {
125
129
  return _objectSpread(_objectSpread({}, component), {}, {
126
130
  pageCollection: _objectSpread({}, page.collection)
127
131
  });
128
132
  })
129
133
  }),
134
+ pages: pages,
130
135
  onAction: onInnerPageAction,
131
136
  onWrapperChange: onInnerPageChange,
132
137
  onTopLevelChange: onTopLevelChange,
@@ -149,6 +154,7 @@ CollectionPage.propTypes = {
149
154
  actions: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.shape({}), _propTypes.default.string])),
150
155
  formData: _propTypes.default.shape({}).isRequired
151
156
  }).isRequired,
157
+ pages: _propTypes.default.arrayOf(_propTypes.default.shape({})).isRequired,
152
158
  onCollectionChange: _propTypes.default.func,
153
159
  onAction: _propTypes.default.func.isRequired,
154
160
  hashLink: _propTypes.default.bool,
@@ -31,13 +31,14 @@ var BannerStrip = function BannerStrip(_ref) {
31
31
  className: classes()
32
32
  }, filteredBanners.map(function (banner, index) {
33
33
  var bannerId = "".concat(id, "-banner-").concat(index);
34
- if (typeof banner === 'string') {
34
+ if (typeof banner === 'string' || banner.type === 'plain') {
35
+ var bannerText = typeof banner === 'string' ? banner : banner.text;
35
36
  return /*#__PURE__*/_react.default.createElement("div", {
36
37
  id: bannerId,
37
38
  key: bannerId,
38
39
  className: classes('banner')
39
40
  }, /*#__PURE__*/_react.default.createElement(_copReactComponents.Markup, {
40
- content: _utils.default.interpolateString(banner, formData)
41
+ content: _utils.default.interpolateString(bannerText, formData)
41
42
  }));
42
43
  }
43
44
  return /*#__PURE__*/_react.default.createElement(_copReactComponents.Tag, {
@@ -1,5 +1,5 @@
1
- @import "node_modules/govuk-frontend/govuk/_base";
2
- @import "node_modules/govuk-frontend/govuk/components/tag/_index";
1
+ @import "govuk-frontend/dist/govuk/_base";
2
+ @import "govuk-frontend/dist/govuk/components/tag/_index";
3
3
 
4
4
  .hods-form-banner-strip {
5
5
  display: block;
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
 
3
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
3
  var _copReactComponents = require("@ukhomeoffice/cop-react-components");
5
4
  var _react = _interopRequireDefault(require("react"));
6
5
  var _setupTests = require("../../setupTests");
@@ -8,10 +7,13 @@ var _BannerStrip = _interopRequireWildcard(require("./BannerStrip"));
8
7
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
9
8
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
10
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
- // Global imports.
12
-
10
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
11
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
12
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
13
+ 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; }
14
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
15
+ 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.
13
16
  // Local imports.
14
-
15
17
  describe('components.CollectionSummary.BannerStrip', function () {
16
18
  var ID = 'testBanner';
17
19
  var BANNERS = ['Banner 1', 'Banner 2'];
@@ -123,4 +125,37 @@ describe('components.CollectionSummary.BannerStrip', function () {
123
125
  expect(plainStringBanner.classList.contains(classes('banner'))).toBe(true);
124
126
  expect(plainStringBanner.textContent).toEqual(PLAIN_STRING_BANNER);
125
127
  });
128
+ it('should correctly render banners based on their show_whens', function () {
129
+ var CUSTOM_BANNERS = [{
130
+ type: 'plain',
131
+ text: 'A banner',
132
+ show_when: [{
133
+ field: 'testField',
134
+ op: '=',
135
+ value: '123'
136
+ }]
137
+ }, {
138
+ type: 'plain',
139
+ text: BANNERS[1]
140
+ }];
141
+ var CUSTOM_FORM_DATA = _objectSpread(_objectSpread({}, FORM_DATA), {}, {
142
+ testField: 'abc'
143
+ });
144
+ var _renderWithValidation6 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react.default.createElement(_BannerStrip.default, {
145
+ id: ID,
146
+ banners: CUSTOM_BANNERS,
147
+ formData: CUSTOM_FORM_DATA
148
+ })),
149
+ container = _renderWithValidation6.container;
150
+ var bannerStripDiv = checkSetup(container);
151
+ expect(bannerStripDiv.tagName).toEqual('DIV');
152
+ expect(bannerStripDiv.classList).toContain(_BannerStrip.DEFAULT_CLASS);
153
+ expect(bannerStripDiv.children.length).toEqual(1); // One banner should be hidden.
154
+
155
+ // Only the second banner should be visible.
156
+ var secondBanner = bannerStripDiv.children[0];
157
+ expect(secondBanner.tagName).toEqual('DIV');
158
+ expect(secondBanner.classList).toContain(classes('banner'));
159
+ expect(secondBanner.textContent).toEqual(CUSTOM_BANNERS[1].text);
160
+ });
126
161
  });
@@ -9,18 +9,22 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _react = _interopRequireWildcard(require("react"));
10
10
  var _hooks = require("../../hooks");
11
11
  var _PageAction = require("../../models/PageAction");
12
+ var _elevateNestedComponents = _interopRequireDefault(require("../../utils/Component/elevateNestedComponents"));
13
+ var _getErrorsForCollection = _interopRequireDefault(require("../../utils/CollectionPage/getErrorsForCollection"));
12
14
  var _utils = _interopRequireDefault(require("../../utils"));
13
15
  var _getCYARow = _interopRequireDefault(require("../../utils/CheckYourAnswers/getCYARow"));
14
- var _elevateNestedComponents = _interopRequireDefault(require("../../utils/Component/elevateNestedComponents"));
15
16
  var _Answer = _interopRequireDefault(require("../CheckYourAnswers/Answer"));
16
17
  var _ActionButton = _interopRequireDefault(require("../PageActions/ActionButton"));
17
18
  var _Confirmation = _interopRequireDefault(require("./Confirmation"));
18
19
  var _SummaryCard = _interopRequireDefault(require("./SummaryCard"));
19
20
  var _SummaryCardValidationContext = _interopRequireDefault(require("./SummaryCardValidationContext"));
20
21
  require("./CollectionSummary.scss");
22
+ var _excluded = ["isDuplicate"];
21
23
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
22
24
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
23
25
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
26
+ 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; }
27
+ 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; }
24
28
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
25
29
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
26
30
  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; }
@@ -54,11 +58,17 @@ var CollectionSummary = function CollectionSummary(_ref) {
54
58
  formData = _ref.formData,
55
59
  onAction = _ref.onAction,
56
60
  onChange = _ref.onChange,
61
+ onTopLevelChange = _ref.onTopLevelChange,
57
62
  pages = _ref.pages;
63
+ var _useHooks = (0, _hooks.useHooks)(),
64
+ hooks = _useHooks.hooks;
58
65
  var _useValidation = (0, _hooks.useValidation)(),
59
66
  errors = _useValidation.errors,
60
67
  addErrors = _useValidation.addErrors,
61
- clearErrors = _useValidation.clearErrors;
68
+ clearErrors = _useValidation.clearErrors,
69
+ queuedErrors = _useValidation.queuedErrors,
70
+ enqueueErrors = _useValidation.enqueueErrors,
71
+ dequeueErrors = _useValidation.dequeueErrors;
62
72
  var _useState = (0, _react.useState)(null),
63
73
  _useState2 = _slicedToArray(_useState, 2),
64
74
  entryToDelete = _useState2[0],
@@ -98,46 +108,21 @@ var CollectionSummary = function CollectionSummary(_ref) {
98
108
  return [];
99
109
  }, [masterPage, formData, entryToDelete, config.card.listView]);
100
110
  var validateEntries = function validateEntries() {
101
- var stored = [];
102
- // We only clear errors if it's not empty to avoid
111
+ // We only clear queuedErrors if it's not empty to avoid
103
112
  // triggering a race condition with the 'data' memo
104
113
  // above.
105
- if (errors.length > 0) {
106
- stored = errors.filter(function (e) {
107
- return e.id === config.id;
108
- });
109
- clearErrors();
110
- }
111
- var allErrors = [];
112
- data.forEach(function (entry) {
113
- // Validation of a collection page uses the data from the
114
- // active entry, so here we have to set the active ID before
115
- // validating.
116
- var childPages = masterPage === null || masterPage === void 0 ? void 0 : masterPage.childPages.map(function (page) {
117
- return _objectSpread(_objectSpread({}, page), {}, {
118
- formData: _objectSpread(_objectSpread({}, masterPage.formData), {}, _defineProperty({}, "".concat(config.collectionName, "ActiveId"), entry.id))
119
- });
120
- });
121
- var allPagesErrors = (childPages === null || childPages === void 0 ? void 0 : childPages.flatMap(function (page) {
122
- return _utils.default.Validate.page(page);
123
- })) || [];
124
- // For each error we found, add the entryId so we know what Summary Card
125
- // we have to pass it to.
126
- var entryErrors = allPagesErrors.map(function (e) {
127
- return _objectSpread(_objectSpread({}, e), {}, {
128
- entryId: entry.id
129
- });
114
+ if (queuedErrors.length > 0) {
115
+ dequeueErrors(function (e) {
116
+ return e.raisedBy === config.id;
130
117
  });
131
- allErrors = allErrors.concat(entryErrors);
132
- });
133
- if (stored.length > 0) {
134
- allErrors = allErrors.concat(stored);
135
118
  }
136
- // We only add allErrors if it's not empty to avoid
119
+ var allErrors = (0, _getErrorsForCollection.default)(config, masterPage, formData, hooks);
120
+
121
+ // We only queue allErrors if it's not empty to avoid
137
122
  // triggering a race condition with the 'data' memo
138
123
  // above.
139
124
  if (allErrors.length > 0) {
140
- addErrors(allErrors);
125
+ enqueueErrors(allErrors);
141
126
  }
142
127
  };
143
128
  (0, _react.useEffect)(function () {
@@ -147,30 +132,43 @@ var CollectionSummary = function CollectionSummary(_ref) {
147
132
  validateEntries();
148
133
  }
149
134
  }, [data]);
150
- var onSummaryCardChange = function onSummaryCardChange(page, entryId) {
151
- if (typeof onAction !== 'function') {
152
- return;
135
+ var onSummaryCardFullEdit = function onSummaryCardFullEdit(page, entryId) {
136
+ if (typeof onAction === 'function') {
137
+ var newData = [].concat(data);
138
+ var entryIndex = data.findIndex(function (e) {
139
+ return e.id === entryId;
140
+ });
141
+ var _data$entryIndex = data[entryIndex],
142
+ isDuplicate = _data$entryIndex.isDuplicate,
143
+ newEntry = _objectWithoutProperties(_data$entryIndex, _excluded);
144
+ newData[entryIndex] = _objectSpread({}, newEntry);
145
+ onAction({
146
+ type: _PageAction.PageActionTypes.SAVE_AND_NAVIGATE,
147
+ page: page,
148
+ addToFormData: [{
149
+ field: "".concat(config.collectionName.split('.').pop(), "ActiveId"),
150
+ value: entryId
151
+ }, {
152
+ field: config.collectionName,
153
+ value: newData,
154
+ isCollection: true
155
+ }]
156
+ });
153
157
  }
154
- onAction({
155
- type: _PageAction.PageActionTypes.SAVE_AND_NAVIGATE,
156
- page: page,
157
- addToFormData: {
158
- field: "".concat(config.collectionName.split('.').pop(), "ActiveId"),
159
- value: entryId
160
- }
161
- });
162
158
  };
163
159
  var onDuplicate = function onDuplicate(entry) {
164
160
  var _config$card;
165
- _utils.default.CollectionPage.duplicateEntry(config.collectionName, formData, entry.id, ((_config$card = config.card) === null || _config$card === void 0 || (_config$card = _config$card.duplicateAction) === null || _config$card === void 0 ? void 0 : _config$card.fieldsToIgnore) || []);
166
- var parentCollection = config.collectionName.split('.').shift();
161
+ _utils.default.CollectionPage.duplicateEntry(config.collectionName, formData, entry.id, ((_config$card = config.card) === null || _config$card === void 0 || (_config$card = _config$card.duplicateAction) === null || _config$card === void 0 ? void 0 : _config$card.fieldsToIgnore) || [], {
162
+ isDuplicate: true
163
+ });
164
+ var topLevelCollectionName = config.collectionName.split('.').shift();
167
165
  // Report the whole top-level collection as being changed. We have to do this
168
166
  // because of how patch is applied to formData on a page submission.
169
- if (typeof onChange === 'function') {
170
- onChange({
167
+ if (typeof onTopLevelChange === 'function') {
168
+ onTopLevelChange({
171
169
  target: {
172
- name: parentCollection,
173
- value: _utils.default.CollectionPage.getData(parentCollection, formData)
170
+ name: topLevelCollectionName,
171
+ value: _utils.default.CollectionPage.getData(topLevelCollectionName, formData)
174
172
  }
175
173
  });
176
174
  validateEntries();
@@ -181,14 +179,14 @@ var CollectionSummary = function CollectionSummary(_ref) {
181
179
  return;
182
180
  }
183
181
  _utils.default.CollectionPage.removeEntry(config.collectionName, formData, entryToDelete.id);
184
- var parentCollection = config.collectionName.split('.').shift();
182
+ var topLevelCollectionName = config.collectionName.split('.').shift();
185
183
  // Report the whole top-level collection as being changed. We have to do this
186
184
  // because of how patch is applied to formData on a page submission.
187
- if (typeof onChange === 'function') {
188
- onChange({
185
+ if (typeof onTopLevelChange === 'function') {
186
+ onTopLevelChange({
189
187
  target: {
190
- name: parentCollection,
191
- value: _utils.default.CollectionPage.getData(parentCollection, formData)
188
+ name: topLevelCollectionName,
189
+ value: _utils.default.CollectionPage.getData(topLevelCollectionName, formData)
192
190
  }
193
191
  });
194
192
  }
@@ -216,7 +214,9 @@ var CollectionSummary = function CollectionSummary(_ref) {
216
214
  id: config.fieldId
217
215
  }, entryToDelete && /*#__PURE__*/_react.default.createElement(_Confirmation.default, {
218
216
  id: "".concat(config.fieldId, ".confirmation"),
219
- message: _utils.default.interpolateString((_config$confirmation = config.confirmation) === null || _config$confirmation === void 0 ? void 0 : _config$confirmation.message, entryToDelete) || null,
217
+ message: _utils.default.interpolateString((_config$confirmation = config.confirmation) === null || _config$confirmation === void 0 ? void 0 : _config$confirmation.message, _objectSpread(_objectSpread({}, entryToDelete), {}, {
218
+ index: entryToDelete.index + 1
219
+ })) || null,
220
220
  confirmLabel: _utils.default.interpolateString((_config$confirmation2 = config.confirmation) === null || _config$confirmation2 === void 0 ? void 0 : _config$confirmation2.label, entryToDelete) || null,
221
221
  onConfirm: onDeleteConfirm,
222
222
  onCancel: function onCancel() {
@@ -247,11 +247,18 @@ var CollectionSummary = function CollectionSummary(_ref) {
247
247
  var isInError = errors.filter(function (e) {
248
248
  return e.entryId === entry.id;
249
249
  }).length > 0;
250
- var finalConfig = _objectSpread(_objectSpread({}, config.card), isInError && config.errorCard ? config.errorCard : {});
250
+ var finalConfig = _objectSpread(_objectSpread(_objectSpread({}, config.card), entry.isDuplicate && config.duplicatedCard ? config.duplicatedCard : {}), isInError && config.errorCard ? config.errorCard : {});
251
251
  var key = "".concat(config.fieldId, ".summaryCard").concat(entry.id);
252
252
  return /*#__PURE__*/_react.default.createElement(_SummaryCardValidationContext.default, {
253
253
  entryId: entry.id,
254
- topLevelErrors: errors
254
+ topLevelErrors: errors,
255
+ clearTopLevelErrorsForCard: function clearTopLevelErrorsForCard() {
256
+ var newErrors = errors.filter(function (e) {
257
+ return e.entryId !== entry.id;
258
+ });
259
+ clearErrors();
260
+ addErrors(newErrors);
261
+ }
255
262
  }, /*#__PURE__*/_react.default.createElement(_SummaryCard.default, {
256
263
  id: key,
257
264
  key: key,
@@ -260,10 +267,12 @@ var CollectionSummary = function CollectionSummary(_ref) {
260
267
  }),
261
268
  masterPage: masterPage,
262
269
  config: finalConfig || {},
263
- onChange: onSummaryCardChange,
270
+ onFullEdit: onSummaryCardFullEdit,
264
271
  onDuplicate: onDuplicate,
265
272
  onDelete: function onDelete() {
266
- return setEntryToDelete(entry);
273
+ return setEntryToDelete(_objectSpread(_objectSpread({}, entry), {}, {
274
+ index: index
275
+ }));
267
276
  },
268
277
  onQuickEdit: function onQuickEdit(target) {
269
278
  validateEntries();
@@ -272,7 +281,7 @@ var CollectionSummary = function CollectionSummary(_ref) {
272
281
  parentCollectionName: config.collectionName.split('.').shift(),
273
282
  childCollections: config.childCollections || [],
274
283
  formData: formData,
275
- classModifiers: entry === entryToDelete ? ['deleting-summary-card'] : [''],
284
+ classModifiers: entry.id === (entryToDelete === null || entryToDelete === void 0 ? void 0 : entryToDelete.id) ? ['deleting-summary-card'] : [''],
276
285
  inError: errors.filter(function (e) {
277
286
  return e.entryId === entry.id;
278
287
  }).length > 0
@@ -315,6 +324,14 @@ CollectionSummary.propTypes = {
315
324
  fieldsToIgnore: _propTypes.default.arrayOf(_propTypes.default.string)
316
325
  })
317
326
  }),
327
+ duplicatedCard: _propTypes.default.shape({
328
+ banners: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.shape({})])),
329
+ title: _propTypes.default.string,
330
+ details: _propTypes.default.string,
331
+ duplicateAction: _propTypes.default.shape({
332
+ fieldsToIgnore: _propTypes.default.arrayOf(_propTypes.default.string)
333
+ })
334
+ }),
318
335
  confirmation: _propTypes.default.shape({
319
336
  message: _propTypes.default.string,
320
337
  label: _propTypes.default.string,
@@ -324,12 +341,14 @@ CollectionSummary.propTypes = {
324
341
  }).isRequired,
325
342
  onAction: _propTypes.default.func,
326
343
  onChange: _propTypes.default.func,
344
+ onTopLevelChange: _propTypes.default.func,
327
345
  formData: _propTypes.default.shape({}).isRequired,
328
346
  pages: _propTypes.default.arrayOf(_propTypes.default.shape({}))
329
347
  };
330
348
  CollectionSummary.defaultProps = {
331
349
  onAction: null,
332
350
  onChange: null,
351
+ onTopLevelChange: null,
333
352
  pages: []
334
353
  };
335
354
  var _default = exports.default = CollectionSummary;
@@ -1,4 +1,4 @@
1
- @import "node_modules/govuk-frontend/govuk/_base";
1
+ @import "govuk-frontend/dist/govuk/_base";
2
2
 
3
3
  .hods-form-summary-card.hods-form-summary-card--nested {
4
4
  box-shadow: none;
@@ -3,8 +3,6 @@
3
3
  var _react = _interopRequireDefault(require("react"));
4
4
  var _react2 = require("@testing-library/react");
5
5
  var _setupTests = require("../../setupTests");
6
- var _context = require("../../context");
7
- var _ValidationContext = require("../../context/ValidationContext");
8
6
  var _hooks = require("../../hooks");
9
7
  var _CollectionSummary = _interopRequireWildcard(require("./CollectionSummary"));
10
8
  var _Confirmation = require("./Confirmation");
@@ -75,11 +73,11 @@ describe('components.CollectionSummary.CollectionSummary', function () {
75
73
  expect(summary.children[0].id).toEqual("".concat(CONFIG.fieldId, ".summaryCard").concat(FORM_DATA.testCollection[0].id));
76
74
  expect(summary.children[1].id).toEqual("".concat(CONFIG.fieldId, ".summaryCard").concat(FORM_DATA.testCollection[1].id));
77
75
  });
78
- it('should correctly raise errors found when validating entries', function () {
76
+ it('should correctly queue errors found when validating entries', function () {
79
77
  var ErrorCheckComponent = function ErrorCheckComponent() {
80
78
  var _useValidation = (0, _hooks.useValidation)(),
81
- errors = _useValidation.errors;
82
- return /*#__PURE__*/_react.default.createElement("div", null, Array.isArray(errors) && "errors is an array of length ".concat(errors.length), (errors === null || errors === void 0 ? void 0 : errors.length) > 0 && errors.map(function (e) {
79
+ queuedErrors = _useValidation.queuedErrors;
80
+ return /*#__PURE__*/_react.default.createElement("div", null, Array.isArray(queuedErrors) && "queuedErrors is an array of length ".concat(queuedErrors.length), (queuedErrors === null || queuedErrors === void 0 ? void 0 : queuedErrors.length) > 0 && queuedErrors.map(function (e) {
83
81
  return e.error;
84
82
  }));
85
83
  };
@@ -91,7 +89,7 @@ describe('components.CollectionSummary.CollectionSummary', function () {
91
89
  }))),
92
90
  container = _renderWithValidation2.container;
93
91
  var errorChecker = container.children[0];
94
- expect(errorChecker.textContent).toContain('errors is an array of length 1');
92
+ expect(errorChecker.textContent).toContain('queuedErrors is an array of length 1');
95
93
  expect(errorChecker.textContent).toContain('testText is required');
96
94
  });
97
95
  it('should render a confirmation when a SummaryCard\'s delete button is pressed', function () {
@@ -110,80 +108,6 @@ describe('components.CollectionSummary.CollectionSummary', function () {
110
108
  expect(summary.children[0].id).toEqual("".concat(CONFIG.fieldId, ".confirmation"));
111
109
  expect(summary.children[0].classList).toContain(_Confirmation.DEFAULT_CLASS);
112
110
  });
113
- it('should keep higher level errors that relate to the CollectionSummary', function () {
114
- var errors = [{
115
- id: 'testSummary',
116
- error: 'add at least one'
117
- }];
118
- var clearErrorCount = 0;
119
- var errorsAdded = [];
120
- var clearErrors = function clearErrors() {
121
- clearErrorCount += 1;
122
- };
123
- var addErrors = function addErrors(newErrors) {
124
- errorsAdded = errorsAdded.concat(newErrors);
125
- };
126
- (0, _react2.render)( /*#__PURE__*/_react.default.createElement(_context.HooksContextProvider, null, /*#__PURE__*/_react.default.createElement(_ValidationContext.ValidationContext.Provider, {
127
- value: {
128
- errors: errors,
129
- clearErrors: clearErrors,
130
- addErrors: addErrors,
131
- validate: function validate() {}
132
- }
133
- }, /*#__PURE__*/_react.default.createElement(_CollectionSummary.default, {
134
- config: _objectSpread(_objectSpread({}, CONFIG), {}, {
135
- required: true
136
- }),
137
- formData: _objectSpread(_objectSpread({}, FORM_DATA), {}, {
138
- testCollection: [{
139
- id: '000',
140
- testText: 'value'
141
- }]
142
- }),
143
- onAction: ON_ACTION,
144
- pages: PAGES
145
- }))));
146
- expect(clearErrorCount).toEqual(1);
147
- expect(errorsAdded[0]).toEqual({
148
- id: 'testSummary',
149
- error: 'add at least one'
150
- });
151
- });
152
- it('should ignore higher level errors that do not relate to the CollectionSummary', function () {
153
- var errors = [{
154
- id: 'somethingElse',
155
- error: 'add at least one'
156
- }];
157
- var clearErrorCount = 0;
158
- var errorsAdded = [];
159
- var clearErrors = function clearErrors() {
160
- clearErrorCount += 1;
161
- };
162
- var addErrors = function addErrors(newErrors) {
163
- errorsAdded = errorsAdded.concat(newErrors);
164
- };
165
- (0, _react2.render)( /*#__PURE__*/_react.default.createElement(_context.HooksContextProvider, null, /*#__PURE__*/_react.default.createElement(_ValidationContext.ValidationContext.Provider, {
166
- value: {
167
- errors: errors,
168
- clearErrors: clearErrors,
169
- addErrors: addErrors
170
- }
171
- }, /*#__PURE__*/_react.default.createElement(_CollectionSummary.default, {
172
- config: _objectSpread(_objectSpread({}, CONFIG), {}, {
173
- required: true
174
- }),
175
- formData: _objectSpread(_objectSpread({}, FORM_DATA), {}, {
176
- testCollection: [{
177
- id: '000',
178
- testText: 'value'
179
- }]
180
- }),
181
- onAction: ON_ACTION,
182
- pages: PAGES
183
- }))));
184
- expect(clearErrorCount).toEqual(1);
185
- expect(errorsAdded.length).toEqual(0);
186
- });
187
111
  describe('Add Another button', function () {
188
112
  it('should render with an Add button if one is configured', function () {
189
113
  var CONFIG_WITH_BUTTON = {
@@ -313,5 +237,41 @@ describe('components.CollectionSummary.CollectionSummary', function () {
313
237
  expect(fieldElement).not.toBeNull();
314
238
  });
315
239
  });
240
+ it('should correctly render field values in confirmation view with index', function () {
241
+ var listViewConfig = _objectSpread(_objectSpread({}, CONFIG), {}, {
242
+ card: _objectSpread(_objectSpread({}, CONFIG.card), {}, {
243
+ listView: true
244
+ }),
245
+ confirmation: {
246
+ displayFields: ['testText'],
247
+ // eslint-disable-next-line no-template-curly-in-string
248
+ message: 'Test confirmation message with index number ${index}'
249
+ }
250
+ });
251
+ var _renderWithValidation10 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react.default.createElement(_CollectionSummary.default, {
252
+ config: listViewConfig,
253
+ formData: FORM_DATA,
254
+ onAction: ON_ACTION,
255
+ pages: PAGES
256
+ })),
257
+ container = _renderWithValidation10.container,
258
+ getByText = _renderWithValidation10.getByText;
259
+ var summary = checkSetup(container);
260
+ expect(summary.children.length).toEqual(2);
261
+ var card = summary.children[0];
262
+ var deleteButton = card.querySelector('.govuk-summary-card__actions li:last-child button');
263
+ _react2.fireEvent.click(deleteButton);
264
+ var confirmation = container.querySelector(".".concat(_Confirmation.DEFAULT_CLASS));
265
+ expect(confirmation).toBeTruthy();
266
+ listViewConfig.confirmation.displayFields.forEach(function (field) {
267
+ var fieldValue = FORM_DATA.testCollection[0][field];
268
+ var fieldElement = getByText(fieldValue);
269
+ expect(fieldElement).not.toBeNull();
270
+ });
271
+
272
+ // Check if the confirmation message contains the index
273
+ var confirmationMessage = confirmation.querySelector('h2').textContent;
274
+ expect(confirmationMessage).toContain("Test confirmation message with index number 1");
275
+ });
316
276
  });
317
277
  });
@@ -1,6 +1,6 @@
1
1
  $govuk-font-family: 'Roboto', arial, sans-serif;
2
2
 
3
- @import "node_modules/govuk-frontend/govuk/_base";
3
+ @import "govuk-frontend/dist/govuk/_base";
4
4
 
5
5
  .hods-form-confirmation {
6
6
  background-color: #E3E3E3;