@ukhomeoffice/cop-react-form-renderer 3.12.0 → 3.16.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,21 +1,15 @@
1
1
  <!-- Global imports -->
2
2
 
3
3
  import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
4
- import {
5
- Details,
6
- Heading,
7
- Link,
8
- Tag,
9
- } from '@ukhomeoffice/cop-react-components';
4
+ import { Details, Heading, Link, Tag } from '@ukhomeoffice/cop-react-components';
10
5
  import withMock from 'storybook-addon-mock';
11
6
 
12
7
  <!-- Local imports -->
13
-
8
+ import { HooksContextProvider, ValidationContextProvider } from '../../context';
14
9
  import Utils from '../../utils';
15
10
  import CheckYourAnswers from './CheckYourAnswers';
16
11
 
17
12
  <!-- JSON documents -->
18
-
19
13
  import CIVIL_SERVANT from '../../json/areYouACivilServant.json';
20
14
  import GRADE from '../../json/grade.json';
21
15
  import TEAMS from '../../json/team.json';
@@ -84,11 +78,15 @@ Renders the **Check your answers** screen for a form.
84
78
  console.log('row action invoked', page);
85
79
  };
86
80
  return (
87
- <CheckYourAnswers
88
- pages={PAGES}
89
- onAction={ON_ACTION}
90
- onRowAction={ON_ROW_ACTION}
91
- />
81
+ <HooksContextProvider>
82
+ <ValidationContextProvider>
83
+ <CheckYourAnswers
84
+ pages={PAGES}
85
+ onAction={ON_ACTION}
86
+ onRowAction={ON_ROW_ACTION}
87
+ />
88
+ </ValidationContextProvider>
89
+ </HooksContextProvider>
92
90
  );
93
91
  }}
94
92
  </Story>
@@ -146,12 +144,16 @@ Renders the **Check your answers** screen for a form.
146
144
  console.log('row action invoked', page);
147
145
  };
148
146
  return (
149
- <CheckYourAnswers
150
- pages={PAGES}
151
- hide_page_titles={true}
152
- onAction={ON_ACTION}
153
- onRowAction={ON_ROW_ACTION}
154
- />
147
+ <HooksContextProvider>
148
+ <ValidationContextProvider>
149
+ <CheckYourAnswers
150
+ pages={PAGES}
151
+ hide_page_titles={true}
152
+ onAction={ON_ACTION}
153
+ onRowAction={ON_ROW_ACTION}
154
+ />
155
+ </ValidationContextProvider>
156
+ </HooksContextProvider>
155
157
  );
156
158
  }}
157
159
  </Story>
@@ -200,13 +202,17 @@ Renders the **Check your answers** screen for a form.
200
202
  console.log('row action invoked', page);
201
203
  };
202
204
  return (
203
- <CheckYourAnswers
204
- pages={PAGES}
205
- hide_page_titles={true}
206
- actions={ACTIONS}
207
- onAction={ON_ACTION}
208
- onRowAction={ON_ROW_ACTION}
209
- />
205
+ <HooksContextProvider>
206
+ <ValidationContextProvider>
207
+ <CheckYourAnswers
208
+ pages={PAGES}
209
+ hide_page_titles={true}
210
+ actions={ACTIONS}
211
+ onAction={ON_ACTION}
212
+ onRowAction={ON_ROW_ACTION}
213
+ />
214
+ </ValidationContextProvider>
215
+ </HooksContextProvider>
210
216
  );
211
217
  }}
212
218
  </Story>
@@ -258,15 +264,19 @@ Renders the **Check your answers** screen for a form.
258
264
  console.log('row action invoked', page);
259
265
  };
260
266
  return (
261
- <CheckYourAnswers
262
- pages={PAGES}
263
- hide_page_titles={true}
264
- onAction={ON_ACTION}
265
- onRowAction={ON_ROW_ACTION}
266
- hide_title={true}
267
- summaryListClassModifiers='no-border'
268
- noChangeAction={true}
269
- />
267
+ <HooksContextProvider>
268
+ <ValidationContextProvider>
269
+ <CheckYourAnswers
270
+ pages={PAGES}
271
+ hide_page_titles={true}
272
+ onAction={ON_ACTION}
273
+ onRowAction={ON_ROW_ACTION}
274
+ hide_title={true}
275
+ summaryListClassModifiers='no-border'
276
+ noChangeAction={true}
277
+ />
278
+ </ValidationContextProvider>
279
+ </HooksContextProvider>
270
280
  );
