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.

Files changed (67) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +320 -3
  3. package/dist/18.jpg +0 -0
  4. package/dist/321.jpg +0 -0
  5. package/dist/6D975C71-92D2-E103-31BF-FC594DC8E7D9.jpg +0 -0
  6. package/dist/87.gif +0 -0
  7. package/dist/91.jpg +0 -0
  8. package/dist/92.jpg +0 -0
  9. package/dist/CACE99F6-C369-E5A6-6C91-F7199A63745C.jpg +0 -0
  10. package/dist/FE65CD08-1437-5D3E-014F-05DE91582606.jpg +0 -0
  11. package/dist/bundle.js +7 -0
  12. package/package.json +87 -3
  13. package/src/components/Errors.jsx +86 -0
  14. package/src/components/Form.jsx +179 -0
  15. package/src/components/FormBuilder.jsx +113 -0
  16. package/src/components/FormEdit.jsx +175 -0
  17. package/src/components/FormGrid.jsx +269 -0
  18. package/src/components/Grid.jsx +278 -0
  19. package/src/components/Pagination.jsx +148 -0
  20. package/src/components/ReactComponent.jsx +189 -0
  21. package/src/components/SubmissionGrid.jsx +249 -0
  22. package/src/components/index.js +9 -0
  23. package/src/constants.js +3 -0
  24. package/src/index.js +19 -0
  25. package/src/modules/auth/actions.js +115 -0
  26. package/src/modules/auth/constants.js +8 -0
  27. package/src/modules/auth/index.js +4 -0
  28. package/src/modules/auth/reducers.js +87 -0
  29. package/src/modules/auth/selectors.js +2 -0
  30. package/src/modules/form/actions.js +102 -0
  31. package/src/modules/form/constants.js +6 -0
  32. package/src/modules/form/index.js +4 -0
  33. package/src/modules/form/reducers.js +60 -0
  34. package/src/modules/form/selectors.js +3 -0
  35. package/src/modules/forms/actions.js +81 -0
  36. package/src/modules/forms/constants.js +4 -0
  37. package/src/modules/forms/index.js +4 -0
  38. package/src/modules/forms/reducers.js +77 -0
  39. package/src/modules/forms/selectors.js +3 -0
  40. package/src/modules/index.js +6 -0
  41. package/src/modules/root/Shark-1.0.0.0802.apk +0 -0
  42. package/src/modules/root/index.js +1 -0
  43. package/src/modules/root/selectors.js +3 -0
  44. package/src/modules/submission/actions.js +94 -0
  45. package/src/modules/submission/constants.js +6 -0
  46. package/src/modules/submission/index.js +4 -0
  47. package/src/modules/submission/reducers.js +64 -0
  48. package/src/modules/submission/selectors.js +3 -0
  49. package/src/modules/submissions/actions.js +82 -0
  50. package/src/modules/submissions/constants.js +4 -0
  51. package/src/modules/submissions/index.js +4 -0
  52. package/src/modules/submissions/reducers.js +79 -0
  53. package/src/modules/submissions/selectors.js +3 -0
  54. package/src/types.js +89 -0
  55. package/src/utils.js +56 -0
  56. package/test/.eslintrc +10 -0
  57. package/test/changes.spec.js +515 -0
  58. package/test/enzyme.js +6 -0
  59. package/test/fixtures/columns.json +80 -0
  60. package/test/fixtures/formWithInput.js +11 -0
  61. package/test/fixtures/index.js +5 -0
  62. package/test/fixtures/layout.json +73 -0
  63. package/test/fixtures/textField.json +30 -0
  64. package/test/fixtures/visible.json +57 -0
  65. package/test/index.js +2 -0
  66. package/test/utils.js +87 -0
  67. package/test/validation.spec.js +130 -0
