@ukhomeoffice/cop-react-form-renderer 0.1.0-beta → 1.0.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 (92) hide show
  1. package/dist/components/CheckYourAnswers/Answer.js +48 -0
  2. package/dist/components/CheckYourAnswers/Answer.test.js +94 -0
  3. package/dist/components/CheckYourAnswers/CheckYourAnswers.js +94 -23
  4. package/dist/components/CheckYourAnswers/CheckYourAnswers.scss +0 -7
  5. package/dist/components/CheckYourAnswers/CheckYourAnswers.stories.mdx +149 -0
  6. package/dist/components/CheckYourAnswers/CheckYourAnswers.test.js +332 -0
  7. package/dist/components/FormComponent/FormComponent.js +7 -7
  8. package/dist/components/FormComponent/FormComponent.stories.mdx +167 -0
  9. package/dist/components/FormComponent/FormComponent.test.js +137 -0
  10. package/dist/components/FormPage/FormPage.js +12 -11
  11. package/dist/components/FormPage/FormPage.stories.mdx +118 -0
  12. package/dist/components/FormPage/FormPage.test.js +255 -0
  13. package/dist/components/FormRenderer/FormRenderer.js +95 -54
  14. package/dist/components/FormRenderer/FormRenderer.stories.mdx +115 -0
  15. package/dist/components/FormRenderer/FormRenderer.test.js +471 -0
  16. package/dist/components/FormRenderer/handlers/cyaAction.js +28 -0
  17. package/dist/components/FormRenderer/handlers/getPageId.js +28 -0
  18. package/dist/components/FormRenderer/handlers/getPageId.test.js +61 -0
  19. package/dist/components/FormRenderer/handlers/handlers.test.js +97 -0
  20. package/dist/components/FormRenderer/handlers/index.js +23 -0
  21. package/dist/components/FormRenderer/handlers/navigate.js +28 -0
  22. package/dist/components/FormRenderer/handlers/submissionError.js +20 -0
  23. package/dist/components/FormRenderer/helpers/canActionProceed.js +35 -0
  24. package/dist/components/FormRenderer/helpers/canActionProceed.test.js +73 -0
  25. package/dist/components/FormRenderer/helpers/canCYASubmit.js +42 -0
  26. package/dist/components/FormRenderer/helpers/canCYASubmit.test.js +155 -0
  27. package/dist/components/FormRenderer/helpers/getCYA.js +31 -0
  28. package/dist/components/FormRenderer/helpers/getCYA.test.js +38 -0
  29. package/dist/components/FormRenderer/helpers/getFormState.js +32 -0
  30. package/dist/components/FormRenderer/helpers/getFormState.test.js +61 -0
  31. package/dist/components/FormRenderer/helpers/getNextPageId.js +65 -0
  32. package/dist/components/FormRenderer/helpers/getNextPageId.test.js +90 -0
  33. package/dist/components/FormRenderer/helpers/getPage.js +34 -0
  34. package/dist/components/FormRenderer/helpers/getPage.test.js +46 -0
  35. package/dist/components/FormRenderer/helpers/index.js +27 -0
  36. package/dist/components/PageActions/ActionButton.js +58 -0
  37. package/dist/components/PageActions/ActionButton.test.js +116 -0
  38. package/dist/components/PageActions/PageActions.js +18 -25
  39. package/dist/components/PageActions/PageActions.stories.mdx +74 -0
  40. package/dist/components/PageActions/PageActions.test.js +157 -0
  41. package/dist/components/SummaryList/RowAction.js +13 -22
  42. package/dist/components/SummaryList/RowAction.test.js +94 -0
  43. package/dist/components/SummaryList/SummaryList.js +6 -20
  44. package/dist/components/SummaryList/SummaryList.scss +7 -0
  45. package/dist/components/SummaryList/SummaryList.stories.mdx +36 -0
  46. package/dist/components/SummaryList/SummaryList.test.js +197 -0
  47. package/dist/components/SummaryList/helpers/getRowActionAttributes.js +27 -0
  48. package/dist/components/SummaryList/helpers/getRowActionAttributes.test.js +77 -0
  49. package/dist/components/SummaryList/helpers/index.js +15 -0
  50. package/dist/components/index.js +8 -0
  51. package/dist/hooks/useGetRequest.js +16 -1
  52. package/dist/hooks/useHooks.js +16 -5
  53. package/dist/index.js +3 -1
  54. package/dist/index.test.js +18 -0
  55. package/dist/models/EventTypes.js +14 -0
  56. package/dist/models/FormPages.js +14 -0
  57. package/dist/models/PageAction.js +40 -0
  58. package/dist/models/index.js +24 -0
  59. package/dist/utils/CheckYourAnswers/getCYAAction.js +9 -0
  60. package/dist/utils/CheckYourAnswers/getCYARow.js +10 -0
  61. package/dist/utils/CheckYourAnswers/getCYARowsForPage.js +9 -0
  62. package/dist/utils/CheckYourAnswers/showComponentCYA.js +6 -5
  63. package/dist/utils/Component/getComponent.js +2 -2
  64. package/dist/utils/Component/getComponent.test.js +1 -1
  65. package/dist/utils/Data/setupFormData.js +3 -3
  66. package/dist/utils/Data/setupFormData.test.js +6 -6
  67. package/dist/utils/Data/setupRefDataUrlForComponent.test.js +4 -4
  68. package/dist/utils/FormPage/getFormPage.js +12 -1
  69. package/dist/utils/FormPage/getFormPage.test.js +178 -0
  70. package/dist/utils/FormPage/getFormPages.js +11 -6
  71. package/dist/utils/FormPage/getFormPages.test.js +95 -0
  72. package/dist/utils/FormPage/getParagraphFromText.js +6 -0
  73. package/dist/utils/FormPage/getParagraphFromText.test.js +29 -0
  74. package/dist/utils/FormPage/useComponent.js +9 -2
  75. package/dist/utils/FormPage/useComponent.test.js +82 -0
  76. package/dist/utils/Format/formatData.js +32 -0
  77. package/dist/utils/Format/formatData.test.js +46 -0
  78. package/dist/utils/Format/formatDataForComponent.js +41 -0
  79. package/dist/utils/Format/formatDataForComponent.test.js +161 -0
  80. package/dist/utils/Format/formatDataForForm.js +33 -0
  81. package/dist/utils/Format/formatDataForForm.test.js +78 -0
  82. package/dist/utils/Format/formatDataForPage.js +37 -0
  83. package/dist/utils/Format/formatDataForPage.test.js +96 -0
  84. package/dist/utils/Format/index.js +26 -0
  85. package/dist/utils/Hub/getFormHub.js +18 -4
  86. package/dist/utils/Hub/getFormHub.test.js +96 -0
  87. package/dist/utils/Hub/index.js +0 -3
  88. package/dist/utils/Validate/validatePage.test.js +1 -1
  89. package/dist/utils/index.js +3 -0
  90. package/package.json +6 -3
  91. package/dist/components/FormRenderer/helpers.js +0 -66
  92. package/dist/components/FormRenderer/helpers.test.js +0 -158
