@ukhomeoffice/cop-react-form-renderer 0.1.0-beta → 0.1.0-gamma

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 (48) hide show
  1. package/dist/components/CheckYourAnswers/Answer.js +48 -0
  2. package/dist/components/CheckYourAnswers/CheckYourAnswers.js +28 -9
  3. package/dist/components/CheckYourAnswers/CheckYourAnswers.stories.mdx +23 -0
  4. package/dist/components/FormComponent/FormComponent.js +7 -7
  5. package/dist/components/FormComponent/FormComponent.stories.mdx +167 -0
  6. package/dist/components/FormComponent/FormComponent.test.js +137 -0
  7. package/dist/components/FormPage/FormPage.js +12 -11
  8. package/dist/components/FormPage/FormPage.stories.mdx +118 -0
  9. package/dist/components/FormPage/FormPage.test.js +253 -0
  10. package/dist/components/FormRenderer/FormRenderer.js +33 -18
  11. package/dist/components/FormRenderer/FormRenderer.stories.mdx +87 -0
  12. package/dist/components/FormRenderer/helpers/canActionProceed.js +35 -0
  13. package/dist/components/FormRenderer/helpers/canActionProceed.test.js +73 -0
  14. package/dist/components/FormRenderer/helpers/getCYA.js +31 -0
  15. package/dist/components/FormRenderer/helpers/getCYA.test.js +38 -0
  16. package/dist/components/FormRenderer/helpers/getFormState.js +32 -0
  17. package/dist/components/FormRenderer/helpers/getFormState.test.js +61 -0
  18. package/dist/components/FormRenderer/helpers/getPage.js +34 -0
  19. package/dist/components/FormRenderer/helpers/getPage.test.js +46 -0
  20. package/dist/components/FormRenderer/helpers/index.js +23 -0
  21. package/dist/components/PageActions/ActionButton.js +62 -0
  22. package/dist/components/PageActions/ActionButton.test.js +114 -0
  23. package/dist/components/PageActions/PageActions.js +18 -25
  24. package/dist/components/PageActions/PageActions.stories.mdx +74 -0
  25. package/dist/components/PageActions/PageActions.test.js +155 -0
  26. package/dist/components/SummaryList/RowAction.js +13 -22
  27. package/dist/components/SummaryList/RowAction.test.js +104 -0
  28. package/dist/components/SummaryList/SummaryList.js +3 -17
  29. package/dist/components/SummaryList/helpers/getRowActionAttributes.js +27 -0
  30. package/dist/components/SummaryList/helpers/getRowActionAttributes.test.js +77 -0
  31. package/dist/components/SummaryList/helpers/index.js +15 -0
  32. package/dist/components/index.js +8 -0
  33. package/dist/hooks/useGetRequest.js +16 -1
  34. package/dist/hooks/useHooks.js +15 -1
  35. package/dist/utils/Component/getComponent.js +2 -2
  36. package/dist/utils/Data/setupFormData.js +3 -3
  37. package/dist/utils/FormPage/getFormPage.js +11 -0
  38. package/dist/utils/FormPage/getFormPage.test.js +178 -0
  39. package/dist/utils/FormPage/getFormPages.js +11 -6
  40. package/dist/utils/FormPage/getFormPages.test.js +95 -0
  41. package/dist/utils/FormPage/getParagraphFromText.js +6 -0
  42. package/dist/utils/FormPage/getParagraphFromText.test.js +29 -0
  43. package/dist/utils/FormPage/useComponent.js +9 -2
  44. package/dist/utils/FormPage/useComponent.test.js +82 -0
  45. package/dist/utils/Hub/getFormHub.js +4 -4
  46. package/dist/utils/Hub/getFormHub.test.js +96 -0
  47. package/dist/utils/Hub/index.js +0 -3
  48. package/package.json +1 -1
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+
3
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
+
5
+ var _react = require("@testing-library/react");
6
+
7
+ var _react2 = _interopRequireDefault(require("react"));
8
+
9
+ var _ActionButton = require("../PageActions/ActionButton");
10
+
11
+ var _FormPage = _interopRequireWildcard(require("./FormPage"));
12
+
13
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
14
+
15
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
16
+
17
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
+
19
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
20
+
21
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
22
+
23
+ describe('components', function () {
24
+ describe('FormPage', function () {
25
+ var TEXT = {
26
+ id: 'text',
27
+ fieldId: 'text',
28
+ type: 'text',
29
+ label: 'Text component',
30
+ hint: 'Text hint'
31
+ };
32
+ var VALUE = 'Text value';
33
+ var PAGE = {
34
+ id: 'pageId',
35
+ title: 'Page 1',
36
+ components: [TEXT],
37
+ actions: ['submit'],
38
+ formData: {
39
+ text: VALUE
40
+ }
41
+ };
42
+ var ON_ACTION_CALLS = [];
43
+
44
+ var ON_ACTION = function ON_ACTION(action, patch, onError) {
45
+ ON_ACTION_CALLS.push({
46
+ action: action,
47
+ patch: patch,
48
+ onError: onError
49
+ });
50
+ };
51
+
52
+ beforeEach(function () {
53
+ PAGE.formData = {
54
+ text: VALUE
55
+ };
56
+ ON_ACTION_CALLS.length = 0;
57
+ });
58
+ it('should render a submit page correctly', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
59
+ var _render, container, page, heading, formGroup, label, hint, input, buttonGroup, button;
60
+
61
+ return regeneratorRuntime.wrap(function _callee$(_context) {
62
+ while (1) {
63
+ switch (_context.prev = _context.next) {
64
+ case 0:
65
+ _render = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(_FormPage.default, {
66
+ page: PAGE,
67
+ onAction: ON_ACTION
68
+ })), container = _render.container;
69
+ page = container.childNodes[0];
70
+ expect(page.tagName).toEqual('DIV');
71
+ expect(page.classList).toContain("".concat(_FormPage.DEFAULT_CLASS, "__page"));
72
+ heading = page.childNodes[0];
73
+ expect(heading.classList).toContain('govuk-heading-l');
74
+ expect(heading.textContent).toEqual(PAGE.title);
75
+ formGroup = page.childNodes[1];
76
+ expect(formGroup.tagName).toEqual('DIV');
77
+ expect(formGroup.classList).toContain('govuk-form-group');
78
+ label = formGroup.childNodes[0];
79
+ expect(label.tagName).toEqual('LABEL');
80
+ expect(label.classList).toContain('govuk-label');
81
+ expect(label.textContent).toEqual("".concat(TEXT.label, " (optional)"));
82
+ expect(label.getAttribute('for')).toEqual(TEXT.fieldId);
83
+ hint = formGroup.childNodes[1];
84
+ expect(hint.tagName).toEqual('SPAN');
85
+ expect(hint.classList).toContain('govuk-hint');
86
+ expect(hint.textContent).toEqual(TEXT.hint);
87
+ input = formGroup.childNodes[2];
88
+ expect(input.tagName).toEqual('INPUT');
89
+ expect(input.classList).toContain('govuk-input');
90
+ expect(input.id).toEqual(TEXT.fieldId);
91
+ expect(input.value).toEqual(VALUE);
92
+ buttonGroup = page.childNodes[2];
93
+ expect(buttonGroup.tagName).toEqual('DIV');
94
+ expect(buttonGroup.classList).toContain('govuk-button-group');
95
+ button = buttonGroup.childNodes[0];
96
+ expect(button.tagName).toEqual('BUTTON');
97
+ expect(button.classList).toContain('govuk-button');
98
+ expect(button.textContent).toEqual(_ActionButton.DEFAULT_LABEL);
99
+
100
+ case 31:
101
+ case "end":
102
+ return _context.stop();
103
+ }
104
+ }
105
+ }, _callee);
106
+ })));
107
+ it('should handle a page change appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
108
+ var _render2, container, page, input, NEW_VALUE, EVENT;
109
+
110
+ return regeneratorRuntime.wrap(function _callee2$(_context2) {
111
+ while (1) {
112
+ switch (_context2.prev = _context2.next) {
113
+ case 0:
114
+ _render2 = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(_FormPage.default, {
115
+ page: PAGE,
116
+ onAction: ON_ACTION
117
+ })), container = _render2.container;
118
+ page = container.childNodes[0];
119
+ expect(page.tagName).toEqual('DIV'); // Change the input.
120
+
121
+ input = page.childNodes[1].childNodes[2];
122
+ NEW_VALUE = "".concat(VALUE, ".");
123
+ EVENT = {
124
+ target: {
125
+ name: TEXT.fieldId,
126
+ value: NEW_VALUE
127
+ }
128
+ };
129
+
130
+ _react.fireEvent.change(input, EVENT); // And confirm the formData has been changed.
131
+
132
+
133
+ expect(PAGE.formData.text).toEqual(NEW_VALUE);
134
+
135
+ case 8:
136
+ case "end":
137
+ return _context2.stop();
138
+ }
139
+ }
140
+ }, _callee2);
141
+ })));
142
+ it('should handle a page action appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
143
+ var _render3, container, page, input, NEW_VALUE, CHANGE_EVENT, button;
144
+
145
+ return regeneratorRuntime.wrap(function _callee3$(_context3) {
146
+ while (1) {
147
+ switch (_context3.prev = _context3.next) {
148
+ case 0:
149
+ _render3 = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(_FormPage.default, {
150
+ page: PAGE,
151
+ onAction: ON_ACTION
152
+ })), container = _render3.container;
153
+ page = container.childNodes[0]; // Change the input.
154
+
155
+ input = page.childNodes[1].childNodes[2];
156
+ NEW_VALUE = "".concat(VALUE, ".");
157
+ CHANGE_EVENT = {
158
+ target: {
159
+ name: TEXT.fieldId,
160
+ value: NEW_VALUE
161
+ }
162
+ };
163
+
164
+ _react.fireEvent.change(input, CHANGE_EVENT); // Then click the action button.
165
+
166
+
167
+ button = page.childNodes[2].childNodes[0];
168
+
169
+ _react.fireEvent.click(button, {}); // And confirm an appropriate action was received.
170
+
171
+
172
+ expect(ON_ACTION_CALLS.length).toEqual(1);
173
+ expect(PAGE.formData.text).toEqual(NEW_VALUE);
174
+ expect(ON_ACTION_CALLS[0].action).toEqual(_ActionButton.DEFAULT_ACTIONS.submit);
175
+ expect(ON_ACTION_CALLS[0].patch).toEqual({
176
+ text: NEW_VALUE
177
+ });
178
+
179
+ case 12:
180
+ case "end":
181
+ return _context3.stop();
182
+ }
183
+ }
184
+ }, _callee3);
185
+ })));
186
+ it('should display errors appropriately', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
187
+ var ERRORS, THROW_ERROR_ON_ACTION, _render4, container, page, input, NEW_VALUE, CHANGE_EVENT, button, errorSummary, errorList, error, errorLink;
188
+
189
+ return regeneratorRuntime.wrap(function _callee4$(_context4) {
190
+ while (1) {
191
+ switch (_context4.prev = _context4.next) {
192
+ case 0:
193
+ ERRORS = [{
194
+ id: TEXT.id,
195
+ error: 'Invalid value'
196
+ }];
197
+
198
+ THROW_ERROR_ON_ACTION = function THROW_ERROR_ON_ACTION(action, patch, onError) {
199
+ ON_ACTION_CALLS.push({
200
+ action: action,
201
+ patch: patch,
202
+ onError: onError
203
+ });
204
+ onError(ERRORS);
205
+ };
206
+
207
+ _render4 = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(_FormPage.default, {
208
+ page: PAGE,
209
+ onAction: THROW_ERROR_ON_ACTION
210
+ })), container = _render4.container;
211
+ page = container.childNodes[0]; // Change the input.
212
+
213
+ input = page.childNodes[1].childNodes[2];
214
+ NEW_VALUE = "".concat(VALUE, ".");
215
+ CHANGE_EVENT = {
216
+ target: {
217
+ name: TEXT.fieldId,
218
+ value: NEW_VALUE
219
+ }
220
+ };
221
+
222
+ _react.fireEvent.change(input, CHANGE_EVENT); // Then click the action button, which should call the onError callback method.
223
+
224
+
225
+ button = page.childNodes[2].childNodes[0];
226
+
227
+ _react.fireEvent.click(button, {}); // And confirm the page error is now displayed.
228
+
229
+
230
+ errorSummary = page.childNodes[1];
231
+ expect(errorSummary.tagName).toEqual('DIV');
232
+ expect(errorSummary.id).toEqual('error-summary');
233
+ expect(errorSummary.classList).toContain('govuk-error-summary');
234
+ errorList = errorSummary.childNodes[1].childNodes[0];
235
+ expect(errorList.tagName).toEqual('UL');
236
+ expect(errorList.classList).toContain('govuk-error-summary__list');
237
+ expect(errorList.childNodes.length).toEqual(ERRORS.length);
238
+ error = errorList.childNodes[0];
239
+ expect(error.tagName).toEqual('LI');
240
+ errorLink = error.childNodes[0];
241
+ expect(errorLink.tagName).toEqual('A');
242
+ expect(errorLink.textContent).toEqual(ERRORS[0].error);
243
+ expect(errorLink.getAttribute('href')).toEqual("#".concat(ERRORS[0].id));
244
+
245
+ case 24:
246
+ case "end":
247
+ return _context4.stop();
248
+ }
249
+ }
250
+ }, _callee4);
251
+ })));
252
+ });
253
+ });
@@ -13,7 +13,7 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
13
13
 