@@ -0,0 +1,269 @@
1
+ import _get from 'lodash/get';
2
+ import _isFunction from 'lodash/isFunction';
3
+ import _isString from 'lodash/isString';
4
+ import PropTypes from 'prop-types';
5
+ import React from 'react';
6
+
7
+ import {defaultPageSizes} from '../constants';
8
+ import {
9
+ Columns,
10
+ Operations,
11
+ PageSizes,
12
+ } from '../types';
13
+ import {stopPropagationWrapper} from '../utils';
14
+
15
+ import Grid from './Grid';
16
+
17
+ const FormGrid = (props) => {
18
+ const getSortQuery = (key, sort) => {
19
+ const {
20
+ forms: {
21
+ sort: currentSort,
22
+ }
23
+ } = props;
24
+
25
+ const sortKey = _isString(sort) ? sort : key;
26
+ const ascSort = sortKey;
27
+ const descSort = `-${sortKey}`;
28
+ const noSort = '';
29
+
30
+ if (currentSort === ascSort) {
31
+ return descSort;
32
+ }
33
+ else if (currentSort === descSort) {
34
+ return noSort;
35
+ }
36
+ else {
37
+ return ascSort;
38
+ }
39
+ };
40
+
41
+ const onSort = ({key, sort}) => {
42
+ if (_isFunction(sort)) {
43
+ return sort();
44
+ }
45
+
46
+ const {getForms} = props;
47
+
48
+ getForms(1, {
49
+ sort: getSortQuery(key, sort),
50
+ });
51
+ };
52
+
53
+ const TitleCell = ({access, form, onAction}) => (
54
+ <span
55
+ style={{cursor: 'pointer'}}
56
+ onClick={stopPropagationWrapper(() => {
57
+ if (access.submission.create) {
58
+ onAction(form, 'view');
59
+ }
60
+ })}
61
+ >
62
+ <h5>{form.title}</h5>
63
+ </span>
64
+ );
65
+
66
+ const Icon = ({icon}) => (
67
+ <span>
68
+ <i className={`fa fa-${icon}`} />&nbsp;
69
+ </span>
70
+ );
71
+
72
+ const OperationButton = ({
73
+ action,
74
+ onAction,
75
+ form,
76
+ buttonType,
77
+ icon,
78
+ title
79
+ }) => (
80
+ <span
81
+ className={`btn btn-${buttonType} btn-sm form-btn`}
82
+ onClick={stopPropagationWrapper(() => onAction(form, action))}
83
+ >
84
+ {
85
+ icon
86
+ ? <Icon icon={icon} />
87
+ : null
88
+ }
89
+ {title}
90
+ </span>
91
+ );
92
+
93
+ const Cell = ({row: form, column}) => {
94
+ const {
95
+ formAccess,
96
+ onAction,
97
+ operations = [],
98
+ } = props;
99
+
100
+ const access = formAccess(form);
101
+
102
+ if (column.key === 'title') {
103
+ return <TitleCell access={access} form={form} onAction={onAction} />;
104
+ }
105
+ else if (column.key === 'operations') {
106
+ return (
107
+ <div>
108
+ {
109
+ operations.map(({
110
+ action,
111
+ buttonType = 'primary',
112
+ icon = '',
113
+ permissionsResolver = () => true,
114
+ title = '',
115
+ }) =>
116
+ permissionsResolver(form)
117
+ ? <OperationButton
118
+ key={action}
119
+ action={action}
120
+ buttonType={buttonType}
121
+ icon={icon}
122
+ title={title}
123
+ form={form}
124
+ onAction={onAction}
125
+ >
126
+ </OperationButton>
127
+ : null
128
+ )
129
+ }
130
+ </div>
131
+ );
132
+ }
133
+
134
+ return (
135
+ <span>
136
+ {
137
+ _isFunction(column.value)
138
+ ? column.value(form)
139
+ : _get(form, column.key, '')
140
+ }
141
+ </span>
142
+ );
143
+ };
144
+
145
+ const {
146
+ columns,
147
+ forms: {
148
+ forms,
149
+ limit,
150
+ pagination: {
151
+ page,
152
+ numPages,
153
+ total,
154
+ },
155
+ sort,
156
+ },
157
+ getForms,
158
+ onAction,
159
+ onPageSizeChanged,
160
+ pageSizes,
161
+ } = props;
162
+
163
+ const skip = (page - 1) * limit;
164
+ const last = Math.min(skip + limit, total);
165
+
166
+ return (
167
+ <Grid
168
+ Cell={Cell}
169
+ activePage={page}
170
+ columns={columns}
171
+ emptyText="No forms found"
172
+ firstItem={skip + 1}
173
+ items={forms}
174
+ lastItem={last}
175
+ onAction={onAction}
176
+ onPage={getForms}
177
+ onPageSizeChanged={onPageSizeChanged}
178
+ onSort={onSort}
179
+ pageSize={limit}
180
+ pageSizes={pageSizes}
181
+ pages={numPages}
182
+ sortOrder={sort}
183
+ total={total}
184
+ />
185
+ );
186
+ };
187
+
188
+ FormGrid.defaultProps = {
189
+ columns: [
190
+ {
191
+ key: 'title',
192
+ sort: true,
193
+ title: 'Form',
194
+ width: 8,
195
+ },
196
+ {
197
+ key: 'operations',
198
+ title: 'Operations',
199
+ width: 4,
200
+ },
201
+ ],
202
+ formAccess: () => ({
203
+ form: {
204
+ create: true,
205
+ view: true,
206
+ edit: true,
207
+ delete: true,
208
+ },
209
+ submission: {
210
+ create: true,
211
+ view: true,
212
+ edit: true,
213
+ delete: true,
214
+ },
215
+ }),
216
+ getForms: () => {},
217
+ onPageSizeChanged: () => {},
218
+ operations: [
219
+ {
220
+ action: 'view',
221
+ buttonType: 'primary',
222
+ icon: 'pencil',
223
+ permissionsResolver() {
224
+ return true;
225
+ },
226
+ title: 'Enter Data',
227
+ },
228
+ {
229
+ action: 'submission',
230
+ buttonType: 'warning',
231
+ icon: 'list-alt',
232
+ permissionsResolver() {
233
+ return true;
234
+ },
235
+ title: 'View Data',
236
+ },
237
+ {
238
+ action: 'edit',
239
+ buttonType: 'secondary',
240
+ icon: 'edit',
241
+ permissionsResolver() {
242
+ return true;
243
+ },
244
+ title: 'Edit Form',
245
+ },
246
+ {
247
+ action: 'delete',
248
+ buttonType: 'danger',
249
+ icon: 'trash',
250
+ permissionsResolver() {
251
+ return true;
252
+ },
253
+ },
254
+ ],
255
+ pageSizes: defaultPageSizes,
256
+ };
257
+
258
+ FormGrid.propTypes = {
259
+ columns: Columns,
260
+ formAccess: PropTypes.func,
261
+ forms: PropTypes.object.isRequired,
262
+ getForms: PropTypes.func,
263
+ onAction: PropTypes.func,
264
+ onPageSizeChanged: PropTypes.func,
265
+ operations: Operations,
266
+ pageSizes: PageSizes,
267
+ };
268
+
269
+ export default FormGrid;
@@ -0,0 +1,278 @@
1
+ import _get from 'lodash/get';
2
+ import _isObject from 'lodash/isObject';
3
+ import _isString from 'lodash/isString';
4
+ import PropTypes from 'prop-types';
5
+ import React from 'react';
6
+
7
+ import {defaultPageSizes} from '../constants';
8
+ import {AllItemsPerPage, PageSizes} from '../types';
9
+
10
+ import Pagination from './Pagination';
11
+
12
+ function normalizePageSize(pageSize) {
13
+ if (_isObject(pageSize)) {
14
+ return pageSize;
15
+ }
16
+
17
+ if (pageSize === AllItemsPerPage) {
18
+ return {
19
+ label: 'All',
20
+ value: 999999,
21
+ };
22
+ }
23
+
24
+ return {
25
+ label: pageSize,
26
+ value: pageSize,
27
+ };
28
+ }
29
+
30
+ const renderPagination = ({
31
+ pages,
32
+ onPage,
33
+ }) => pages && onPage;
34
+
35
+ const renderPageSizeSelector = ({
36
+ pageSize,
37
+ pageSizes,
38
+ onPageSizeChanged,
39
+ }) => pageSize && pageSizes && pageSizes.length && onPageSizeChanged;
40
+
41
+ const renderItemCounter = ({
42
+ firstItem,
43
+ lastItem,
44
+ total,
45
+ }) => firstItem && lastItem && total;
46
+
47
+ const renderFooter = (props) => renderPagination(props) || renderItemCounter(props);
48
+
49
+ function Grid(props) {
50
+ const {
51
+ Cell,
52
+ activePage,
53
+ columns,
54
+ emptyText,
55
+ firstItem,
56
+ items,
57
+ lastItem,
58
+ onAction,
59
+ onPage,
60
+ onPageSizeChanged,
61
+ onSort,
62
+ pageNeighbours,
63
+ pageSize,
64
+ pageSizes,
65
+ pages,
66
+ sortOrder,
67
+ total,
68
+ } = props;
69
+ const normalizedPageSizes = pageSizes.map(normalizePageSize);
70
+
71
+ const getColumn = (column) => {
72
+ const {
73
+ key,
74
+ sort = false,
75
+ title = '',
76
+ width,
77
+ } = column;
78
+ const className = `col col-md-${width}`;
79
+
80
+ const columnProps = {
81
+ key,
82
+ className,
83
+ };
84
+
85
+ if (!title) {
86
+ return (
87
+ <div {...columnProps} />
88
+ );
89
+ }
90
+
91
+ if (!sort) {
92
+ return (
93
+ <div {...columnProps}>
94
+ <strong>{title}</strong>
95
+ </div>
96
+ );
97
+ }
98
+
99
+ const sortKey = _isString(sort) ? sort : key;
100
+ const ascSort = sortKey;
101
+ const descSort = `-${sortKey}`;
102
+
103
+ let sortClass = '';
104
+ if (sortOrder === ascSort) {
105
+ sortClass = 'glyphicon glyphicon-triangle-top fa fa-caret-up';
106
+ }
107
+ else if (sortOrder === descSort) {
108
+ sortClass = 'glyphicon glyphicon-triangle-bottom fa fa-caret-down';
109
+ }
110
+
111
+ return (
112
+ <div {...columnProps}>
113
+ <span
114
+ style={{cursor: 'pointer'}}
115
+ onClick={() => onSort(column)}
116
+ >
117
+ <strong>{title} <span className={sortClass}/></strong>
118
+ </span>
119
+ </div>
120
+ );
121
+ };
122
+
123
+ const getItem = (item) => (
124
+ <li className="list-group-item" key={item._id}>
125
+ <div className="row" onClick={() => onAction(item, 'row')}>
126
+ {
127
+ columns.map((column) => (
128
+ <div key={column.key} className={`col col-md-${column.width}`}>
129
+ <Cell row={item} column={column} />
130
+ </div>
131
+ ))
132
+ }
133
+ </div>
134
+ </li>
135
+ );
136
+
137
+ const PageSizeSelector = () => (
138
+ <div className="col-auto">
139
+ <div className="row align-items-center">
140
+ <div className="col-auto">
141
+ <select
142
+ className="form-control"
143
+ value={pageSize}
144
+ onChange={(event) => onPageSizeChanged(event.target.value)}
145
+ >
146
+ {
147
+ normalizedPageSizes.map(({
148
+ label,
149
+ value,
150
+ }) => (
151
+ <option key={value} value={value}>{label}</option>
152
+ ))
153
+ }
154
+ </select>
155
+ </div>
156
+ <span className="col-auto">
157
+ items per page
158
+ </span>
159
+ </div>
160
+ </div>
161
+ );
162
+
163
+ const FooterPagination = () => (
164
+ <div className="col-auto">
165
+ <div className="row align-items-center">
166
+ <div className="col-auto">
167
+ <Pagination
168
+ pages={pages}
169
+ activePage={activePage}
170
+ pageNeighbours={pageNeighbours}
171
+ prev="Previous"
172
+ next="Next"
173
+ onSelect={onPage}
174
+ />
175
+ </div>
176
+ {
177
+ renderPageSizeSelector(props)
178
+ ? <PageSizeSelector></PageSizeSelector>
179
+ : null
180
+ }
181
+ </div>
182
+ </div>
183
+ );
184
+
185
+ const ItemCounter = () => (
186
+ <div className="col-auto ml-auto">
187
+ <span className="item-counter pull-right">
188
+ <span className="page-num">{ firstItem } - { lastItem }</span> / { total } total
189
+ </span>
190
+ </div>
191
+ );
192
+
193
+ const Footer = () => (
194
+ <li className="list-group-item">
195
+ <div className="row align-items-center">
196
+ {
197
+ renderPagination(props)
198
+ ? <FooterPagination></FooterPagination>
199
+ : null
200
+ }
201
+ {
202
+ renderItemCounter(props)
203
+ ? <ItemCounter></ItemCounter>
204
+ : null
205
+ }
206
+ </div>
207
+ </li>
208
+ );
209
+
210
+ return (
211
+ <div>
212
+ {
213
+ items.length
214
+ ? (
215
+ <ul className="list-group list-group-striped">
216
+ <li className="list-group-item list-group-header hidden-xs hidden-md">
217
+ <div className="row">
218
+ {columns.map(getColumn)}
219
+ </div>
220
+ </li>
221
+ {items.map(getItem)}
222
+ {
223
+ renderFooter(props)
224
+ ? <Footer></Footer>
225
+ : null
226
+ }
227
+ </ul>
228
+ )
229
+ : <div>{emptyText}</div>
230
+ }
231
+ </div>
232
+ );
233
+ }
234
+
235
+ Grid.propTypes = {
236
+ Cell: PropTypes.func,
237
+ activePage: PropTypes.number,
238
+ columns: PropTypes.array.isRequired,
239
+ emptyText: PropTypes.string,
240
+ firstItem: PropTypes.number,
241
+ items: PropTypes.array.isRequired,
242
+ lastItem: PropTypes.number,
243
+ onAction: PropTypes.func,
244
+ onPage: PropTypes.func,
245
+ onPageSizeChanged: PropTypes.func,
246
+ onSort: PropTypes.func,
247
+ pageNeighbours: PropTypes.number,
248
+ pageSize: PropTypes.number,
249
+ pageSizes: PageSizes,
250
+ pages: PropTypes.number,
251
+ sortOrder: PropTypes.string,
252
+ total: PropTypes.number,
253
+ };
254
+
255
+ Grid.defaultProps = {
256
+ Cell: ({
257
+ column,
258
+ row,
259
+ }) => (
260
+ <span>{_get(row, column.key, '')}</span>
261
+ ),
262
+ activePage: 1,
263
+ emptyText: 'No data found',
264
+ firstItem: 0,
265
+ lastItem: 0,
266
+ onAction: () => {},
267
+ onPage: () => {},
268
+ onPageSizeChanged: () => {},
269
+ onSort: () => {},
270
+ pageNeighbours: 1,
271
+ pageSize: 0,
272
+ pageSizes: defaultPageSizes,
273
+ pages: 0,
274
+ sortOrder: '',
275
+ total: 0,
276
+ };
277
+
278
+ export default Grid;
@@ -0,0 +1,148 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+
4
+ const LEFT_PAGE = 'LEFT';
5
+ const RIGHT_PAGE = 'RIGHT';
6
+
7
+ function range(from, to, step = 1) {
8
+ let i = from;
9
+ const range = [];
10
+
11
+ while (i <= to) {
12
+ range.push(i);
13
+ i += step;
14
+ }
15
+
16
+ return range;
17
+ }
18
+
19
+ function getPageNumbers({
20
+ currentPage,
21
+ pageNeighbours,
22
+ totalPages,
23
+ }) {
24
+ const totalNumbers = (pageNeighbours * 2) + 3;
25
+ const totalBlocks = totalNumbers + 2;
26
+
27
+ if (totalPages > totalBlocks) {
28
+ const calculatedStartPage = Math.max(2, currentPage - pageNeighbours);
29
+ const calculatedEndPage = Math.min(totalPages - 1, currentPage + pageNeighbours);
30
+ const startPage = (calculatedStartPage === 3) ? 2 : calculatedStartPage;
31
+ const endPage = (calculatedEndPage === (totalPages - 2)) ? (totalPages - 1) : calculatedEndPage;
32
+
33
+ let pages = range(startPage, endPage);
34
+
35
+ const hasLeftSpill = startPage > 2;
36
+ const hasRightSpill = (totalPages - endPage) > 1;
37
+ const spillOffset = totalNumbers - (pages.length + 1);
38
+ let extraPages;
39
+
40
+ if (hasLeftSpill && !hasRightSpill) {
41
+ extraPages = range(startPage - spillOffset, startPage - 1);
42
+ pages = [LEFT_PAGE, ...extraPages, ...pages];
43
+ }
44
+ else if (!hasLeftSpill && hasRightSpill) {
45
+ extraPages = range(endPage + 1, endPage + spillOffset);
46
+ pages = [...pages, ...extraPages, RIGHT_PAGE];
47
+ }
48
+ else {
49
+ pages = [LEFT_PAGE, ...pages, RIGHT_PAGE];
50
+ }
51
+
52
+ return [1, ...pages, totalPages];
53
+ }
54
+
55
+ return range(1, totalPages);
56
+ }
57
+
58
+ function Pagination({
59
+ activePage,
60
+ pageNeighbours,
61
+ pages,
62
+ prev,
63
+ next,
64
+ onSelect,
65
+ }) {
66
+ const pageNumbers = getPageNumbers({
67
+ currentPage: activePage,
68
+ pageNeighbours,
69
+ totalPages: pages,
70
+ });
71
+
72
+ return (
73
+ <nav aria-label="Page navigation">
74
+ <ul className="pagination">
75
+ <li className={`page-item ${(activePage === 1) ? 'disabled' : ''}`}>
76
+ <button
77
+ className="page-link"
78
+ onClick={() => {
79
+ if (activePage !== 1) {
80
+ onSelect(activePage - 1);
81
+ }
82
+ }}
83
+ >
84
+ {prev}
85
+ </button>
86
+ </li>
87
+
88
+ {
89
+ pageNumbers.map((page) => {
90
+ const className = (page === activePage) ? 'active' : '';
91
+
92
+ if ([LEFT_PAGE, RIGHT_PAGE].includes(page)) {
93
+ return (
94
+ <li className="page-item disabled">
95
+ <span className="page-link">
96
+ <span aria-hidden="true">...</span>
97
+ </span>
98
+ </li>
99
+ );
100
+ }
101
+
102
+ return (
103
+ <li className={`page-item ${className}`} key={page}>
104
+ <button
105
+ className="page-link"
106
+ onClick={() => onSelect(page)}
107
+ >
108
+ {page}
109
+ </button>
110
+ </li>
111
+ );
112
+ })
113
+ }
114
+
115
+ <li className={`page-item ${(activePage === pages) ? 'disabled' : ''}`}>
116
+ <button
117
+ className="page-link"
118
+ onClick={() => {
119
+ if (activePage !== pages) {
120
+ onSelect(activePage + 1);
121
+ }
122
+ }}
123
+ >
124
+ {next}
125
+ </button>
126
+ </li>
127
+ </ul>
128
+ </nav>
129
+ );
130
+ }
131
+
132
+ Pagination.propTypes = {
133
+ activePage: PropTypes.number,
134
+ pageNeighbours: PropTypes.number,
135
+ pages: PropTypes.number.isRequired,
136
+ prev: PropTypes.string,
137
+ next: PropTypes.string,
138
+ onSelect: PropTypes.func.isRequired,
139
+ };
140
+
141
+ Pagination.defaultProps = {
142
+ activePage: 1,
143
+ pageNeighbours: 1,
144
+ prev: 'Previous',
145
+ next: 'Next',
146
+ };
147
+
148
+ export default Pagination;