271
281
  }}
272
282
  </Story>
@@ -320,13 +330,17 @@ Renders the **Check your answers** screen for a form.
320
330
  console.log('row action invoked', page);
321
331
  };
322
332
  return (
323
- <CheckYourAnswers
324
- pages={PAGES}
325
- hide_page_titles={false}
326
- onAction={ON_ACTION}
327
- onRowAction={ON_ROW_ACTION}
328
- groups={CYA.groups}
329
- />
333
+ <HooksContextProvider>
334
+ <ValidationContextProvider>
335
+ <CheckYourAnswers
336
+ pages={PAGES}
337
+ hide_page_titles={false}
338
+ onAction={ON_ACTION}
339
+ onRowAction={ON_ROW_ACTION}
340
+ groups={CYA.groups}
341
+ />
342
+ </ValidationContextProvider>
343
+ </HooksContextProvider>
330
344
  );
331
345
  }}
332
346
  </Story>
@@ -359,33 +373,37 @@ Renders the **Check your answers** screen for a form.
359
373
  ],
360
374
  }}>
361
375
  {() => {
362
- const DATA = Utils.Data.setupForm(
363
- GROUP.pages,
364
- GROUP.components,
365
- GROUP_DATA
366
- );
367
- const PAGES = Utils.FormPage.getAll(
368
- GROUP.pages,
369
- GROUP.components,
370
- { ...DATA }
371
- );
372
- const ACTIONS = GROUP.cya.actions;
373
- const ON_ACTION = (action, patch, onError) => {
374
- console.log('action invoked', action, patch);
375
- };
376
- const ON_ROW_ACTION = (page) => {
377
- console.log('row action invoked', page);
378
- };
379
- return (
380
- <CheckYourAnswers
381
- pages={PAGES}
382
- hide_page_titles={true}
383
- actions={ACTIONS}
384
- onAction={ON_ACTION}
385
- onRowAction={ON_ROW_ACTION}
386
- />
387
- );
388
- }}
376
+ const DATA = Utils.Data.setupForm(
377
+ GROUP.pages,
378
+ GROUP.components,
379
+ GROUP_DATA
380
+ );
381
+ const PAGES = Utils.FormPage.getAll(
382
+ GROUP.pages,
383
+ GROUP.components,
384
+ { ...DATA }
385
+ );
386
+ const ACTIONS = GROUP.cya.actions;
387
+ const ON_ACTION = (action, patch, onError) => {
388
+ console.log('action invoked', action, patch);
389
+ };
390
+ const ON_ROW_ACTION = (page) => {
391
+ console.log('row action invoked', page);
392
+ };
393
+ return (
394
+ <HooksContextProvider>
395
+ <ValidationContextProvider>
396
+ <CheckYourAnswers
397
+ pages={PAGES}
398
+ hide_page_titles={true}
399
+ actions={ACTIONS}
400
+ onAction={ON_ACTION}
401
+ onRowAction={ON_ROW_ACTION}
402
+ />
403
+ </ValidationContextProvider>
404
+ </HooksContextProvider>
405
+ );
406
+ }}
389
407
  </Story>
390
408
  </Canvas>
391
409
 
@@ -4,6 +4,7 @@ import { Details, Heading, Link } from '@ukhomeoffice/cop-react-components';
4
4
  import withMock from 'storybook-addon-mock';
5
5
 
6
6
  <!-- Local imports -->
7
+ import { HooksContextProvider, ValidationContextProvider } from '../../context';
7
8
  import FormComponent from './FormComponent';
8
9
 
9
10
  <!-- JSON documents -->
@@ -54,7 +55,11 @@ on the basis of a <Link href="/?path=/docs/f-json-component">JSON</Link> configu
54
55
  // Do something with the target here.