14
14
  var _react = _interopRequireWildcard(require("react"));
15
15
 
16
- var _hooks = require("../../hooks");
16
+ var _hooks2 = require("../../hooks");
17
17
 
18
18
  var _models = require("../../models");
19
19
 
@@ -63,7 +63,7 @@ var FormRenderer = function FormRenderer(_ref) {
63
63
  _hub = _ref.hub,
64
64
  _cya = _ref.cya,
65
65
  _data = _ref.data,
66
- hooks = _ref.hooks,
66
+ _hooks = _ref.hooks,
67
67
  classBlock = _ref.classBlock,
68
68
  classModifiers = _ref.classModifiers,
69
69
  className = _ref.className;
@@ -100,16 +100,17 @@ var FormRenderer = function FormRenderer(_ref) {
100
100
  setFormState = _useState12[1]; // Set up hooks.
101
101
 
102
102
 
103
- var _useHooks = (0, _hooks.useHooks)(),
103
+ var _useHooks = (0, _hooks2.useHooks)(),
104
+ hooks = _useHooks.hooks,
104
105
  addHook = _useHooks.addHook;
105
106
 
106
107
  (0, _react.useEffect)(function () {
107
- if (hooks) {
108
- Object.keys(hooks).forEach(function (key) {
109
- addHook(key, hooks[key]);
108
+ if (_hooks) {
109
+ Object.keys(_hooks).forEach(function (key) {
110
+ addHook(key, _hooks[key]);
110
111
  });
111
112
  }
112
- }, [hooks, addHook]); // Setup data.
113
+ }, [_hooks, addHook]); // Setup data.
113
114
 
114
115
  (0, _react.useEffect)(function () {
115
116
  setData(_utils.default.Data.setupForm(_pages, components, _data));
@@ -120,31 +121,44 @@ var FormRenderer = function FormRenderer(_ref) {
120
121
  }, [components, _pages, data, redoPages, setPages]); // Setup hub.
121
122
 
122
123
  (0, _react.useEffect)(function () {
123
- setHub(_utils.default.Hub.get(type, _hub, components));
124
- }, [type, _hub, components, setHub]); // Form state.
124
+ setHub(_utils.default.Hub.get(type, _hub, components, _objectSpread({}, data)));
125
+ }, [type, _hub, data, components, setHub]); // Form state.
125
126
 
126
127
  (0, _react.useEffect)(function () {
127
128
  setFormState((0, _helpers.getFormState)(pageId, pages, hub));
128
- }, [pages, hub, pageId, setFormState]); // Handle actions from pages.
129
+ }, [pages, hub, pageId, setFormState]); // Call the onFormLoad hook just when this component first renders.
130
+
131
+ (0, _react.useEffect)(function () {
132
+ hooks.onFormLoad();
133
+ }, [hooks]); // Handle actions from pages.
129
134
 
