@uportal/form-builder 1.3.1 → 2.0.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.
package/src/App.js DELETED
@@ -1,301 +0,0 @@
1
-
2
- import React, { Component } from 'react';
3
- import Form from "react-jsonschema-form";
4
- import PropTypes from 'prop-types';
5
- import oidc from '@uportal/open-id-connect';
6
- import get from 'lodash.get';
7
- import { library } from '@fortawesome/fontawesome-svg-core';
8
- import { faExclamationCircle, faCheckCircle } from '@fortawesome/free-solid-svg-icons';
9
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
10
- import 'regenerator-runtime/runtime';
11
-
12
- library.add(faExclamationCircle, faCheckCircle);
13
-
14
- // FIXME: remove this
15
- const log = (type) => console.log.bind(console, type);
16
-
17
- class App extends Component {
18
- static propTypes = {
19
- fbmsBaseUrl: PropTypes.string,
20
- fbmsFormFname: PropTypes.string.isRequired,
21
- oidcUrl: PropTypes.string,
22
- showErrorList: PropTypes.bool,
23
- styles: PropTypes.string
24
- };
25
-
26
- static defaultProps = {
27
- fbmsBaseUrl: '/fbms',
28
- showErrorList: true
29
- };
30
-
31
- state = {
32
- schema: {},
33
- uiSchema: {},
34
- formData: {},
35
- hasError: false,
36
- submissionStatus: {},
37
- hasSuccess: false,
38
- fbmsFormFname: this.props.fbmsFormFname,
39
- };
40
-
41
- handleOidcError = (err) => {
42
- console.error(err);
43
- this.setState({hasError: true, errorMessage: 'There was a problem authorizing this request.'});
44
- };
45
-
46
- handleFbmsError = (err) => {
47
- if (err.type === 'submission') {
48
- err.messageHeader = 'There was a problem submitting your form.';
49
- } else {
50
- err.messageHeader = 'There was a problem finding your form.';
51
- }
52
-
53
- this.setState({hasError: true});
54
- };
55
-
56
- handleChange = (data) => {
57
- this.setState({formData: data.formData});
58
- };
59
-
60
- getToken = async () => {
61
- const {oidcUrl} = this.props;
62
-
63
- try {
64
- return (await oidc({userInfoApiUrl: oidcUrl, timeout: 18000}));
65
- } catch (err) {
66
- console.error(err);
67
- this.handleOidcError(err);
68
- }
69
- };
70
-
71
- fetchSchema = async () => {
72
- const {fbmsBaseUrl} = this.props;
73
- const {fbmsFormFname} = this.state;
74
- try {
75
- const response = await fetch(fbmsBaseUrl + '/api/v1/forms/' + fbmsFormFname, {
76
- credentials: 'same-origin',
77
- headers: {
78
- 'Authorization': 'Bearer ' + (await this.getToken()).encoded,
79
- 'content-type': 'application/jwt',
80
- }
81
- });
82
-
83
- if (!response.ok) {
84
- throw new Error(response.statusText);
85
- }
86
-
87
- const payload = await response.json();
88
- const fbmsFormVersion = payload.version;
89
- const uiSchema = payload.metadata;
90
- const schema = payload.schema;
91
-
92
- this.setState({fbmsFormVersion, schema, uiSchema});
93
- this.fetchFormData();
94
- } catch (err) {
95
- // error
96
- this.handleFbmsError(err);
97
- console.error(err);
98
- }
99
- };
100
-
101
- fetchFormData = async () => {
102
- const {fbmsBaseUrl} = this.props;
103
- const {fbmsFormFname} = this.state;
104
-
105
- // Add a random query string token to the URL to get around the way
106
- // Safari caches content, despite explicit Cache-Control header settings.
107
- const submissionUrl = fbmsBaseUrl + '/api/v1/submissions/' + fbmsFormFname + '?safarifix=' + Math.random();
108
-
109
- try {
110
- const response = await fetch(submissionUrl, {
111
- credentials: 'same-origin',
112
- headers: {
113
- 'Authorization': 'Bearer ' + (await this.getToken()).encoded,
114
- 'content-type': 'application/jwt',
115
- }
116
- });
117
-
118
- if (!response.ok) {
119
- if (response.status !== 404) {
120
- throw new Error(response.statusText);
121
- } else {
122
- return;
123
- }
124
- }
125
-
126
- const payload = await response.json();
127
- const formData = payload.answers;
128
- this.setState({formData});
129
- } catch (err) {
130
- console.error(err);
131
- this.handleFbmsError(err);
132
- }
133
- };
134
-
135
- transformBody = (formData, username) => {
136
- const {fbmsFormFname, fbmsFormVersion} = this.state;
137
- return {
138
- username: username,
139
- formFname: fbmsFormFname,
140
- formVersion: fbmsFormVersion,
141
- timestamp: Date.now(),
142
- answers: formData
143
- };
144
- };
145
-
146
- conditionallyHideSubmit = (schema) => {
147
- if (schema.properties && Object.keys(schema.properties).length === 0) {
148
- return (
149
- ' '
150
- )
151
- }
152
- };
153
-
154
- submitForm = async (userFormData) => {
155
- const {fbmsBaseUrl} = this.props;
156
- const {fbmsFormFname} = this.state;
157
- const token = await this.getToken();
158
- const body = this.transformBody(userFormData, token.decoded.sub);
159
- this.setState({hasError: false});
160
-
161
- try {
162
- const response = await fetch(fbmsBaseUrl + '/api/v1/submissions/' + fbmsFormFname, {
163
- method: 'POST',
164
- credentials: 'same-origin',
165
- headers: {
166
- 'Authorization': 'Bearer ' + token.encoded,
167
- 'content-type': 'application/json',
168
- },
169
- body: JSON.stringify(body)
170
- });
171
-
172
- let submissionStatus = await response.json();
173
- this.setState({submissionStatus});
174
-
175
- if (!response.ok) {
176
- submissionStatus.type = 'submission';
177
- this.handleFbmsError(submissionStatus);
178
- throw new Error(response.statusText);
179
- }
180
-
181
- this.fetchFormData();
182
-
183
- /* Note: for...of was not used here because of IE */
184
- const entries = response.headers.entries();
185
- let formForward,
186
- item = entries.next();
187
- while (!item.done) {
188
- let headerName = item.value[0],
189
- headerValue = item.value[1];
190
- if (headerName.toLowerCase() === 'x-fbms-formforward') {
191
- formForward = headerValue;
192
- break;
193
- }
194
- item = entries.next();
195
- }
196
-
197
- if (formForward) {
198
- this.setState({fbmsFormFname: formForward});
199
- this.getForm();
200
- }
201
-
202
- this.setState({hasSuccess: true});
203
- this.scrollToNotification();
204
- } catch (err) {
205
- console.error(err);
206
- this.scrollToNotification();
207
- }
208
- };
209
-
210
- scrollToNotification = () => {
211
- const element = document.getElementById('form-builder-notification');
212
- if (element) {
213
- element.scrollIntoView({behavior: 'smooth'});
214
- }
215
- };
216
-
217
- getForm = () => {
218
- this.fetchSchema();
219
- };
220
-
221
- /**
222
- * Allows any message from a validation rule to be overridden.
223
- * Overrides come from a "messages" object, with a property matching the
224
- * rule that will be overridden.
225
- * For example to override a string pattern, that following schema could be
226
- * used.
227
- *
228
- * "example": {
229
- * "type": "string",
230
- * "pattern": "^[A-Z]{3}$",
231
- * "messages": {
232
- * "pattern": "Must be three upper case letters"
233
- * }
234
- * }
235
- */
236
- transformErrors = (errors) => errors.map((err) => {
237
- const {property, name} = err;
238
- const {schema} = this.state;
239
- const pathParts = property.split('.');
240
- const prefix = pathParts.join('.properties.').substring(1); // remove leading period (.)
241
- const messageLocation = prefix + '.messages.' + name;
242
- const customMessage = get(schema, messageLocation);
243
- if (customMessage) {
244
- err.message = customMessage;
245
- }
246
- return err;
247
- });
248
-
249
- componentDidMount = this.getForm;
250
-
251
- render = () => {
252
- const {schema, uiSchema, formData, hasError, hasSuccess, submissionStatus} = this.state;
253
- const onSubmit = ({formData}) => this.submitForm(formData);
254
-
255
- return (
256
- <div>
257
- {this.props.styles && <style>{this.props.styles}</style>}
258
- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"></link>
259
- { hasError &&
260
- <div id="form-builder-notification" className="alert alert-danger" role="alert">
261
- <h3><FontAwesomeIcon icon="exclamation-circle" style={{width: '1em'}} /> {submissionStatus.messageHeader}</h3>
262
- {submissionStatus && submissionStatus.messages && submissionStatus.messages.length > 0 &&
263
- <ul>
264
- {submissionStatus.messages.map((item, index) => (
265
- <li key={index}>{item}</li>
266
- ))}
267
- </ul>
268
- }
269
- </div>
270
- }
271
- { hasSuccess &&
272
- <div id="form-builder-notification" className="alert alert-success" role="alert">
273
- <FontAwesomeIcon icon="check-circle" style={{width: '1em'}} /> Your form was successfully submitted.
274
- {submissionStatus && submissionStatus.messages && submissionStatus.messages.length > 0 &&
275
- <ul>
276
- {submissionStatus.messages.map((item, index) => (
277
- <li key={index}>{item}</li>
278
- ))}
279
- </ul>
280
- }
281
- </div>
282
- }
283
-
284
- <Form
285
- schema={schema}
286
- uiSchema={uiSchema}
287
- formData={formData}
288
- onChange={this.handleChange}
289
- onSubmit={onSubmit}
290
- onError={log("errors")}
291
- showErrorList={this.props.showErrorList}
292
- transformErrors={this.transformErrors}
293
- safeRenderCompletion={true}>
294
- {this.conditionallyHideSubmit(schema)}
295
- </Form>
296
- </div>
297
- );
298
- }
299
- }
300
-
301
- export default App;
package/src/App.test.js DELETED
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom';
3
- import App from './App';
4
-
5
- it('renders without crashing', () => {
6
- const div = document.createElement('div');
7
- ReactDOM.render(<App />, div);
8
- ReactDOM.unmountComponentAtNode(div);
9
- });
package/src/setupProxy.js DELETED
@@ -1,8 +0,0 @@
1
- // See: https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development#configuring-the-proxy-manually
2
-
3
- const proxy = require('http-proxy-middleware');
4
-
5
- module.exports = function(app) {
6
- app.use(proxy('/uPortal', { target: 'http://localhost:8080' }));
7
- app.use(proxy('/fbms', { target: 'http://localhost:8080' }));
8
- };