55
56
  };
56
57
  return (
57
- <FormComponent component={COMPONENT} value={''} onChange={ON_CHANGE} />
58
+ <HooksContextProvider>
59
+ <ValidationContextProvider>
60
+ <FormComponent component={COMPONENT} value={''} onChange={ON_CHANGE} />
61
+ </ValidationContextProvider>
62
+ </HooksContextProvider>
58
63
  );
59
64
  }}
60
65
  </Story>
@@ -101,7 +106,11 @@ on the basis of a <Link href="/?path=/docs/f-json-component">JSON</Link> configu
101
106
  // Do something with the target here.
102
107
  };
103
108
  return (
104
- <FormComponent component={COMPONENT} value={''} onChange={ON_CHANGE} />
109
+ <HooksContextProvider>
110
+ <ValidationContextProvider>
111
+ <FormComponent component={COMPONENT} value={''} onChange={ON_CHANGE} />
112
+ </ValidationContextProvider>
113
+ </HooksContextProvider>
105
114
  );
106
115
  }}
107
116
  </Story>
@@ -117,7 +126,11 @@ on the basis of a <Link href="/?path=/docs/f-json-component">JSON</Link> configu
117
126
  // Do something with the target here.
118
127
  };
119
128
  return (
120
- <FormComponent component={COMPONENT} value={''} onChange={ON_CHANGE} />
129
+ <HooksContextProvider>
130
+ <ValidationContextProvider>
131
+ <FormComponent component={COMPONENT} value={''} onChange={ON_CHANGE} />
132
+ </ValidationContextProvider>
133
+ </HooksContextProvider>
121
134
  );
122
135
  }}
123
136
  </Story>
@@ -160,7 +173,11 @@ on the basis of a <Link href="/?path=/docs/f-json-component">JSON</Link> configu
160
173
  // Do something with the target here.
161
174
  };
162
175
  return (
163
- <FormComponent component={COMPONENT} value={''} wrap={false} onChange={ON_CHANGE} />
176
+ <HooksContextProvider>
177
+ <ValidationContextProvider>
178
+ <FormComponent component={COMPONENT} value={''} wrap={false} onChange={ON_CHANGE} />
179
+ </ValidationContextProvider>
180
+ </HooksContextProvider>
164
181
  );
165
182
  }}
166
183
  </Story>
@@ -104,7 +104,9 @@ var FormPage = function FormPage(_ref) {
104
104
  formData: _objectSpread(_objectSpread({}, page.formData), patch)
105
105
  });
106
106
  }), /*#__PURE__*/_react.default.createElement(_PageActions.default, {
107
- actions: page.actions,
107
+ actions: page.actions.filter(function (action) {
108
+ return _utils.default.Component.show(action, page.formData);
109
+ }),
108
110
  onAction: function onAction(action) {
109
111
  return _onAction(action, patch);
110
112
  }
@@ -4,6 +4,7 @@ import { Details, Heading, Link } from '@ukhomeoffice/cop-react-components';
4
4
  import withMock from 'storybook-addon-mock';
5
5
 
6
6
  <!-- Local imports -->
7
+ import { HooksContextProvider, ValidationContextProvider } from '../../context';
7
8
  import Utils from '../../utils';
8
9
  import FormPage from './FormPage';
9
10
 
@@ -51,7 +52,11 @@ on the basis of a <Link href="/?path=/docs/f-json-page">JSON</Link> configuratio
51
52
  console.log('action invoked', action, patch);
52
53
  };
53
54
  return (
54
- <FormPage page={PAGE} onAction={ON_ACTION} />
55
+ <HooksContextProvider>
56
+ <ValidationContextProvider>
57
+ <FormPage page={PAGE} onAction={ON_ACTION} />
58
+ </ValidationContextProvider>
59
+ </HooksContextProvider>
55
60
  );
56
61
  }}
57
62
  </Story>
@@ -94,7 +99,11 @@ on the basis of a <Link href="/?path=/docs/f-json-page">JSON</Link> configuratio
94
99
  console.log('action invoked', action, patch);