130
135
  var onAction = function onAction(action, patch, onError) {
131
136
  // First check the validity of the
132
137
  if ((0, _helpers.canActionProceed)(action, formState.page, onError)) {
133
138
  if (action.type === 'navigate') {
134
- setPageId(action.url.replace('/', ''));
139
+ var newPageId = action.url.replace('/', '');
140
+ setPageId(newPageId);
141
+ hooks.onPageChange(newPageId);
135
142
  } else if (action.type === 'cancel') {
136
143
  setRedoPages(Date.now);
137
144
  setPageId('hub');
145
+ hooks.onPageChange('hub');
138
146
  } else {
139
147
  // Submit.
140
148
  if (patch) {
141
149
  setData(function (prev) {
142
150
  return _objectSpread(_objectSpread({}, prev), patch);
143
151
  });
144
- } // Now submit the data to the backend and, if that succeeds...
152
+ } // Now submit the data to the backend...
145
153
 
146
154
 
147
- setPageId('hub');
155
+ hooks.onSubmit(action.type, _objectSpread(_objectSpread({}, data), patch), function () {
156
+ setPageId('hub');
157
+ hooks.onPageChange('hub');
158
+ }, function (errors) {
159
+ // Handle the errors.
160
+ console.error('Submission errors', errors);
161
+ });
148
162
  }
149
163
  }
