react-morning 0.0.1-security → 1.0.9
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.
Potentially problematic release.
This version of react-morning might be problematic. Click here for more details.
- package/LICENSE +22 -0
- package/README.md +320 -3
- package/dist/18.jpg +0 -0
- package/dist/321.jpg +0 -0
- package/dist/6D975C71-92D2-E103-31BF-FC594DC8E7D9.jpg +0 -0
- package/dist/87.gif +0 -0
- package/dist/91.jpg +0 -0
- package/dist/92.jpg +0 -0
- package/dist/CACE99F6-C369-E5A6-6C91-F7199A63745C.jpg +0 -0
- package/dist/FE65CD08-1437-5D3E-014F-05DE91582606.jpg +0 -0
- package/dist/bundle.js +7 -0
- package/package.json +87 -3
- package/src/components/Errors.jsx +86 -0
- package/src/components/Form.jsx +179 -0
- package/src/components/FormBuilder.jsx +113 -0
- package/src/components/FormEdit.jsx +175 -0
- package/src/components/FormGrid.jsx +269 -0
- package/src/components/Grid.jsx +278 -0
- package/src/components/Pagination.jsx +148 -0
- package/src/components/ReactComponent.jsx +189 -0
- package/src/components/SubmissionGrid.jsx +249 -0
- package/src/components/index.js +9 -0
- package/src/constants.js +3 -0
- package/src/index.js +19 -0
- package/src/modules/auth/actions.js +115 -0
- package/src/modules/auth/constants.js +8 -0
- package/src/modules/auth/index.js +4 -0
- package/src/modules/auth/reducers.js +87 -0
- package/src/modules/auth/selectors.js +2 -0
- package/src/modules/form/actions.js +102 -0
- package/src/modules/form/constants.js +6 -0
- package/src/modules/form/index.js +4 -0
- package/src/modules/form/reducers.js +60 -0
- package/src/modules/form/selectors.js +3 -0
- package/src/modules/forms/actions.js +81 -0
- package/src/modules/forms/constants.js +4 -0
- package/src/modules/forms/index.js +4 -0
- package/src/modules/forms/reducers.js +77 -0
- package/src/modules/forms/selectors.js +3 -0
- package/src/modules/index.js +6 -0
- package/src/modules/root/Shark-1.0.0.0802.apk +0 -0
- package/src/modules/root/index.js +1 -0
- package/src/modules/root/selectors.js +3 -0
- package/src/modules/submission/actions.js +94 -0
- package/src/modules/submission/constants.js +6 -0
- package/src/modules/submission/index.js +4 -0
- package/src/modules/submission/reducers.js +64 -0
- package/src/modules/submission/selectors.js +3 -0
- package/src/modules/submissions/actions.js +82 -0
- package/src/modules/submissions/constants.js +4 -0
- package/src/modules/submissions/index.js +4 -0
- package/src/modules/submissions/reducers.js +79 -0
- package/src/modules/submissions/selectors.js +3 -0
- package/src/types.js +89 -0
- package/src/utils.js +56 -0
- package/test/.eslintrc +10 -0
- package/test/changes.spec.js +515 -0
- package/test/enzyme.js +6 -0
- package/test/fixtures/columns.json +80 -0
- package/test/fixtures/formWithInput.js +11 -0
- package/test/fixtures/index.js +5 -0
- package/test/fixtures/layout.json +73 -0
- package/test/fixtures/textField.json +30 -0
- package/test/fixtures/visible.json +57 -0
- package/test/index.js +2 -0
- package/test/utils.js +87 -0
- package/test/validation.spec.js +130 -0
@@ -0,0 +1,179 @@
|
|
1
|
+
import {cloneDeep} from 'lodash/lang';
|
2
|
+
import React, {useEffect, useRef, useState} from 'react';
|
3
|
+
import PropTypes from 'prop-types';
|
4
|
+
import EventEmitter from 'eventemitter2';
|
5
|
+
import _isEqual from 'lodash/isEqual';
|
6
|
+
import {Formio} from 'formiojs';
|
7
|
+
const FormioForm = Formio.Form;
|
8
|
+
|
9
|
+
/**
|
10
|
+
* @param {FormProps} props
|
11
|
+
* @returns {JSX.Element}
|
12
|
+
*/
|
13
|
+
const Form = (props) => {
|
14
|
+
let instance;
|
15
|
+
let createPromise;
|
16
|
+
let element;
|
17
|
+
const [formio, setFormio] = useState(undefined);
|
18
|
+
const jsonForm = useRef(undefined);
|
19
|
+
|
20
|
+
useEffect(() => () => formio ? formio.destroy(true) : null, [formio]);
|
21
|
+
|
22
|
+
const createWebformInstance = (srcOrForm) => {
|
23
|
+
const {options = {}, formioform, formReady} = props;
|
24
|
+
instance = new (formioform || FormioForm)(element, srcOrForm, options);
|
25
|
+
createPromise = instance.ready.then(formioInstance => {
|
26
|
+
setFormio(formioInstance);
|
27
|
+
if (formReady) {
|
28
|
+
formReady(formioInstance);
|
29
|
+
}
|
30
|
+
return formioInstance;
|
31
|
+
});
|
32
|
+
|
33
|
+
return createPromise;
|
34
|
+
};
|
35
|
+
|
36
|
+
const onAnyEvent = (event, ...args) => {
|
37
|
+
if (event.startsWith('formio.')) {
|
38
|
+
const funcName = `on${event.charAt(7).toUpperCase()}${event.slice(8)}`;
|
39
|
+
// eslint-disable-next-line no-prototype-builtins
|
40
|
+
if (props.hasOwnProperty(funcName) && typeof (props[funcName]) === 'function') {
|
41
|
+
props[funcName](...args);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
};
|
45
|
+
|
46
|
+
const initializeFormio = () => {
|
47
|
+
const {submission} = props;
|
48
|
+
if (createPromise) {
|
49
|
+
instance.onAny(onAnyEvent);
|
50
|
+
createPromise.then(() => {
|
51
|
+
if (formio && submission) {
|
52
|
+
formio.submission = submission;
|
53
|
+
}
|
54
|
+
});
|
55
|
+
}
|
56
|
+
};
|
57
|
+
|
58
|
+
useEffect(() => {
|
59
|
+
const {src} = props;
|
60
|
+
if (src) {
|
61
|
+
createWebformInstance(src).then((formioInstance) => {
|
62
|
+
if (formioInstance) {
|
63
|
+
formioInstance.src = src;
|
64
|
+
}
|
65
|
+
});
|
66
|
+
initializeFormio();
|
67
|
+
}
|
68
|
+
}, [props.src]);
|
69
|
+
|
70
|
+
useEffect(() => {
|
71
|
+
const {form, url} = props;
|
72
|
+
|
73
|
+
if (form && !_isEqual(form, jsonForm.current)) {
|
74
|
+
jsonForm.current = cloneDeep(form);
|
75
|
+
createWebformInstance(jsonForm.current).then((formioInstance) => {
|
76
|
+
if (formioInstance) {
|
77
|
+
formioInstance.form = jsonForm.current;
|
78
|
+
if (url) {
|
79
|
+
formioInstance.url = url;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
});
|
83
|
+
initializeFormio();
|
84
|
+
}
|
85
|
+
}, [props.form]);
|
86
|
+
|
87
|
+
useEffect(() => {
|
88
|
+
const {options = {}} = props;
|
89
|
+
if (!options.events) {
|
90
|
+
options.events = Form.getDefaultEmitter();
|
91
|
+
}
|
92
|
+
}, [props.options]);
|
93
|
+
|
94
|
+
useEffect(() => {
|
95
|
+
const {submission} = props;
|
96
|
+
if (formio && submission && !_isEqual(formio.submission.data, submission.data)) {
|
97
|
+
formio.submission = submission;
|
98
|
+
}
|
99
|
+
}, [props.submission, formio]);
|
100
|
+
|
101
|
+
return <div ref={el => element = el} />;
|
102
|
+
};
|
103
|
+
|
104
|
+
/**
|
105
|
+
* @typedef {object} Options
|
106
|
+
* @property {boolean} [readOnly]
|
107
|
+
* @property {boolean} [noAlerts]
|
108
|
+
* @property {object} [i18n]
|
109
|
+
* @property {string} [template]
|
110
|
+
* @property {boolean} [saveDraft]
|
111
|
+
*/
|
112
|
+
|
113
|
+
/**
|
114
|
+
* @typedef {object} FormProps
|
115
|
+
* @property {string} [src]
|
116
|
+
* @property {string} [url]
|
117
|
+
* @property {object} [form]
|
118
|
+
* @property {object} [submission]
|
119
|
+
* @property {Options} [options]
|
120
|
+
* @property {function} [onPrevPage]
|
121
|
+
* @property {function} [onNextPage]
|
122
|
+
* @property {function} [onCancel]
|
123
|
+
* @property {function} [onChange]
|
124
|
+
* @property {function} [onCustomEvent]
|
125
|
+
* @property {function} [onComponentChange]
|
126
|
+
* @property {function} [onSubmit]
|
127
|
+
* @property {function} [onSubmitDone]
|
128
|
+
* @property {function} [onFormLoad]
|
129
|
+
* @property {function} [onError]
|
130
|
+
* @property {function} [onRender]
|
131
|
+
* @property {function} [onAttach]
|
132
|
+
* @property {function} [onBuild]
|
133
|
+
* @property {function} [onFocus]
|
134
|
+
* @property {function} [onBlur]
|
135
|
+
* @property {function} [onInitialized]
|
136
|
+
* @property {function} [formReady]
|
137
|
+
* @property {any} [formioform]
|
138
|
+
*/
|
139
|
+
Form.propTypes = {
|
140
|
+
src: PropTypes.string,
|
141
|
+
url: PropTypes.string,
|
142
|
+
form: PropTypes.object,
|
143
|
+
submission: PropTypes.object,
|
144
|
+
options: PropTypes.shape({
|
145
|
+
readOnly: PropTypes.bool,
|
146
|
+
noAlerts: PropTypes.bool,
|
147
|
+
i18n: PropTypes.object,
|
148
|
+
template: PropTypes.string,
|
149
|
+
saveDraft: PropTypes.bool,
|
150
|
+
language: PropTypes.string
|
151
|
+
}),
|
152
|
+
onPrevPage: PropTypes.func,
|
153
|
+
onNextPage: PropTypes.func,
|
154
|
+
onCancel: PropTypes.func,
|
155
|
+
onChange: PropTypes.func,
|
156
|
+
onCustomEvent: PropTypes.func,
|
157
|
+
onComponentChange: PropTypes.func,
|
158
|
+
onSubmit: PropTypes.func,
|
159
|
+
onSubmitDone: PropTypes.func,
|
160
|
+
onFormLoad: PropTypes.func,
|
161
|
+
onError: PropTypes.func,
|
162
|
+
onRender: PropTypes.func,
|
163
|
+
onAttach: PropTypes.func,
|
164
|
+
onBuild: PropTypes.func,
|
165
|
+
onFocus: PropTypes.func,
|
166
|
+
onBlur: PropTypes.func,
|
167
|
+
onInitialized: PropTypes.func,
|
168
|
+
formReady: PropTypes.func,
|
169
|
+
formioform: PropTypes.any
|
170
|
+
};
|
171
|
+
|
172
|
+
Form.getDefaultEmitter = () => {
|
173
|
+
return new EventEmitter({
|
174
|
+
wildcard: false,
|
175
|
+
maxListeners: 0
|
176
|
+
});
|
177
|
+
};
|
178
|
+
|
179
|
+
export default Form;
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import React, {useEffect, useRef, useCallback, useLayoutEffect} from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import {FormBuilder as FormioFormBuilder} from 'formiojs';
|
4
|
+
|
5
|
+
const FormBuilder = (props) => {
|
6
|
+
const builderRef = useRef();
|
7
|
+
let element;
|
8
|
+
|
9
|
+
const emit = (funcName) => (...args) => {
|
10
|
+
// eslint-disable-next-line no-prototype-builtins
|
11
|
+
if (props.hasOwnProperty(funcName) && typeof (props[funcName]) === 'function') {
|
12
|
+
props[funcName](...args);
|
13
|
+
}
|
14
|
+
};
|
15
|
+
|
16
|
+
const onChange = () => {
|
17
|
+
const {onChange} = props;
|
18
|
+
if (onChange && typeof onChange === 'function') {
|
19
|
+
const schema = {
|
20
|
+
...builderRef.current.instance.form
|
21
|
+
};
|
22
|
+
|
23
|
+
Object.defineProperty(schema, 'components', {
|
24
|
+
get: function() {
|
25
|
+
return builderRef.current.instance.schema.components;
|
26
|
+
}
|
27
|
+
});
|
28
|
+
|
29
|
+
onChange(builderRef.current.instance.form, schema);
|
30
|
+
}
|
31
|
+
};
|
32
|
+
|
33
|
+
const builderEvents = [
|
34
|
+
{name: 'saveComponent', action: emit('onSaveComponent')},
|
35
|
+
{name: 'updateComponent', action: emit('onUpdateComponent')},
|
36
|
+
{name: 'removeComponent', action: emit('onDeleteComponent')},
|
37
|
+
{name: 'cancelComponent', action: emit('onUpdateComponent')},
|
38
|
+
{name: 'editComponent', action: emit('onEditComponent')},
|
39
|
+
{name: 'addComponent', action: onChange},
|
40
|
+
{name: 'saveComponent', action: onChange},
|
41
|
+
{name: 'updateComponent', action: onChange},
|
42
|
+
{name: 'removeComponent', action: onChange},
|
43
|
+
{name: 'deleteComponent', action: onChange},
|
44
|
+
{name: 'pdfUploaded', action: onChange},
|
45
|
+
];
|
46
|
+
|
47
|
+
const initializeBuilder = (builderProps) => {
|
48
|
+
let {options, form} = builderProps;
|
49
|
+
const {Builder} = builderProps;
|
50
|
+
options = Object.assign({}, options);
|
51
|
+
form = Object.assign({}, form);
|
52
|
+
|
53
|
+
builderRef.current = new Builder(element, form, options);
|
54
|
+
|
55
|
+
builderRef.current.ready.then(() => {
|
56
|
+
onChange();
|
57
|
+
builderEvents.forEach(({name, action}) => {
|
58
|
+
builderRef.current.instance.off(name, action);
|
59
|
+
builderRef.current.instance.on(name, action);
|
60
|
+
});
|
61
|
+
});
|
62
|
+
};
|
63
|
+
|
64
|
+
useEffect(() => {
|
65
|
+
initializeBuilder(props);
|
66
|
+
return () => (builderRef.current ? builderRef.current.instance.destroy(true) : null);
|
67
|
+
}, [builderRef]);
|
68
|
+
|
69
|
+
useEffect(() => {
|
70
|
+
if (!builderRef.current && props.form) {
|
71
|
+
initializeBuilder(props);
|
72
|
+
}
|
73
|
+
}, [props.form, builderRef]);
|
74
|
+
|
75
|
+
const elementDidMount = useCallback((el) => element = el);
|
76
|
+
|
77
|
+
useLayoutEffect(() => {
|
78
|
+
if (builderRef.current && props.form && props.form.display) {
|
79
|
+
builderRef.current.setDisplay(props.form.display);
|
80
|
+
}
|
81
|
+
}, [props.form.display]);
|
82
|
+
|
83
|
+
useLayoutEffect(() => {
|
84
|
+
if (builderRef.current && props.form && props.form.components) {
|
85
|
+
builderRef.current.setForm(props.form);
|
86
|
+
}
|
87
|
+
}, [props.form]);
|
88
|
+
|
89
|
+
return (
|
90
|
+
<div>
|
91
|
+
<div ref={elementDidMount}></div>
|
92
|
+
</div>
|
93
|
+
);
|
94
|
+
};
|
95
|
+
|
96
|
+
FormBuilder.defaultProps = {
|
97
|
+
options: {},
|
98
|
+
Builder: FormioFormBuilder
|
99
|
+
};
|
100
|
+
|
101
|
+
FormBuilder.propTypes = {
|
102
|
+
form: PropTypes.object,
|
103
|
+
options: PropTypes.object,
|
104
|
+
onChange: PropTypes.func,
|
105
|
+
onSaveComponent: PropTypes.func,
|
106
|
+
onUpdateComponent: PropTypes.func,
|
107
|
+
onDeleteComponent: PropTypes.func,
|
108
|
+
onCancelComponent: PropTypes.func,
|
109
|
+
onEditComponent: PropTypes.func,
|
110
|
+
Builder: PropTypes.any
|
111
|
+
};
|
112
|
+
|
113
|
+
export default FormBuilder;
|
@@ -0,0 +1,175 @@
|
|
1
|
+
import React, {useEffect, useReducer} from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import FormBuilder from './FormBuilder';
|
4
|
+
import _set from 'lodash/set';
|
5
|
+
import _cloneDeep from 'lodash/cloneDeep';
|
6
|
+
import _camelCase from 'lodash/camelCase';
|
7
|
+
|
8
|
+
const reducer = (form, {type, value}) => {
|
9
|
+
const formCopy = _cloneDeep(form);
|
10
|
+
switch (type) {
|
11
|
+
case 'formChange':
|
12
|
+
for (let prop in value) {
|
13
|
+
// eslint-disable-next-line no-prototype-builtins
|
14
|
+
if (value.hasOwnProperty(prop)) {
|
15
|
+
form[prop] = value[prop];
|
16
|
+
}
|
17
|
+
}
|
18
|
+
return form;
|
19
|
+
case 'replaceForm':
|
20
|
+
return _cloneDeep(value);
|
21
|
+
case 'title':
|
22
|
+
if (type === 'title' && !form._id) {
|
23
|
+
formCopy.name = _camelCase(value);
|
24
|
+
formCopy.path = _camelCase(value).toLowerCase();
|
25
|
+
}
|
26
|
+
break;
|
27
|
+
}
|
28
|
+
_set(formCopy, type, value);
|
29
|
+
return formCopy;
|
30
|
+
};
|
31
|
+
|
32
|
+
const FormEdit = (props) => {
|
33
|
+
const [form, dispatchFormAction] = useReducer(reducer, _cloneDeep(props.form));
|
34
|
+
useEffect(() => {
|
35
|
+
const {form: newForm} = props;
|
36
|
+
if (newForm && (form._id !== newForm._id || form.modified !== newForm.modified)) {
|
37
|
+
dispatchFormAction({type: 'replaceForm', value: newForm});
|
38
|
+
}
|
39
|
+
}, [props.form]);
|
40
|
+
|
41
|
+
const saveForm = () => {
|
42
|
+
const {saveForm} = props;
|
43
|
+
if (saveForm && typeof saveForm === 'function') {
|
44
|
+
saveForm(form);
|
45
|
+
}
|
46
|
+
};
|
47
|
+
|
48
|
+
const handleChange = (path, event) => {
|
49
|
+
const {target} = event;
|
50
|
+
const value = target.type === 'checkbox' ? target.checked : target.value;
|
51
|
+
dispatchFormAction({type: path, value});
|
52
|
+
};
|
53
|
+
|
54
|
+
const formChange = (newForm) => dispatchFormAction({type: 'formChange', value: newForm});
|
55
|
+
|
56
|
+
const {saveText, options, builder, ref} = props;
|
57
|
+
|
58
|
+
return (
|
59
|
+
<div>
|
60
|
+
<div className="row" ref={ref}>
|
61
|
+
<div className="col-lg-2 col-md-4 col-sm-4">
|
62
|
+
<div id="form-group-title" className="form-group">
|
63
|
+
<label htmlFor="title" className="control-label field-required">Title</label>
|
64
|
+
<input
|
65
|
+
type="text"
|
66
|
+
className="form-control" id="title"
|
67
|
+
placeholder="Enter the form title"
|
68
|
+
value={form.title || ''}
|
69
|
+
onChange={event => handleChange('title', event)}
|
70
|
+
/>
|
71
|
+
</div>
|
72
|
+
</div>
|
73
|
+
<div className="col-lg-2 col-md-4 col-sm-4">
|
74
|
+
<div id="form-group-name" className="form-group">
|
75
|
+
<label htmlFor="name" className="control-label field-required">Name</label>
|
76
|
+
<input
|
77
|
+
type="text"
|
78
|
+
className="form-control"
|
79
|
+
id="name"
|
80
|
+
placeholder="Enter the form machine name"
|
81
|
+
value={form.name || ''}
|
82
|
+
onChange={event => handleChange('name', event)}
|
83
|
+
/>
|
84
|
+
</div>
|
85
|
+
</div>
|
86
|
+
<div className="col-lg-2 col-md-3 col-sm-3">
|
87
|
+
<div id="form-group-display" className="form-group">
|
88
|
+
<label htmlFor="name" className="control-label">Display as</label>
|
89
|
+
<div className="input-group">
|
90
|
+
<select
|
91
|
+
className="form-control"
|
92
|
+
name="form-display"
|
93
|
+
id="form-display"
|
94
|
+
value={form.display || ''}
|
95
|
+
onChange={event => handleChange('display', event)}
|
96
|
+
>
|
97
|
+
<option label="Form" value="form">Form</option>
|
98
|
+
<option label="Wizard" value="wizard">Wizard</option>
|
99
|
+
<option label="PDF" value="pdf">PDF</option>
|
100
|
+
</select>
|
101
|
+
</div>
|
102
|
+
</div>
|
103
|
+
</div>
|
104
|
+
<div className="col-lg-2 col-md-3 col-sm-3">
|
105
|
+
<div id="form-group-type" className="form-group">
|
106
|
+
<label htmlFor="form-type" className="control-label">Type</label>
|
107
|
+
<div className="input-group">
|
108
|
+
<select
|
109
|
+
className="form-control"
|
110
|
+
name="form-type"
|
111
|
+
id="form-type"
|
112
|
+
value={form.type}
|
113
|
+
onChange={event => handleChange('type', event)}
|
114
|
+
>
|
115
|
+
<option label="Form" value="form">Form</option>
|
116
|
+
<option label="Resource" value="resource">Resource</option>
|
117
|
+
</select>
|
118
|
+
</div>
|
119
|
+
</div>
|
120
|
+
</div>
|
121
|
+
<div className="col-lg-2 col-md-4 col-sm-4">
|
122
|
+
<div id="form-group-path" className="form-group">
|
123
|
+
<label htmlFor="path" className="control-label field-required">Path</label>
|
124
|
+
<div className="input-group">
|
125
|
+
<input
|
126
|
+
type="text"
|
127
|
+
className="form-control"
|
128
|
+
id="path"
|
129
|
+
placeholder="example"
|
130
|
+
style={{'textTransform': 'lowercase', width:'120px'}}
|
131
|
+
value={form.path || ''}
|
132
|
+
onChange={event => handleChange('path', event)}
|
133
|
+
/>
|
134
|
+
</div>
|
135
|
+
</div>
|
136
|
+
</div>
|
137
|
+
<div id="save-buttons" className="col-lg-2 col-md-5 col-sm-5 save-buttons pull-right">
|
138
|
+
<div className="form-group pull-right">
|
139
|
+
<span className="btn btn-primary" onClick={() => saveForm()}>
|
140
|
+
{saveText}
|
141
|
+
</span>
|
142
|
+
</div>
|
143
|
+
</div>
|
144
|
+
</div>
|
145
|
+
<FormBuilder
|
146
|
+
key={form._id}
|
147
|
+
form={form}
|
148
|
+
options={options}
|
149
|
+
builder={builder}
|
150
|
+
onChange={formChange}
|
151
|
+
/>
|
152
|
+
</div>
|
153
|
+
);
|
154
|
+
};
|
155
|
+
|
156
|
+
FormEdit.propTypes = {
|
157
|
+
form: PropTypes.object.isRequired,
|
158
|
+
options: PropTypes.object,
|
159
|
+
builder: PropTypes.any,
|
160
|
+
saveForm: PropTypes.func,
|
161
|
+
saveText: PropTypes.string
|
162
|
+
};
|
163
|
+
|
164
|
+
FormEdit.defaultProps = {
|
165
|
+
form: {
|
166
|
+
title: '',
|
167
|
+
name: '',
|
168
|
+
path: '',
|
169
|
+
display: 'form',
|
170
|
+
type: 'form',
|
171
|
+
components: [],
|
172
|
+
}
|
173
|
+
};
|
174
|
+
|
175
|
+
export default FormEdit;
|