95
100
  };
96
101
  return (
97
- <FormPage page={PAGE} onAction={ON_ACTION} />
102
+ <HooksContextProvider>
103
+ <ValidationContextProvider>
104
+ <FormPage page={PAGE} onAction={ON_ACTION} />
105
+ </ValidationContextProvider>
106
+ </HooksContextProvider>
98
107
  );
99
108
  }}
100
109
  </Story>
@@ -111,7 +120,11 @@ on the basis of a <Link href="/?path=/docs/f-json-page">JSON</Link> configuratio
111
120
  console.log('action invoked', action, patch);
112
121
  };
113
122
  return (
114
- <FormPage page={PAGE} onAction={ON_ACTION} />
123
+ <HooksContextProvider>
124
+ <ValidationContextProvider>
125
+ <FormPage page={PAGE} onAction={ON_ACTION} />
126
+ </ValidationContextProvider>
127
+ </HooksContextProvider>
115
128
  );
116
129
  }}
117
130
  </Story>
@@ -92,6 +92,44 @@ describe('components.FormPage', function () {
92
92
  }
93
93
  }
94
94
  };
95
+ var PAGE_WITH_CONDITIONAL_BUTTONS = {
96
+ id: 'pageId',
97
+ // eslint-disable-next-line no-template-curly-in-string
98
+ title: '${title}',
99
+ components: [TEXT_WITH_EXPRESSION, AUTO_WITH_EXPRESSION],
100
+ actions: [{
101
+ type: 'submit',
102
+ validate: true,
103
+ label: 'Button 1',
104
+ show_when: [{
105
+ field: 'currentUser.givenName',
106
+ op: '!=',
107
+ value: 'Doe'
108
+ }]
109
+ }, {
110
+ type: 'submit',
111
+ validate: false,
112
+ label: 'Button 2',
113
+ show_when: [{
114
+ field: 'currentUser.givenName',
115
+ op: '=',
116
+ value: 'Doe'
117
+ }]
118
+ }],
119
+ formData: {
120
+ title: 'Order Form',
121
+ text1: "Text1 ".concat(VALUE),
122
+ text2: "Text2 ".concat(VALUE),
123
+ wrapper: {
124
+ email: 'test@example.email',
125
+ nextAction: 'Payment',
126
+ prevAction: 'User Details'
127
+ },
128
+ currentUser: {
129
+ givenName: 'Doe'
130
+ }
131
+ }
132
+ };
95
133
  var ON_ACTION_CALLS = [];
96
134
 
97
135
  var checkInputField = function checkInputField(formGroup, fieldId, lbl, hnt, val) {
@@ -305,5 +343,26 @@ describe('components.FormPage', function () {
305
343
  }
306
344
  }, _callee4);
307
345
  })));
346
+ it('should render only the conditionally shown button', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
347
+ var _renderWithValidation5, container, page;
348
+
349
+ return regeneratorRuntime.wrap(function _callee5$(_context5) {
350
+ while (1) {
351
+ switch (_context5.prev = _context5.next) {
352
+ case 0:
353
+ _renderWithValidation5 = (0, _setupTests.renderWithValidation)( /*#__PURE__*/_react2.default.createElement(_FormPage.default, {
354
+ page: PAGE_WITH_CONDITIONAL_BUTTONS,
355
+ onAction: ON_ACTION
356
+ })), container = _renderWithValidation5.container;
357
+ page = container.childNodes[0];
358
+ checkFormButtonGroup(page.childNodes[3], ['Button 2']); // Just the second button shown
359
+
360
+ case 3:
361
+ case "end":
362
+ return _context5.stop();
363
+ }
364
+ }
365
+ }, _callee5);
366
+ })));
308
367
  });
309
368
  });
@@ -250,9 +250,14 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
250
250
  }, [newPageId]); // Handle actions from pages.
251
251
 