@@ -5,7 +5,7 @@ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "functi
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.default = void 0;
8
+ exports.default = exports.DEFAULT_CLASS = void 0;
9
9
 
10
10
  var _copReactComponents = require("@ukhomeoffice/cop-react-components");
11
11
 
@@ -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
 
@@ -23,7 +23,9 @@ var _CheckYourAnswers = _interopRequireDefault(require("../CheckYourAnswers"));
23
23
 
24
24
  var _FormPage = _interopRequireDefault(require("../FormPage"));
25
25
 
26
- var _helpers = require("./helpers");
26
+ var _handlers = _interopRequireDefault(require("./handlers"));
27
+
28
+ var _helpers = _interopRequireDefault(require("./helpers"));
27
29
 
28
30
  require("./FormRenderer.scss");
29
31
 
@@ -54,6 +56,7 @@ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Sy
54
56
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
55
57
 
56
58
  var DEFAULT_CLASS = 'hods-form';
59
+ exports.DEFAULT_CLASS = DEFAULT_CLASS;
57
60
 
58
61
  var FormRenderer = function FormRenderer(_ref) {
59
62
  var title = _ref.title,
@@ -61,9 +64,9 @@ var FormRenderer = function FormRenderer(_ref) {
61
64
  components = _ref.components,
62
65
  _pages = _ref.pages,
63
66
  _hub = _ref.hub,
64
- _cya = _ref.cya,
67
+ cya = _ref.cya,
65
68
  _data = _ref.data,
66
- hooks = _ref.hooks,
69
+ _hooks = _ref.hooks,
67
70
  classBlock = _ref.classBlock,
68
71
  classModifiers = _ref.classModifiers,
69
72
  className = _ref.className;
@@ -74,42 +77,38 @@ var FormRenderer = function FormRenderer(_ref) {
74
77
  data = _useState2[0],
75
78
  setData = _useState2[1];
76
79
 
77
- var _useState3 = (0, _react.useState)(0),
80
+ var _useState3 = (0, _react.useState)([]),
78
81
  _useState4 = _slicedToArray(_useState3, 2),
79
- redoPages = _useState4[0],
80
- setRedoPages = _useState4[1];
82
+ pages = _useState4[0],
83
+ setPages = _useState4[1];
81
84
 
82
- var _useState5 = (0, _react.useState)([]),
85
+ var _useState5 = (0, _react.useState)(undefined),
83
86
  _useState6 = _slicedToArray(_useState5, 2),
84
- pages = _useState6[0],
85
- setPages = _useState6[1];
87
+ hub = _useState6[0],
88
+ setHub = _useState6[1];
86
89
 
87
- var _useState7 = (0, _react.useState)(undefined),
90
+ var _useState7 = (0, _react.useState)(_helpers.default.getNextPageId(type, _pages)),
88
91
  _useState8 = _slicedToArray(_useState7, 2),
89
- hub = _useState8[0],
90
- setHub = _useState8[1];
92
+ pageId = _useState8[0],
93
+ setPageId = _useState8[1];
91
94
 
92
- var _useState9 = (0, _react.useState)('hub'),
95
+ var _useState9 = (0, _react.useState)(_helpers.default.getFormState(pageId, pages, hub)),
93
96
  _useState10 = _slicedToArray(_useState9, 2),
94
- pageId = _useState10[0],
95
- setPageId = _useState10[1];
96
-
97
- var _useState11 = (0, _react.useState)((0, _helpers.getFormState)(pageId, pages, hub)),
98
- _useState12 = _slicedToArray(_useState11, 2),
99
- formState = _useState12[0],
100
- setFormState = _useState12[1]; // Set up hooks.
97
+ formState = _useState10[0],
98
+ setFormState = _useState10[1]; // Set up hooks.
101
99
 
102
100
 
103
- var _useHooks = (0, _hooks.useHooks)(),
101
+ var _useHooks = (0, _hooks2.useHooks)(),
102
+ hooks = _useHooks.hooks,
104
103
  addHook = _useHooks.addHook;
105
104
 
106
105
  (0, _react.useEffect)(function () {
107
- if (hooks) {
108
- Object.keys(hooks).forEach(function (key) {
109
- addHook(key, hooks[key]);
106
+ if (_hooks) {
107
+ Object.keys(_hooks).forEach(function (key) {
108
+ addHook(key, _hooks[key]);
110
109
  });
111
110
  }
112
- }, [hooks, addHook]); // Setup data.
111
+ }, [_hooks, addHook]); // Setup data.
113
112
 
114
113
  (0, _react.useEffect)(function () {
115
114
  setData(_utils.default.Data.setupForm(_pages, components, _data));
@@ -117,46 +116,85 @@ var FormRenderer = function FormRenderer(_ref) {
117
116
 
118
117
  (0, _react.useEffect)(function () {
119
118
  setPages(_utils.default.FormPage.getAll(_pages, components, _objectSpread({}, data)));
120
- }, [components, _pages, data, redoPages, setPages]); // Setup hub.
119
+ }, [components, _pages, data, setPages]); // Setup hub.
120
+
121
+ (0, _react.useEffect)(function () {
122
+ setHub(_utils.default.Hub.get(type, _hub, components, _objectSpread({}, data)));
123
+ }, [type, _hub, data, components, setHub]); // Form state.
121
124
 
122
125
  (0, _react.useEffect)(function () {
123
- setHub(_utils.default.Hub.get(type, _hub, components));
124
- }, [type, _hub, components, setHub]); // Form state.
126
+ setFormState(_helpers.default.getFormState(pageId, pages, hub));
127
+ }, [pages, hub, pageId, setFormState]); // Call the onFormLoad hook just when this component first renders.
125
128
 
126
129
  (0, _react.useEffect)(function () {
127
- setFormState((0, _helpers.getFormState)(pageId, pages, hub));
128
- }, [pages, hub, pageId, setFormState]); // Handle actions from pages.
130
+ hooks.onFormLoad();
131
+ }, [hooks]);
132
+
133
+ var onPageChange = function onPageChange(newPageId) {
134
+ setPageId(newPageId);
135
+ hooks.onPageChange(newPageId);
136
+ }; // Handle actions from pages.
137
+
129
138
 
130
- var onAction = function onAction(action, patch, onError) {
131
- // First check the validity of the
132
- if ((0, _helpers.canActionProceed)(action, formState.page, onError)) {
139
+ var onPageAction = function onPageAction(action, patch, onError) {
140
+ // Check to see whether the action is able to proceed, which in
141
+ // in the case of a submission will validate the fields in the page.
142
+ if (_helpers.default.canActionProceed(action, formState.page, onError)) {
133
143
  if (action.type === 'navigate') {
134
- setPageId(action.url.replace('/', ''));
135
- } else if (action.type === 'cancel') {
136
- setRedoPages(Date.now);
137
- setPageId('hub');
144
+ _handlers.default.navigate(action, pageId, onPageChange);
138
145
  } else {
139
146
  // Submit.
147
+ var submissionData = _utils.default.Format.form({
148
+ pages: pages,
149
+ components: components
150
+ }, _objectSpread(_objectSpread({}, data), patch), _models.EventTypes.SUBMIT);
151
+
140
152
  if (patch) {
153
+ setData(submissionData);
154
+ } // Now submit the data to the backend...
155
+
156
+
157
+ hooks.onSubmit(action.type, submissionData, function (response) {
158
+ // The backend response may well contain data we need so apply it.
141
159
  setData(function (prev) {
142
- return _objectSpread(_objectSpread({}, prev), patch);
160
+ return _objectSpread(_objectSpread({}, prev), response);
143
161
  });
144
- } // Now submit the data to the backend and, if that succeeds...
145
162
 
163
+ var nextPageId = _helpers.default.getNextPageId(type, pages, pageId, action);
146
164
 
147
- setPageId('hub');
165
+ onPageChange(nextPageId);
166
+ }, function (errors) {
167
+ _handlers.default.submissionError(errors, onError);
168
+ });
148
169
  }
149
170
  }
150
171
  }; // Handle navigation from "Check your answers".
151
172
 
152
173
 
153
- var onCheckYourAnswerChange = function onCheckYourAnswerChange(page) {
154
- var action = page.action;
174
+ var onCYARowAction = function onCYARowAction(page) {
175
+ _handlers.default.cyaAction(page, pageId, onPageChange);
176
+ }; // Handle actions from "Check your answers".
155
177
 
156
- if (action && action.href) {
157
- setPageId(action.href.replace('/', ''));
158
- } else {
159
- setPageId(page.pageId);
178
+
179
+ var onCYAAction = function onCYAAction(action, onError) {
180
+ // Check to see whether the action is able to proceed, which in
181
+ // in the case of a submission will validate the fields in the page.
182
+ if (action.type === _models.PageAction.TYPES.SUBMIT) {
183
+ if (_helpers.default.canCYASubmit(pages, onError)) {
184
+ // Submit.
185
+ var submissionData = _utils.default.Format.form({
186
+ pages: pages,
187
+ components: components
188
+ }, _objectSpread({}, data), _models.EventTypes.SUBMIT);
189
+
190
+ setData(submissionData); // Now submit the data to the backend...
191
+
192
+ hooks.onSubmit(action.type, submissionData, function () {
193
+ hooks.onFormComplete();
194
+ }, function (errors) {
195
+ _handlers.default.submissionError(errors, onError);
196
+ });
197
+ }
160
198
  }
161
199
  };
162
200
 
@@ -164,14 +202,14 @@ var FormRenderer = function FormRenderer(_ref) {
164
202
 
165
203
  return /*#__PURE__*/_react.default.createElement("div", {
166
204
  className: classes()
167
- }, title && pageId === 'hub' && /*#__PURE__*/_react.default.createElement(_copReactComponents.LargeHeading, null, title), formState.cya && /*#__PURE__*/_react.default.createElement(_CheckYourAnswers.default, _extends({
205
+ }, title && pageId === _models.FormPages.HUB && /*#__PURE__*/_react.default.createElement(_copReactComponents.LargeHeading, null, title), formState.cya && /*#__PURE__*/_react.default.createElement(_CheckYourAnswers.default, _extends({
168
206
  pages: pages
169
- }, _cya, formState.cya, {
170
- onAction: onCheckYourAnswerChange
207
+ }, cya, formState.cya, {
208
+ onAction: onCYAAction,
209
+ onRowAction: onCYARowAction
171
210
  })), formState.page && /*#__PURE__*/_react.default.createElement(_FormPage.default, {
172
211
  page: formState.page,
173
- onAction: onAction,
174
- classes: classes
212
+ onAction: onPageAction
175
213
  }));
176
214
  };
177
215
 
@@ -186,7 +224,10 @@ FormRenderer.propTypes = {
186
224
  cya: _propTypes.default.object,
187
225
  data: _propTypes.default.object,
188
226
  hooks: _propTypes.default.shape({
189
- onRequest: _propTypes.default.func
227
+ onFormLoad: _propTypes.default.func,
228
+ onPageChange: _propTypes.default.func,
229
+ onRequest: _propTypes.default.func,
230
+ onSubmit: _propTypes.default.func
190
231
  }),
191
232
  classBlock: _propTypes.default.string,
192
233
  classModifiers: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
@@ -0,0 +1,115 @@
1
+ <!-- Global imports -->
2
+ import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
3
+ import { Button, Details, Heading, Link, Panel } from '@ukhomeoffice/cop-react-components';
4
+ import { useState } from 'react';
5
+ import withMock from 'storybook-addon-mock';
6
+
7
+ <!-- Local imports -->
8
+ import { addHook } from '../../hooks/useHooks';
9
+ import FormRenderer from './FormRenderer';
10
+
11
+ <!-- JSON documents -->
12
+ import CIVIL_SERVANT from '../../json/areYouACivilServant.json';
13
+ import FIRST_FORM from '../../json/firstForm.json';
14
+ import GRADE from '../../json/grade.json';
15
+ import TEAMS from '../../json/team.json';
16
+ import USER_PROFILE_DATA from '../../json/userProfile.data.json';
17
+ import USER_PROFILE from '../../json/userProfile.json';
18
+
19
+ <Meta title="Components/Form renderer" id="D-FormRenderer" component={ FormRenderer } decorators={[withMock]} />
20
+
21
+ <Heading size="xl" caption="Components">Form renderer</Heading>
22
+
23
+ Renders a form with <Link href="https://ukhomeoffice.github.io/cop-react-components/?path=/docs/d-alert--default-story">COP React components</Link>,
24
+ on the basis of a <Link href="/?path=/docs/f-json-form">JSON</Link> that describes which elements are required.
25
+
26
+ <Canvas withToolbar>
27
+ <Story name="Default" parameters={{
28
+ mockData: [
29
+ {
30
+ url: `${USER_PROFILE_DATA.urls.refData}/areYouACivilServant`,
31
+ method: 'GET',
32
+ status: 200,
33
+ response: CIVIL_SERVANT
34
+ },
35
+ {
36
+ url: `${USER_PROFILE_DATA.urls.refData}/grade`,
37
+ method: 'GET',
38
+ status: 200,
39
+ response: GRADE
40
+ },
41
+ {
42
+ url: `${USER_PROFILE_DATA.urls.refData}/team`,
43
+ method: 'GET',
44
+ status: 200,
45
+ response: TEAMS
46
+ }
47
+ ]
48
+ }}>
49
+ {() => {
50
+ return (
51
+ <FormRenderer {...USER_PROFILE} data={USER_PROFILE_DATA} />
52
+ );
53
+ }}
54
+ </Story>
55
+ </Canvas>
56
+
57
+ <Details summary="Properties" className="no-indent">
58
+ <ArgsTable of={ FormRenderer } />
59
+ </Details>
60
+
61
+ ## CYA type
62
+
63
+ <Canvas>
64
+ <Story name="CYA">
65
+ {() => {
66
+ const [complete, setComplete] = useState(false);
67
+ const [returnLater, setReturnLater] = useState(false);
68
+ addHook('onRequest', (req) => {
69
+ // Do whatever you need to do to the request in here, such as adding an Authorization header.
70
+ console.log('onRequest hook called');
71
+ return req;
72
+ });
73
+ addHook('onFormLoad', () => {
74
+ console.log('onFormLoad called');
75
+ });
76
+ addHook('onFormComplete', () => {
77
+ console.log('onFormComplete called');
78
+ setComplete(true);
79
+ });
80
+ addHook('onPageChange', (pageId) => {
81
+ console.log('onPageChange called', pageId);
82
+ setReturnLater(!!pageId === false);
83
+ });
84
+ addHook('onSubmit', (type, payload, onSuccess, onError) => {
85
+ console.log('onSubmit called of type', type, 'called, with the payload', payload);
86
+ onSuccess();
87
+ });
88
+ const reset = () => {
89
+ setComplete(false);
90
+ setReturnLater(false);
91
+ };
92
+ return (
93
+ <>
94
+ {!complete && !returnLater && <FormRenderer {...FIRST_FORM} data={{}} />}
95
+ {complete &&
96
+ <div>
97
+ <Panel title="Submission successful">
98
+ Your submission was successful.
99
+ </Panel>
100
+ <Button onClick={() => reset()}>Start again</Button>
101
+ </div>
102
+ }
103
+ {!complete && returnLater &&
104
+ <div>
105
+ <Panel title="Saved to return later">
106
+ You clicked on "Save and return later".
107
+ </Panel>
108
+ <Button onClick={() => reset()}>Start again</Button>
109
+ </div>
110
+ }
111
+ </>
112
+ );
113
+ }}
114
+ </Story>
115
+ </Canvas>