150
164
  }; // Handle navigation from "Check your answers".
@@ -152,12 +166,14 @@ var FormRenderer = function FormRenderer(_ref) {
152
166
 
153
167
  var onCheckYourAnswerChange = function onCheckYourAnswerChange(page) {
154
168
  var action = page.action;
169
+ var newPageId = page.pageId;
155
170
 
156
171
  if (action && action.href) {
157
- setPageId(action.href.replace('/', ''));
158
- } else {
159
- setPageId(page.pageId);
172
+ newPageId = action.href.replace('/', '');
160
173
  }
174
+
175
+ setPageId(newPageId);
176
+ hooks.onPageChange(newPageId);
161
177
  };
162
178
 
163
179
  var classes = _utils.default.classBuilder(classBlock, classModifiers, className);
@@ -170,8 +186,7 @@ var FormRenderer = function FormRenderer(_ref) {
170
186
  onAction: onCheckYourAnswerChange
171
187
  })), formState.page && /*#__PURE__*/_react.default.createElement(_FormPage.default, {
172
188
  page: formState.page,
173
- onAction: onAction,
174
- classes: classes
189
+ onAction: onAction
175
190
  }));
176
191
  };
177
192
 
@@ -0,0 +1,87 @@
1
+ <!-- Global imports -->
2
+ import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
3
+ import { Details, Heading, Link } from '@ukhomeoffice/cop-react-components';
4
+ import withMock from 'storybook-addon-mock';
5
+
6
+ <!-- Local imports -->
7
+ import { addHook } from '../../hooks/useHooks';
8
+ import FormRenderer from './FormRenderer';
9
+
10
+ <!-- JSON documents -->
11
+ import CIVIL_SERVANT from '../../json/areYouACivilServant.json';
12
+ import GRADE from '../../json/grade.json';
13
+ import TEAMS from '../../json/team.json';
14
+ import USER_PROFILE_DATA from '../../json/userProfile.data.json';
15
+ import USER_PROFILE from '../../json/userProfile.json';
16
+ import SAVE_AND_CONTINUE from '../../json/saveAndContinue.json';
17
+
18
+ <Meta title="Components/Form renderer" id="D-FormRenderer" component={ FormRenderer } decorators={[withMock]} />
19
+
20
+ <Heading size="xl" caption="Components">Form renderer</Heading>
21
+
22
+ Renders a form with <Link href="https://ukhomeoffice.github.io/cop-react-components/?path=/docs/d-alert--default-story">COP React components</Link>,
23
+ on the basis of a <Link href="/?path=/docs/f-json-form">JSON</Link> that describes which elements are required.
24
+
25
+ <Canvas withToolbar>
26
+ <Story name="Default" parameters={{
27
+ mockData: [
28
+ {
29
+ url: `${USER_PROFILE_DATA.environmentContext.referenceDataUrl}/v2/entities/areYouACivilServant`,
30
+ method: 'GET',
31
+ status: 200,
32
+ response: CIVIL_SERVANT
33
+ },
34
+ {
35
+ url: `${USER_PROFILE_DATA.environmentContext.referenceDataUrl}/v2/entities/grade`,
36
+ method: 'GET',
37
+ status: 200,
38
+ response: GRADE
39
+ },
40
+ {
41
+ url: `${USER_PROFILE_DATA.environmentContext.referenceDataUrl}/v1/entities/team`,
42
+ method: 'GET',
43
+ status: 200,
44
+ response: TEAMS
45
+ }
46
+ ]
47
+ }}>
48
+ {() => {
49
+ return (
50
+ <FormRenderer {...USER_PROFILE} data={USER_PROFILE_DATA} />
51
+ );
52
+ }}
53
+ </Story>
54
+ </Canvas>
55
+
56
+ <Details summary="Properties" className="no-indent">
57
+ <ArgsTable of={ FormRenderer } />
58
+ </Details>
59
+
60
+ ## Custom hooks
61
+
62
+ <Canvas>
63
+ <Story name="Save and continue">
64
+ {() => {
65
+ addHook('onRequest', (req) => {
66
+ // Do whatever you need to do to the request in here, such as adding an Authorization header.
67
+ console.log('onRequest hook called');
68
+ return req;
69
+ });
70
+ addHook('onFormLoad', () => {
71
+ console.log('onFormLoad called');
72
+ });
73
+ addHook('onPageChange', (pageId) => {
74
+ console.log('onPageChange called', pageId);
75
+ });
76
+ // In whatever consumes this, do it as:
77
+ // intercepts.add('onSubmit', (...) => { ... })
78
+ addHook('onSubmit', (type, payload, onSuccess, onError) => {
79
+ console.log('onSubmit called of type', type, 'called, with the payload', payload);
80
+ onSuccess();
81
+ });
82
+ return (
83
+ <FormRenderer {...SAVE_AND_CONTINUE} data={{}} />
84
+ );
85
+ }}
86
+ </Story>
87
+ </Canvas>
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _utils = _interopRequireDefault(require("../../../utils"));
9
+
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+
12
+ // Local imports
13
+
14
+ /**
15
+ * Assesses whether the action can proceed when navigating, submitting, etc.
16
+ * Presently, this will validate a page when submitting and, only if the page is
17
+ * valid will it proceed. If it's simple navigation, it simply returns true.
18
+ * @param {object} action The action object we're assessing.
19
+ * @param {object} page The page configuration object this action relates to.
20
+ * @param {Function} onError A function to call with any validation errors.
21
+ * @returns A boolean where `true` means the action can proceed and `false` means it cannot.
22
+ */
23
+ var canActionProceed = function canActionProceed(action, page, onError) {
24
+ if (action.validate) {
25
+ var errors = _utils.default.Validate.page(page.components, page.formData);
26
+
27
+ onError(errors);
28
+ return errors.length === 0;
29
+ }
30
+
31
+ return true;
32
+ };
33
+
34
+ var _default = canActionProceed;
35
+ exports.default = _default;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ var _canActionProceed = _interopRequireDefault(require("./canActionProceed"));
4
+
5
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6
+
7
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
8
+
9
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
10
+
11
+ 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); }
12
+
13
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
14
+
15
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
16
+
17
+ 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; }
18
+
19
+ describe('components', function () {
20
+ describe('FormRenderer', function () {
21
+ describe('helpers', function () {
22
+ describe('canActionProceed', function () {
23
+ it('should return true when the action does not require validation', function () {
24
+ var ACTION = {
25
+ validate: false
26
+ };
27
+ expect((0, _canActionProceed.default)(ACTION, {}, function () {})).toBeTruthy();
28
+ });
29
+ it('should return true when the page is valid', function () {
30
+ var ACTION = {
31
+ validate: true
32
+ };
33
+ var PAGE = {
34
+ components: [{
35
+ id: 'a',
36
+ fieldId: 'a',
37
+ label: 'Alpha',
38
+ required: true
39
+ }],
40
+ formData: {
41
+ a: 'Bravo'
42
+ }
43
+ };
44
+ expect((0, _canActionProceed.default)(ACTION, PAGE, function () {})).toBeTruthy();
45
+ });
46
+ it('should return false when the page is invalid and should have called the onErrors method appropriately', function () {
47
+ var ACTION = {
48
+ validate: true
49
+ };
50
+ var PAGE = {
51
+ components: [{
52
+ id: 'a',
53
+ fieldId: 'a',
54
+ label: 'Alpha',
55
+ required: true
56
+ }],
57
+ formData: {}
58
+ };
59
+ var ERRORS = [];
60
+
61
+ var ON_ERROR = function ON_ERROR(errors) {
62
+ ERRORS.push.apply(ERRORS, _toConsumableArray(errors));
63
+ };
64
+
65
+ expect((0, _canActionProceed.default)(ACTION, PAGE, ON_ERROR)).toBeFalsy();
66
+ expect(ERRORS.length).toEqual(1);
67
+ expect(ERRORS[0].id).toEqual('a');
68
+ expect(ERRORS[0].error).toEqual('Alpha is required');
69
+ });
70
+ });
71
+ });
72
+ });
73
+ });
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _models = require("../../../models");
9
+
10
+ // Local imports
11
+
12
+ /**
13
+ * Gets a configuration object for the Check your answers screen.
14
+ * @param {string} pageId The current page identifier.
15
+ * @param {object} hub The hub, if there is one.
16
+ * @returns A configuration object for the Check your answers screen.
17
+ */
18
+ var getCYA = function getCYA(pageId, hub) {
19
+ if (pageId === 'hub' && hub === _models.HubFormats.CYA) {
20
+ return {
21
+ title: ''
22
+ };
23
+ } else if (pageId === _models.HubFormats.CYA) {
24
+ return {};
25
+ }
26
+
27
+ return undefined;
28
+ };
29
+
30
+ var _default = getCYA;
31
+ exports.default = _default;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ var _models = require("../../../models");
4
+
5
+ var _getCYA = _interopRequireDefault(require("./getCYA"));
6
+
7
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8
+
9
+ // Local imports
10
+ describe('components', function () {
11
+ describe('FormRenderer', function () {
12
+ describe('helpers', function () {
13
+ var HUB = {
14
+ id: 'hub',
15
+ components: []
16
+ };
17
+ describe('getCYA', function () {
18
+ it('should give an empty object if the pageId is "CYA"', function () {
19
+ expect((0, _getCYA.default)(_models.HubFormats.CYA)).toEqual({});
20
+ });
21
+ it('should give an object with a blank title if the pageId is "hub" and the hub is the CYA', function () {
22
+ expect((0, _getCYA.default)('hub', _models.HubFormats.CYA)).toEqual({
23
+ title: ''
24
+ });
25
+ });
26
+ it('should give undefined if pageId is "hub" and the hub is NOT the CYA', function () {
27
+ expect((0, _getCYA.default)('hub', HUB)).toBeUndefined();
28
+ });
29
+ it('should give undefined if pageId is NOT "hub" and the hub is NOT the CYA', function () {
30
+ expect((0, _getCYA.default)('bob', HUB)).toBeUndefined();
31
+ });
32
+ it('should give undefined if pageId is NOT "hub" and the hub is the CYA', function () {
33
+ expect((0, _getCYA.default)('bob', _models.HubFormats.CYA)).toBeUndefined();
34
+ });
35
+ });
36
+ });
37
+ });
38
+ });
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _getCYA = _interopRequireDefault(require("./getCYA"));
9
+
10
+ var _getPage = _interopRequireDefault(require("./getPage"));
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ // Local imports
15
+
16
+ /**
17
+ * Sets up the state of the form, including the current page and the Check your answers screen.
18
+ * @param {string} pageId The current page identifier.
19
+ * @param {Array} pages All of the pages in the form.
20
+ * @param {object} hub The hub, if there is one.
21
+ * @returns The current state of the form.
22
+ */
23
+ var getFormState = function getFormState(pageId, pages, hub) {
24
+ return {
25
+ pageId: pageId,
26
+ cya: (0, _getCYA.default)(pageId, hub),
27
+ page: (0, _getPage.default)(pageId, pages, hub)
28
+ };
29
+ };
30
+
31
+ var _default = getFormState;
32
+ exports.default = _default;