252
252
  var onPageAction = function onPageAction(action, patch) {
253
- // Re-apply the patch to the page's formData.
253
+ if (action.type === _models.PageAction.TYPES.CANCEL) {
254
+ hooks.onCancel();
255
+ return;
256
+ } // Re-apply the patch to the page's formData.
254
257
  // This should normally have no effect but will prevent issues
255
258
  // with validation if formData happens to have been wiped.
259
+
260
+
256
261
  formState.page.formData = _objectSpread(_objectSpread({}, formState.page.formData), patch); // Check to see whether the action is able to proceed, which in
257
262
  // in the case of a submission will validate the fields in the page.
258
263
 
@@ -318,10 +323,15 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
318
323
  setCurrentTask(currentTask);
319
324
 
320
325
  if (currentTask.state === _models.TaskStates.TYPES.COMPLETE) {
321
- onPageChange(_models.FormPages.CYA);
326
+ if (hubDetails !== null && hubDetails !== void 0 && hubDetails.noTaskCYAs) {
327
+ var currentPage = data.formStatus.tasks[currentTask.name].currentPage;
328
+ onPageChange(currentPage || currentTask.pages[0]);
329
+ } else {
330
+ onPageChange(_models.FormPages.CYA);
331
+ }
322
332
  } else if (currentTask.state === _models.TaskStates.TYPES.IN_PROGRESS) {
323
- var currentPage = data.formStatus.tasks[currentTask.name].currentPage;
324
- onPageChange(currentPage || currentTask.pages[0]);
333
+ var _currentPage = data.formStatus.tasks[currentTask.name].currentPage;
334
+ onPageChange(_currentPage || currentTask.pages[0]);
325
335
  } else {
326
336
  onPageChange(currentTask.pages[0]);
327
337
  }
@@ -388,6 +398,10 @@ var InternalFormRenderer = function InternalFormRenderer(_ref2) {
388
398
  });
389
399
  }
390
400
  }
401
+
402
+ if (action.type === _models.PageAction.TYPES.CANCEL) {
403
+ hooks.onCancel();
404
+ }
391
405
  };
392
406
 
393
407
  var classes = _utils.default.classBuilder(classBlock, classModifiers, className);
@@ -99,6 +99,10 @@ describe('components', function () {
99
99
  return page.childNodes[page.childNodes.length - 1].childNodes[0].childNodes[0];
100
100
  };
101
101
 
102
+ var getCancelButton = function getCancelButton(page) {
103
+ return page.childNodes[page.childNodes.length - 1].childNodes[1].childNodes[0];
104
+ };
105
+
102
106
  it('should start on the hub page correctly and display the title', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
103
107
  var form, title, hub;
104
108
  return regeneratorRuntime.wrap(function _callee2$(_context2) {
@@ -743,5 +747,154 @@ describe('components', function () {
743
747
  }
744
748
  }, _callee20);
745
749
  })));
750
+ it('should go to the last page of a complete task if noTaskCYAs specified', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee22() {
751
+ var ON_SUBMIT, HOOKS, TASK_LIST_WITH_NO_TASK_CYAS, taskList, newPage;
752
+ return regeneratorRuntime.wrap(function _callee22$(_context22) {
753
+ while (1) {
754
+ switch (_context22.prev = _context22.next) {
755
+ case 0:
756
+ ON_SUBMIT = function ON_SUBMIT(type, payload, onSuccess, onError) {
757
+ onSuccess();
758
+ };
759
+
760
+ HOOKS = {
761
+ onSubmit: ON_SUBMIT
762
+ };
763
+ TASK_LIST_WITH_NO_TASK_CYAS = JSON.parse(JSON.stringify(_taskList.default));
764
+ TASK_LIST_WITH_NO_TASK_CYAS.hub.noTaskCYAs = true;
765
+ TASK_LIST_WITH_NO_TASK_CYAS.pages[1].actions[0] = {
766
+ type: 'save',
767
+ complete: true
768
+ };
769
+ _context22.next = 7;
770
+ return (0, _testUtils.act)( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee21() {
771
+ return regeneratorRuntime.wrap(function _callee21$(_context21) {
772
+ while (1) {
773
+ switch (_context21.prev = _context21.next) {
774
+ case 0:
775
+ (0, _reactDom.render)( /*#__PURE__*/_react2.default.createElement(_FormRenderer.default, _extends({}, TASK_LIST_WITH_NO_TASK_CYAS, {
776
+ hooks: HOOKS
777
+ })), container);
778
+
779
+ case 1:
780
+ case "end":
781
+ return _context21.stop();
782
+ }
783
+ }
784
+ }, _callee21);
785
+ })));
786
+
787
+ case 7:
788
+ taskList = container.childNodes[0].childNodes[1]; // Launch first task
789
+
790
+ _react.fireEvent.click(taskList.childNodes[3].childNodes[0].childNodes[0].childNodes[0], {}); // Fill first page and navigate
791
+
792
+
793
+ newPage = container.childNodes[0].childNodes[0];
794
+
795
+ _react.fireEvent.change(newPage.childNodes[1].childNodes[2].childNodes[0].childNodes[1], {
796
+ target: {
797
+ name: 'date-day',
798
+ value: '7'
799
+ }
800
+ });
801
+
802
+ _react.fireEvent.change(newPage.childNodes[1].childNodes[2].childNodes[1].childNodes[1], {
803
+ target: {
804
+ name: 'date-month',
805
+ value: '7'
806
+ }
807
+ });
808
+
809
+ _react.fireEvent.change(newPage.childNodes[1].childNodes[2].childNodes[2].childNodes[1], {
810
+ target: {
811
+ name: 'date-year',
812
+ value: '2022'
813
+ }
814
+ });
815
+
816
+ _react.fireEvent.click(newPage.childNodes[2].childNodes[0], {}); // Fill second page
817
+
818
+
819
+ newPage = container.childNodes[0].childNodes[0];
820
+
821
+ _react.fireEvent.click(newPage.childNodes[1].childNodes[2].childNodes[0].childNodes[0], {});
822
+
823
+ _react.fireEvent.click(newPage.childNodes[2].childNodes[0], {}); // Launch same task again
824
+
825
+
826
+ _react.fireEvent.click(container.childNodes[0].childNodes[1].childNodes[3].childNodes[0].childNodes[0].childNodes[0], {}); // Should be on the second page
827
+
828
+
829
+ expect(container.childNodes[0].childNodes[0].childNodes[0].textContent).toEqual('Event Mode');
830
+
831
+ case 19:
832
+ case "end":
833
+ return _context22.stop();
834
+ }
835
+ }
836
+ }, _callee22);
837
+ })));
838
+ it('should handle cancellation from a page', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee24() {
839
+ var ON_CANCEL_CALLS, ON_CANCEL, HOOKS, form, hub, _hub$childNodes5, civilServantList, link, page, cancel;
840
+
841
+ return regeneratorRuntime.wrap(function _callee24$(_context24) {
842
+ while (1) {
843
+ switch (_context24.prev = _context24.next) {
844
+ case 0:
845
+ ON_CANCEL_CALLS = [];
846
+
847
+ ON_CANCEL = function ON_CANCEL() {
848
+ ON_CANCEL_CALLS.push(undefined);
849
+ };
850
+
851
+ HOOKS = {
852
+ onCancel: ON_CANCEL
853
+ };
854
+ _context24.next = 5;
855
+ return (0, _testUtils.act)( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee23() {
856
+ return regeneratorRuntime.wrap(function _callee23$(_context23) {
857
+ while (1) {
858
+ switch (_context23.prev = _context23.next) {
859
+ case 0:
860
+ (0, _reactDom.render)( /*#__PURE__*/_react2.default.createElement(_FormRenderer.default, _extends({}, _userProfile.default, {
861
+ data: _userProfileData.default,
862
+ hooks: HOOKS
863
+ })), container);
864
+
865
+ case 1:
866
+ case "end":
867
+ return _context23.stop();
868
+ }
869
+ }
870
+ }, _callee23);
871
+ })));
872
+
873
+ case 5:
874
+ form = checkForm(container); // Navigate to the "Are you a civil servant?" page.
875
+
876
+ hub = form.childNodes[1]; // Hub = CYA
877
+
878
+ _hub$childNodes5 = _slicedToArray(hub.childNodes, 3), civilServantList = _hub$childNodes5[2];
879
+ link = getChangeLink(civilServantList);
880
+
881
+ _react.fireEvent.click(link, {}); // Should already be answered "Yes", so simply click "Continue".
882
+
883
+
884
+ page = form.childNodes[0];
885
+ cancel = getCancelButton(page);
886
+ expect(ON_CANCEL_CALLS.length).toEqual(0);
887
+
888
+ _react.fireEvent.click(cancel, {});
889
+
890
+ expect(ON_CANCEL_CALLS.length).toEqual(1);
891
+
892
+ case 15:
893
+ case "end":
894
+ return _context24.stop();
895
+ }
896
+ }
897
+ }, _callee24);
898
+ })));
746
899
  });
747
900
  });
@@ -13,22 +13,20 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
13
13
 
14
14
  var getSubmissionStatus = function getSubmissionStatus(formType, pages, currentPageId, action, formData, currentTask, isCompleted) {
15
15
  if (formType === _models.FormTypes.TASK) {
16
- var formStatus = formData.formStatus ? formData.formStatus : {};
17
- formStatus.tasks = formStatus.tasks ? formStatus.tasks : {};
18
- formStatus.tasks[currentTask.name] = formStatus.tasks[currentTask.name] ? formStatus.tasks[currentTask.name] : {};
16
+ var formStatus = formData.formStatus || {};
17
+ formStatus.tasks = formStatus.tasks || {};
18
+ formStatus.tasks[currentTask.name] = formStatus.tasks[currentTask.name] || {};
19
19
 
20
20
  if (currentPageId === (_models.FormPages.CYA || 'submitForm') && isCompleted) {
21
21
  formStatus.tasks[currentTask.name].complete = true;
22
22
  } else if ((action === null || action === void 0 ? void 0 : action.type) === _models.PageAction.TYPES.SAVE_AND_NAVIGATE) {
23
- console.log('pg action sc');
24
23
  formStatus.tasks[currentTask.name] = {
25
24
  complete: false,
26
25
  currentPage: (0, _getNextPageId.default)(formType, pages, currentPageId, action, formData)
27
26
  };
28
27
  } else {
29
- console.log('got to else stmt');
30
28
  formStatus.tasks[currentTask.name] = {
31
- complete: false,
29
+ complete: !!(action !== null && action !== void 0 && action.complete),
32
30
  currentPage: currentPageId
33
31
  };
34
32
  }
@@ -240,6 +240,21 @@ describe('components', function () {
240
240
  })
241
241
  });
242
242
  });
243
+ it("should mark the current task as complete if the action indicates as much", function () {
244
+ var CURRENT_PAGE_ID = PAGES[0].id;
245
+ var TASK_NAME = 'taskName';
246
+ var CURRENT_TASK = {
247
+ name: TASK_NAME
248
+ };
249
+ var ACTION = {
250
+ complete: true
251
+ };
252
+ expect((0, _getSubmissionStatus.default)(FORM_TYPE, PAGES, CURRENT_PAGE_ID, ACTION, {}, CURRENT_TASK, true)).toMatchObject({
253
+ tasks: _defineProperty({}, TASK_NAME, {
254
+ complete: true
255
+ })
256
+ });
257
+ });
243
258
  });
244
259
  });
245
260
  });
@@ -45,7 +45,9 @@ var DEFAULT_HOOKS = {
45
45
  },
46
46
  onSubmit: function onSubmit(type, payload, onSuccess, onError) {
47
47
  if (typeof onSuccess === 'function') onSuccess();
48
- }
48
+ },
49
+ onCancel: function onCancel() {} // Consuming application must provide function to action, else this does nothing.
50
+
49
51
  };
50
52
  var ALLOWED_HOOKS = Object.keys(DEFAULT_HOOKS);
51
53
  exports.ALLOWED_HOOKS = ALLOWED_HOOKS;
@@ -62,7 +64,8 @@ var HooksContextProvider = function HooksContextProvider(_ref) {
62
64
  onGetComponent: (overrides === null || overrides === void 0 ? void 0 : overrides.onGetComponent) || DEFAULT_HOOKS.onGetComponent,
63
65
  onPageChange: (overrides === null || overrides === void 0 ? void 0 : overrides.onPageChange) || DEFAULT_HOOKS.onPageChange,
64
66
  onRequest: (overrides === null || overrides === void 0 ? void 0 : overrides.onRequest) || DEFAULT_HOOKS.onRequest,
65
- onSubmit: (overrides === null || overrides === void 0 ? void 0 : overrides.onSubmit) || DEFAULT_HOOKS.onSubmit
67
+ onSubmit: (overrides === null || overrides === void 0 ? void 0 : overrides.onSubmit) || DEFAULT_HOOKS.onSubmit,
68
+ onCancel: (overrides === null || overrides === void 0 ? void 0 : overrides.onCancel) || DEFAULT_HOOKS.onCancel
66
69
  }),
67
70
  _useState2 = _slicedToArray(_useState, 2),
68
71
  hooks = _useState2[0],
@@ -138,7 +138,7 @@
138
138
  "label": ""
139
139
  }
140
140
  ],
141
- "actions": ["submit"],
141
+ "actions": ["submit", "cancel"],
142
142
  "cya_link": {
143
143
  "page": "civil-servant-status",
144
144
  "aria_suffix": "civil servant status"
@@ -9,12 +9,14 @@ var _DefaultPageActions;
9
9
 
10
10
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
11
11
 
12
+ var TYPE_CANCEL = 'cancel';
12
13
  var TYPE_NAVIGATE = 'navigate';
13
14
  var TYPE_SAVE_AND_CONTINUE = 'saveAndContinue';
14
15
  var TYPE_SAVE_AND_NAVIGATE = 'saveAndNavigate';
15
16
  var TYPE_SAVE_AND_RETURN = 'saveAndReturn';
16
17
  var TYPE_SUBMIT = 'submit';
17
18
  var PageActionTypes = {
19
+ CANCEL: TYPE_CANCEL,
18
20
  NAVIGATE: TYPE_NAVIGATE,
19
21
  SAVE_AND_CONTINUE: TYPE_SAVE_AND_CONTINUE,
20
22
  SAVE_AND_NAVIGATE: TYPE_SAVE_AND_NAVIGATE,
@@ -22,7 +24,12 @@ var PageActionTypes = {
22
24
  SUBMIT: TYPE_SUBMIT
23
25
  };
24
26
  exports.PageActionTypes = PageActionTypes;
25
- var DefaultPageActions = (_DefaultPageActions = {}, _defineProperty(_DefaultPageActions, TYPE_NAVIGATE, undefined), _defineProperty(_DefaultPageActions, TYPE_SAVE_AND_CONTINUE, {
27
+ var DefaultPageActions = (_DefaultPageActions = {}, _defineProperty(_DefaultPageActions, TYPE_CANCEL, {
28
+ type: TYPE_CANCEL,
29
+ validate: false,
30
+ label: 'Cancel',
31
+ classModifiers: 'secondary'
32
+ }), _defineProperty(_DefaultPageActions, TYPE_NAVIGATE, undefined), _defineProperty(_DefaultPageActions, TYPE_SAVE_AND_CONTINUE, {
26
33
  type: TYPE_SAVE_AND_CONTINUE,
27
34
  validate: true,
28
35
  label: 'Save and continue'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukhomeoffice/cop-react-form-renderer",
3
- "version": "3.12.0",
3
+ "version": "3.16.0",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "clean": "rimraf dist",
@@ -16,7 +16,7 @@
16
16
  "post-compile": "rimraf dist/*.test.* dist/**/*.test.* dist/**/*.stories.* dist/docs dist/assets"
17
17
  },
18
18
  "dependencies": {
19
- "@ukhomeoffice/cop-react-components": "1.10.0",
19
+ "@ukhomeoffice/cop-react-components": "1.12.0",
20
20
  "axios": "^0.23.0",
21
21
  "dayjs": "^1.11.0",
22
22
  "govuk-frontend": "^3.13.0",