@oneblink/apps-react 6.9.0-beta.2 → 6.9.0-beta.3
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/dist/OneBlinkFormBase.js +6 -10
- package/dist/OneBlinkFormBase.js.map +1 -1
- package/dist/components/ValidationErrorsCard.d.ts +9 -0
- package/dist/components/ValidationErrorsCard.js +178 -0
- package/dist/components/ValidationErrorsCard.js.map +1 -0
- package/dist/components/ValidationErrorsCard_framer.d.ts +10 -0
- package/dist/components/ValidationErrorsCard_framer.js +218 -0
- package/dist/components/ValidationErrorsCard_framer.js.map +1 -0
- package/dist/styles/validation-errors-card.scss +186 -0
- package/dist/styles.css +172 -0
- package/dist/styles.scss +1 -0
- package/package.json +1 -1
@@ -0,0 +1,178 @@
|
|
1
|
+
import { IconButton, Collapse, Tooltip } from '@mui/material';
|
2
|
+
import * as React from 'react';
|
3
|
+
import MaterialIcon from './MaterialIcon';
|
4
|
+
import useBooleanState from '../hooks/useBooleanState';
|
5
|
+
import clsx from 'clsx';
|
6
|
+
import useFormDefinition from '../hooks/useFormDefinition';
|
7
|
+
const NO_PAGE_KEY = 'NO_PAGE';
|
8
|
+
const getValidationErrors = ({ formElementsValidation, elements, page, idPrefix, }) => {
|
9
|
+
return elements.reduce((memo, el) => {
|
10
|
+
switch (el.type) {
|
11
|
+
case 'page': {
|
12
|
+
memo.push(...getValidationErrors({
|
13
|
+
formElementsValidation,
|
14
|
+
elements: el.elements,
|
15
|
+
page: el,
|
16
|
+
idPrefix,
|
17
|
+
}));
|
18
|
+
break;
|
19
|
+
}
|
20
|
+
case 'section': {
|
21
|
+
memo.push(...getValidationErrors({
|
22
|
+
formElementsValidation,
|
23
|
+
elements: el.elements,
|
24
|
+
page,
|
25
|
+
idPrefix,
|
26
|
+
}));
|
27
|
+
break;
|
28
|
+
}
|
29
|
+
case 'repeatableSet': {
|
30
|
+
const validationData = formElementsValidation[el.name];
|
31
|
+
if (!!validationData &&
|
32
|
+
typeof validationData !== 'string' &&
|
33
|
+
validationData.type === 'repeatableSet') {
|
34
|
+
if (validationData.set) {
|
35
|
+
memo.push({
|
36
|
+
id: `${idPrefix}${el.name}-label`,
|
37
|
+
errorMessage: validationData.set,
|
38
|
+
label: el.label,
|
39
|
+
page,
|
40
|
+
});
|
41
|
+
}
|
42
|
+
for (const [key, entry] of Object.entries(validationData.entries)) {
|
43
|
+
if (!entry)
|
44
|
+
continue;
|
45
|
+
memo.push(...getValidationErrors({
|
46
|
+
formElementsValidation: entry,
|
47
|
+
elements: el.elements,
|
48
|
+
page,
|
49
|
+
idPrefix: `${idPrefix}${el.name}_entry-${key}_`,
|
50
|
+
}));
|
51
|
+
}
|
52
|
+
}
|
53
|
+
break;
|
54
|
+
}
|
55
|
+
case 'infoPage':
|
56
|
+
case 'form': {
|
57
|
+
const validationData = formElementsValidation[el.name];
|
58
|
+
if (!!validationData &&
|
59
|
+
typeof validationData !== 'string' &&
|
60
|
+
validationData.type === 'formElements') {
|
61
|
+
if (validationData.formElements && el.elements) {
|
62
|
+
memo.push(...getValidationErrors({
|
63
|
+
formElementsValidation: validationData.formElements,
|
64
|
+
elements: el.elements,
|
65
|
+
page,
|
66
|
+
idPrefix: `${idPrefix}${el.name}_`,
|
67
|
+
}));
|
68
|
+
}
|
69
|
+
}
|
70
|
+
break;
|
71
|
+
}
|
72
|
+
default: {
|
73
|
+
const validationMessage = formElementsValidation[el.name];
|
74
|
+
if (typeof validationMessage === 'string') {
|
75
|
+
memo.push({
|
76
|
+
id: `${idPrefix}${el.name}`,
|
77
|
+
label: el.label,
|
78
|
+
page,
|
79
|
+
errorMessage: validationMessage,
|
80
|
+
});
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
return memo;
|
85
|
+
}, []);
|
86
|
+
};
|
87
|
+
const ValidationErrorsCard = ({ formElementsValidation, currentPage, setPageId, }) => {
|
88
|
+
const [isExpanded, expand, contract] = useBooleanState(false);
|
89
|
+
const form = useFormDefinition();
|
90
|
+
const pagesWithValidationErrors = React.useMemo(() => {
|
91
|
+
if (!formElementsValidation)
|
92
|
+
return [];
|
93
|
+
const flatErrors = getValidationErrors({
|
94
|
+
formElementsValidation,
|
95
|
+
elements: form.elements,
|
96
|
+
idPrefix: '',
|
97
|
+
});
|
98
|
+
// Organise into pages
|
99
|
+
const pages = new Map();
|
100
|
+
for (const error of flatErrors) {
|
101
|
+
if (error.page) {
|
102
|
+
// If error belongs to a page
|
103
|
+
const existingSetEntry = pages.get(error.page.id);
|
104
|
+
const errors = [...((existingSetEntry === null || existingSetEntry === void 0 ? void 0 : existingSetEntry.errors) || []), error];
|
105
|
+
const page = error.page;
|
106
|
+
pages.set(page.id, {
|
107
|
+
page,
|
108
|
+
errors,
|
109
|
+
});
|
110
|
+
}
|
111
|
+
else {
|
112
|
+
// No page associated with error
|
113
|
+
const existingSetEntry = pages.get(NO_PAGE_KEY);
|
114
|
+
const errors = [...((existingSetEntry === null || existingSetEntry === void 0 ? void 0 : existingSetEntry.errors) || []), error];
|
115
|
+
pages.set(NO_PAGE_KEY, {
|
116
|
+
page: undefined,
|
117
|
+
errors,
|
118
|
+
});
|
119
|
+
}
|
120
|
+
}
|
121
|
+
return Array.from(pages.values());
|
122
|
+
}, [form.elements, formElementsValidation]);
|
123
|
+
return (React.createElement("div", { className: "ob-validation-notification-wrapper" },
|
124
|
+
React.createElement("div", { className: clsx('ob-validation-notification-card cypress-invalid-submit-attempt', {
|
125
|
+
'is-clickable': !isExpanded,
|
126
|
+
'is-contracted': !isExpanded,
|
127
|
+
'is-expanded': isExpanded,
|
128
|
+
}), onClick: !isExpanded ? expand : undefined },
|
129
|
+
React.createElement("div", { className: "ob-validation-notification-card-content" },
|
130
|
+
React.createElement("div", { className: "ob-validation-notification-card-header-wrapper" },
|
131
|
+
React.createElement("div", { className: "ob-validation-notification-card-header-title-wrapper" },
|
132
|
+
React.createElement(MaterialIcon, { className: clsx('ob-validation-notification-card-header-title-icon ob-validation-color-transition', {
|
133
|
+
'has-text-danger': isExpanded,
|
134
|
+
'has-text-white': !isExpanded,
|
135
|
+
}) }, "error"),
|
136
|
+
React.createElement("p", { className: clsx('ob-validation-color-transition ob-validation-notification-card-header-title-text', {
|
137
|
+
'has-text-danger': isExpanded,
|
138
|
+
'has-text-white': !isExpanded,
|
139
|
+
}) }, "Validation Errors")),
|
140
|
+
React.createElement("div", { className: "ob-validation-notification-card-header-collapse-icon-wrapper" }, isExpanded ? (React.createElement(IconButton, { onClick: contract },
|
141
|
+
React.createElement(MaterialIcon, { className: "icon-small" }, "expand_more"))) : (React.createElement(IconButton, null,
|
142
|
+
React.createElement(MaterialIcon, { className: "icon-small has-text-white" }, "expand_less"))))),
|
143
|
+
React.createElement("div", { className: "ob-validation-notification-card-collapse-wrapper" },
|
144
|
+
React.createElement(Collapse, { in: isExpanded }, pagesWithValidationErrors.map(({ page, errors }, pageIndex) => {
|
145
|
+
const isNotFirstPage = pageIndex > 0;
|
146
|
+
return (React.createElement(React.Fragment, null,
|
147
|
+
page && (React.createElement("p", { className: clsx('ob-validation-notification-card-page-label ob-validation-color-transition', {
|
148
|
+
'is-not-first': isNotFirstPage,
|
149
|
+
}) }, page.label)),
|
150
|
+
React.createElement("div", { className: "ob-list has-dividers has-borders ob-validation-notification-card-list ob-validation-color-transition" }, errors.map(({ errorMessage, label, id }, index, list) => {
|
151
|
+
const isFirst = index === 0;
|
152
|
+
const isLast = index === list.length - 1;
|
153
|
+
return (React.createElement("div", { key: index, className: clsx('ob-list__item is-clickable ob-validation-notification-card-item', {
|
154
|
+
'is-first': isFirst,
|
155
|
+
'is-last': isLast,
|
156
|
+
}), onClick: () => {
|
157
|
+
if (page && page.id !== currentPage.id) {
|
158
|
+
setPageId(page.id);
|
159
|
+
}
|
160
|
+
const element = document.getElementById(id);
|
161
|
+
if (element) {
|
162
|
+
window.requestAnimationFrame(() => {
|
163
|
+
element.scrollIntoView({
|
164
|
+
behavior: 'smooth',
|
165
|
+
});
|
166
|
+
});
|
167
|
+
}
|
168
|
+
} },
|
169
|
+
React.createElement("div", { className: "ob-validation-notification-card-item-text" },
|
170
|
+
React.createElement("p", null, label),
|
171
|
+
React.createElement(Tooltip, { title: errorMessage, placement: "left", arrow: true },
|
172
|
+
React.createElement("p", { className: "ob-validation-notification-card-item-text-error-message has-text-danger" }, errorMessage))),
|
173
|
+
React.createElement(MaterialIcon, { className: "has-text-grey icon-small ob-validation-notification-card-item-icon" }, "chevron_right")));
|
174
|
+
}))));
|
175
|
+
})))))));
|
176
|
+
};
|
177
|
+
export default React.memo(ValidationErrorsCard);
|
178
|
+
//# sourceMappingURL=ValidationErrorsCard.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ValidationErrorsCard.js","sourceRoot":"","sources":["../../src/components/ValidationErrorsCard.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconButton, Collapse, Tooltip } from '@mui/material'\nimport * as React from 'react'\nimport MaterialIcon from './MaterialIcon'\nimport { FormElementsValidation } from '../types/form'\nimport useBooleanState from '../hooks/useBooleanState'\nimport clsx from 'clsx'\nimport useFormDefinition from '../hooks/useFormDefinition'\nimport { FormTypes } from '@oneblink/types'\n\nconst NO_PAGE_KEY = 'NO_PAGE'\ntype ValidationErrorMetaData = {\n id: string\n label: string\n page?: {\n label: string\n id: string\n }\n errorMessage: string\n}\nconst getValidationErrors = ({\n formElementsValidation,\n elements,\n page,\n idPrefix,\n}: {\n formElementsValidation: FormElementsValidation\n elements: FormTypes.FormElement[]\n page?: ValidationErrorMetaData['page']\n idPrefix: string\n}) => {\n return elements.reduce<Array<ValidationErrorMetaData>>((memo, el) => {\n switch (el.type) {\n case 'page': {\n memo.push(\n ...getValidationErrors({\n formElementsValidation,\n elements: el.elements,\n page: el,\n idPrefix,\n }),\n )\n break\n }\n case 'section': {\n memo.push(\n ...getValidationErrors({\n formElementsValidation,\n elements: el.elements,\n page,\n idPrefix,\n }),\n )\n break\n }\n case 'repeatableSet': {\n const validationData = formElementsValidation[el.name]\n if (\n !!validationData &&\n typeof validationData !== 'string' &&\n validationData.type === 'repeatableSet'\n ) {\n if (validationData.set) {\n memo.push({\n id: `${idPrefix}${el.name}-label`,\n errorMessage: validationData.set,\n label: el.label,\n page,\n })\n }\n for (const [key, entry] of Object.entries(validationData.entries)) {\n if (!entry) continue\n memo.push(\n ...getValidationErrors({\n formElementsValidation: entry,\n elements: el.elements,\n page,\n idPrefix: `${idPrefix}${el.name}_entry-${key}_`,\n }),\n )\n }\n }\n break\n }\n case 'infoPage':\n case 'form': {\n const validationData = formElementsValidation[el.name]\n if (\n !!validationData &&\n typeof validationData !== 'string' &&\n validationData.type === 'formElements'\n ) {\n if (validationData.formElements && el.elements) {\n memo.push(\n ...getValidationErrors({\n formElementsValidation: validationData.formElements,\n elements: el.elements,\n page,\n idPrefix: `${idPrefix}${el.name}_`,\n }),\n )\n }\n }\n break\n }\n default: {\n const validationMessage = formElementsValidation[el.name]\n if (typeof validationMessage === 'string') {\n memo.push({\n id: `${idPrefix}${el.name}`,\n label: el.label,\n page,\n errorMessage: validationMessage,\n })\n }\n }\n }\n return memo\n }, [])\n}\n\nconst ValidationErrorsCard = ({\n formElementsValidation,\n currentPage,\n setPageId,\n}: {\n formElementsValidation: FormElementsValidation | undefined\n currentPage: FormTypes.PageElement\n setPageId: (pageId: string) => void\n}) => {\n const [isExpanded, expand, contract] = useBooleanState(false)\n\n const form = useFormDefinition()\n\n const pagesWithValidationErrors = React.useMemo(() => {\n if (!formElementsValidation) return []\n const flatErrors = getValidationErrors({\n formElementsValidation,\n elements: form.elements,\n idPrefix: '',\n })\n\n // Organise into pages\n const pages = new Map<\n string,\n {\n page: ValidationErrorMetaData['page']\n errors: ValidationErrorMetaData[]\n }\n >()\n for (const error of flatErrors) {\n if (error.page) {\n // If error belongs to a page\n const existingSetEntry = pages.get(error.page.id)\n const errors = [...(existingSetEntry?.errors || []), error]\n const page = error.page\n\n pages.set(page.id, {\n page,\n errors,\n })\n } else {\n // No page associated with error\n const existingSetEntry = pages.get(NO_PAGE_KEY)\n const errors = [...(existingSetEntry?.errors || []), error]\n pages.set(NO_PAGE_KEY, {\n page: undefined,\n errors,\n })\n }\n }\n return Array.from(pages.values())\n }, [form.elements, formElementsValidation])\n\n return (\n <div className=\"ob-validation-notification-wrapper\">\n <div\n className={clsx(\n 'ob-validation-notification-card cypress-invalid-submit-attempt',\n {\n 'is-clickable': !isExpanded,\n 'is-contracted': !isExpanded,\n 'is-expanded': isExpanded,\n },\n )}\n onClick={!isExpanded ? expand : undefined}\n >\n <div className=\"ob-validation-notification-card-content\">\n <div className=\"ob-validation-notification-card-header-wrapper\">\n <div className=\"ob-validation-notification-card-header-title-wrapper\">\n <MaterialIcon\n className={clsx(\n 'ob-validation-notification-card-header-title-icon ob-validation-color-transition',\n {\n 'has-text-danger': isExpanded,\n 'has-text-white': !isExpanded,\n },\n )}\n >\n error\n </MaterialIcon>\n <p\n className={clsx(\n 'ob-validation-color-transition ob-validation-notification-card-header-title-text',\n {\n 'has-text-danger': isExpanded,\n 'has-text-white': !isExpanded,\n },\n )}\n >\n Validation Errors\n </p>\n </div>\n <div className=\"ob-validation-notification-card-header-collapse-icon-wrapper\">\n {isExpanded ? (\n <IconButton onClick={contract}>\n <MaterialIcon className=\"icon-small\">\n expand_more\n </MaterialIcon>\n </IconButton>\n ) : (\n <IconButton>\n <MaterialIcon className=\"icon-small has-text-white\">\n expand_less\n </MaterialIcon>\n </IconButton>\n )}\n </div>\n </div>\n <div className=\"ob-validation-notification-card-collapse-wrapper\">\n <Collapse in={isExpanded}>\n {pagesWithValidationErrors.map(({ page, errors }, pageIndex) => {\n const isNotFirstPage = pageIndex > 0\n return (\n <>\n {page && (\n <p\n className={clsx(\n 'ob-validation-notification-card-page-label ob-validation-color-transition',\n {\n 'is-not-first': isNotFirstPage,\n },\n )}\n >\n {page.label}\n </p>\n )}\n <div className=\"ob-list has-dividers has-borders ob-validation-notification-card-list ob-validation-color-transition\">\n {errors.map(\n ({ errorMessage, label, id }, index, list) => {\n const isFirst = index === 0\n const isLast = index === list.length - 1\n return (\n <div\n key={index}\n className={clsx(\n 'ob-list__item is-clickable ob-validation-notification-card-item',\n {\n 'is-first': isFirst,\n 'is-last': isLast,\n },\n )}\n onClick={() => {\n if (page && page.id !== currentPage.id) {\n setPageId(page.id)\n }\n const element = document.getElementById(id)\n if (element) {\n window.requestAnimationFrame(() => {\n element.scrollIntoView({\n behavior: 'smooth',\n })\n })\n }\n }}\n >\n <div className=\"ob-validation-notification-card-item-text\">\n <p>{label}</p>\n <Tooltip\n title={errorMessage}\n placement=\"left\"\n arrow\n >\n <p className=\"ob-validation-notification-card-item-text-error-message has-text-danger\">\n {errorMessage}\n </p>\n </Tooltip>\n </div>\n <MaterialIcon className=\"has-text-grey icon-small ob-validation-notification-card-item-icon\">\n chevron_right\n </MaterialIcon>\n </div>\n )\n },\n )}\n </div>\n </>\n )\n })}\n </Collapse>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default React.memo(ValidationErrorsCard)\n"]}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import { FormElementsValidation } from '../types/form';
|
3
|
+
import { FormTypes } from '@oneblink/types';
|
4
|
+
declare const _default: React.MemoExoticComponent<({ formElementsValidation, display, currentPage, setPageId, }: {
|
5
|
+
formElementsValidation: FormElementsValidation | undefined;
|
6
|
+
display: boolean;
|
7
|
+
currentPage: FormTypes.PageElement;
|
8
|
+
setPageId: (pageId: string) => void;
|
9
|
+
}) => React.JSX.Element | null>;
|
10
|
+
export default _default;
|
@@ -0,0 +1,218 @@
|
|
1
|
+
import { Box, Card, CardContent, Typography, Grid, IconButton, Collapse, styled, } from '@mui/material';
|
2
|
+
import * as React from 'react';
|
3
|
+
import MaterialIcon from './MaterialIcon';
|
4
|
+
import useBooleanState from '../hooks/useBooleanState';
|
5
|
+
import clsx from 'clsx';
|
6
|
+
import useFormDefinition from '../hooks/useFormDefinition';
|
7
|
+
const NO_PAGE_KEY = 'NO_PAGE';
|
8
|
+
const getValidationErrors = ({ formElementsValidation, elements, page, idPrefix, }) => {
|
9
|
+
return elements.reduce((memo, el) => {
|
10
|
+
switch (el.type) {
|
11
|
+
case 'page': {
|
12
|
+
memo.push(...getValidationErrors({
|
13
|
+
formElementsValidation,
|
14
|
+
elements: el.elements,
|
15
|
+
page: el,
|
16
|
+
idPrefix,
|
17
|
+
}));
|
18
|
+
break;
|
19
|
+
}
|
20
|
+
case 'section': {
|
21
|
+
memo.push(...getValidationErrors({
|
22
|
+
formElementsValidation,
|
23
|
+
elements: el.elements,
|
24
|
+
page,
|
25
|
+
idPrefix,
|
26
|
+
}));
|
27
|
+
break;
|
28
|
+
}
|
29
|
+
case 'repeatableSet': {
|
30
|
+
const validationData = formElementsValidation[el.name];
|
31
|
+
if (!!validationData &&
|
32
|
+
typeof validationData !== 'string' &&
|
33
|
+
validationData.type === 'repeatableSet') {
|
34
|
+
for (const [key, entry] of Object.entries(validationData.entries)) {
|
35
|
+
if (!entry)
|
36
|
+
continue;
|
37
|
+
memo.push(...getValidationErrors({
|
38
|
+
formElementsValidation: entry,
|
39
|
+
elements: el.elements,
|
40
|
+
page,
|
41
|
+
idPrefix: `${idPrefix}${el.name}_entry-${key}_`,
|
42
|
+
}));
|
43
|
+
}
|
44
|
+
}
|
45
|
+
break;
|
46
|
+
}
|
47
|
+
case 'infoPage':
|
48
|
+
case 'form': {
|
49
|
+
const validationData = formElementsValidation[el.name];
|
50
|
+
if (!!validationData &&
|
51
|
+
typeof validationData !== 'string' &&
|
52
|
+
validationData.type === 'formElements') {
|
53
|
+
validationData.formElements;
|
54
|
+
if (validationData.formElements && el.elements) {
|
55
|
+
memo.push(...getValidationErrors({
|
56
|
+
formElementsValidation: validationData.formElements,
|
57
|
+
elements: el.elements,
|
58
|
+
page,
|
59
|
+
idPrefix: `${idPrefix}${el.name}_`,
|
60
|
+
}));
|
61
|
+
}
|
62
|
+
}
|
63
|
+
break;
|
64
|
+
}
|
65
|
+
default: {
|
66
|
+
const validationMessage = formElementsValidation[el.name];
|
67
|
+
if (typeof validationMessage === 'string') {
|
68
|
+
memo.push({
|
69
|
+
id: `${idPrefix}${el.name}`,
|
70
|
+
label: el.label,
|
71
|
+
page,
|
72
|
+
errorMessage: validationMessage,
|
73
|
+
});
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
return memo;
|
78
|
+
}, []);
|
79
|
+
};
|
80
|
+
const PulsingCard = styled(Card)(() => {
|
81
|
+
return {
|
82
|
+
animation: 'pulse-animation 1.5s infinite',
|
83
|
+
'@keyframes pulse-animation': {
|
84
|
+
'0%': {
|
85
|
+
boxShadow: '0 0 0 0px rgba(255, 0, 0, 0.4)',
|
86
|
+
},
|
87
|
+
'99%': {
|
88
|
+
boxShadow: '0 0 0 16px rgba(255, 0, 0, 0.0)',
|
89
|
+
},
|
90
|
+
},
|
91
|
+
};
|
92
|
+
});
|
93
|
+
const ValidationErrorsCard = ({ formElementsValidation, display, currentPage, setPageId, }) => {
|
94
|
+
const [isExpanded, expand, contract] = useBooleanState(true);
|
95
|
+
const form = useFormDefinition();
|
96
|
+
const pagesWithValidationErrors = React.useMemo(() => {
|
97
|
+
if (!formElementsValidation)
|
98
|
+
return [];
|
99
|
+
const flatErrors = getValidationErrors({
|
100
|
+
formElementsValidation,
|
101
|
+
elements: form.elements,
|
102
|
+
idPrefix: '',
|
103
|
+
});
|
104
|
+
// Organise into pages
|
105
|
+
const pages = new Map();
|
106
|
+
for (const error of flatErrors) {
|
107
|
+
if (error.page) {
|
108
|
+
// If error belongs to a page
|
109
|
+
const existingSetEntry = pages.get(error.page.id);
|
110
|
+
const errors = [...((existingSetEntry === null || existingSetEntry === void 0 ? void 0 : existingSetEntry.errors) || []), error];
|
111
|
+
const page = error.page;
|
112
|
+
pages.set(page.id, {
|
113
|
+
page,
|
114
|
+
errors,
|
115
|
+
});
|
116
|
+
}
|
117
|
+
else {
|
118
|
+
// No page associated with error
|
119
|
+
const existingSetEntry = pages.get(NO_PAGE_KEY);
|
120
|
+
const errors = [...((existingSetEntry === null || existingSetEntry === void 0 ? void 0 : existingSetEntry.errors) || []), error];
|
121
|
+
pages.set(NO_PAGE_KEY, {
|
122
|
+
page: undefined,
|
123
|
+
errors,
|
124
|
+
});
|
125
|
+
}
|
126
|
+
}
|
127
|
+
return Array.from(pages.values());
|
128
|
+
}, [form.elements, formElementsValidation]);
|
129
|
+
if (!display)
|
130
|
+
return null;
|
131
|
+
return (React.createElement(Box, { sx: {
|
132
|
+
position: 'fixed',
|
133
|
+
bottom: 16,
|
134
|
+
right: 16,
|
135
|
+
zIndex: 10,
|
136
|
+
} },
|
137
|
+
React.createElement(PulsingCard, { isExpanded: isExpanded, elevation: !isExpanded ? 20 : 0, sx: (theme) => ({
|
138
|
+
transition: `${theme.transitions.duration.standard}ms ${theme.transitions.easing.easeInOut}`,
|
139
|
+
borderTopLeftRadius: 8,
|
140
|
+
borderTopRightRadius: 8,
|
141
|
+
borderBottomLeftRadius: 8,
|
142
|
+
borderBottomRightRadius: 8,
|
143
|
+
maxHeight: 350,
|
144
|
+
overflowY: 'auto',
|
145
|
+
borderColor: theme.palette.error.light,
|
146
|
+
borderWidth: 2,
|
147
|
+
borderStyle: 'solid',
|
148
|
+
backgroundColor: !isExpanded ? theme.palette.error.light : undefined,
|
149
|
+
color: !isExpanded ? theme.palette.error.contrastText : undefined,
|
150
|
+
}), className: !isExpanded ? 'is-clickable' : '', onClick: !isExpanded ? expand : undefined },
|
151
|
+
React.createElement(CardContent, { sx: (theme) => ({
|
152
|
+
transition: `${theme.transitions.duration.standard}ms ${theme.transitions.easing.easeInOut}`,
|
153
|
+
paddingBottom: !isExpanded ? `8px !important` : undefined,
|
154
|
+
paddingTop: !isExpanded ? `8px !important` : undefined,
|
155
|
+
}) },
|
156
|
+
React.createElement(Grid, { container: true, justifyContent: "space-between", alignItems: "center" },
|
157
|
+
React.createElement(Grid, { item: true, alignItems: "center", display: "flex" },
|
158
|
+
React.createElement(MaterialIcon, { className: clsx({
|
159
|
+
'has-text-danger': isExpanded,
|
160
|
+
'has-text-white': !isExpanded,
|
161
|
+
}), sx: { mr: 1, fontSize: 22 } }, "error"),
|
162
|
+
React.createElement(Typography, { className: clsx({
|
163
|
+
'has-text-danger': isExpanded,
|
164
|
+
'has-text-white': !isExpanded,
|
165
|
+
}), fontWeight: 600 }, "Validation Errors")),
|
166
|
+
React.createElement(Grid, { item: true }, isExpanded ? (React.createElement(IconButton, { onClick: contract },
|
167
|
+
React.createElement(MaterialIcon, { className: "icon-small" }, "expand_more"))) : (React.createElement(IconButton, { onClick: expand },
|
168
|
+
React.createElement(MaterialIcon, { className: "icon-small has-text-white" }, "expand_less"))))),
|
169
|
+
React.createElement(Box, { sx: (theme) => ({
|
170
|
+
transition: `width ${theme.transitions.duration.standard}ms ${theme.transitions.easing.easeInOut}`,
|
171
|
+
whiteSpace: 'nowrap',
|
172
|
+
width: isExpanded ? 300 : 194,
|
173
|
+
overflowX: 'hidden',
|
174
|
+
opacity: isExpanded ? 1 : 0,
|
175
|
+
}) },
|
176
|
+
React.createElement(Collapse, { in: isExpanded }, pagesWithValidationErrors.map(({ page, errors }, pageIndex) => {
|
177
|
+
const isNotFirstPage = pageIndex > 0;
|
178
|
+
return (React.createElement(React.Fragment, null,
|
179
|
+
isNotFirstPage && React.createElement(Box, { mt: 1 }),
|
180
|
+
page && (React.createElement(Typography, { variant: "body2", fontWeight: "600", color: "text.primary" }, page.label)),
|
181
|
+
React.createElement(Box, { mb: 1 }),
|
182
|
+
errors.map(({ errorMessage, label, id }, index, list) => {
|
183
|
+
const isFirst = index === 0;
|
184
|
+
const isLast = index === list.length - 1;
|
185
|
+
return (React.createElement(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", key: index, p: 1, sx: (theme) => ({
|
186
|
+
borderColor: theme.palette.divider,
|
187
|
+
borderWidth: 1,
|
188
|
+
borderStyle: 'solid',
|
189
|
+
borderTopLeftRadius: isFirst ? 8 : 0,
|
190
|
+
borderTopRightRadius: isFirst ? 8 : 0,
|
191
|
+
borderBottomWidth: isLast ? 1 : 0,
|
192
|
+
borderBottomLeftRadius: isLast ? 8 : 0,
|
193
|
+
borderBottomRightRadius: isLast ? 8 : 0,
|
194
|
+
}), className: "ob-list__item is-clickable", onClick: () => {
|
195
|
+
if (page && page.id !== currentPage.id) {
|
196
|
+
setPageId(page.id);
|
197
|
+
}
|
198
|
+
const element = document.getElementById(id);
|
199
|
+
if (element) {
|
200
|
+
window.requestAnimationFrame(() => {
|
201
|
+
element.scrollIntoView({
|
202
|
+
behavior: 'smooth',
|
203
|
+
});
|
204
|
+
});
|
205
|
+
}
|
206
|
+
} },
|
207
|
+
React.createElement(Box, { sx: { whitespace: 'nowrap' } },
|
208
|
+
React.createElement(Typography, { variant: "body2", color: "text.primary" }, label),
|
209
|
+
React.createElement(Typography, { variant: "body2", className: "has-text-danger", sx: {
|
210
|
+
whiteSpace: 'nowrap',
|
211
|
+
textOverflow: 'ellipsis',
|
212
|
+
} }, errorMessage)),
|
213
|
+
React.createElement(MaterialIcon, { className: "has-text-grey icon-small", sx: { ml: 1 } }, "chevron_right")));
|
214
|
+
})));
|
215
|
+
})))))));
|
216
|
+
};
|
217
|
+
export default React.memo(ValidationErrorsCard);
|
218
|
+
//# sourceMappingURL=ValidationErrorsCard_framer.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ValidationErrorsCard_framer.js","sourceRoot":"","sources":["../../src/components/ValidationErrorsCard_framer.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Box,\n Card,\n CardContent,\n Typography,\n Grid,\n IconButton,\n Collapse,\n styled,\n} from '@mui/material'\nimport * as React from 'react'\nimport MaterialIcon from './MaterialIcon'\nimport { FormElementsValidation } from '../types/form'\nimport useBooleanState from '../hooks/useBooleanState'\nimport clsx from 'clsx'\nimport useFormDefinition from '../hooks/useFormDefinition'\nimport { FormTypes } from '@oneblink/types'\n\nconst NO_PAGE_KEY = 'NO_PAGE'\n// const transitionLength = 3000\ntype ValidationErrorMetaData = {\n id: string\n label: string\n page?: {\n label: string\n id: string\n }\n errorMessage: string\n}\nconst getValidationErrors = ({\n formElementsValidation,\n elements,\n page,\n idPrefix,\n}: {\n formElementsValidation: FormElementsValidation\n elements: FormTypes.FormElement[]\n page?: ValidationErrorMetaData['page']\n idPrefix: string\n}) => {\n return elements.reduce<Array<ValidationErrorMetaData>>((memo, el) => {\n switch (el.type) {\n case 'page': {\n memo.push(\n ...getValidationErrors({\n formElementsValidation,\n elements: el.elements,\n page: el,\n idPrefix,\n }),\n )\n break\n }\n case 'section': {\n memo.push(\n ...getValidationErrors({\n formElementsValidation,\n elements: el.elements,\n page,\n idPrefix,\n }),\n )\n break\n }\n case 'repeatableSet': {\n const validationData = formElementsValidation[el.name]\n if (\n !!validationData &&\n typeof validationData !== 'string' &&\n validationData.type === 'repeatableSet'\n ) {\n for (const [key, entry] of Object.entries(validationData.entries)) {\n if (!entry) continue\n memo.push(\n ...getValidationErrors({\n formElementsValidation: entry,\n elements: el.elements,\n page,\n idPrefix: `${idPrefix}${el.name}_entry-${key}_`,\n }),\n )\n }\n }\n break\n }\n case 'infoPage':\n case 'form': {\n const validationData = formElementsValidation[el.name]\n if (\n !!validationData &&\n typeof validationData !== 'string' &&\n validationData.type === 'formElements'\n ) {\n validationData.formElements\n\n if (validationData.formElements && el.elements) {\n memo.push(\n ...getValidationErrors({\n formElementsValidation: validationData.formElements,\n elements: el.elements,\n page,\n idPrefix: `${idPrefix}${el.name}_`,\n }),\n )\n }\n }\n break\n }\n default: {\n const validationMessage = formElementsValidation[el.name]\n if (typeof validationMessage === 'string') {\n memo.push({\n id: `${idPrefix}${el.name}`,\n label: el.label,\n page,\n errorMessage: validationMessage,\n })\n }\n }\n }\n return memo\n }, [])\n}\n\nconst PulsingCard = styled(Card)<{ isExpanded: boolean }>(() => {\n return {\n animation: 'pulse-animation 1.5s infinite',\n '@keyframes pulse-animation': {\n '0%': {\n boxShadow: '0 0 0 0px rgba(255, 0, 0, 0.4)',\n },\n '99%': {\n boxShadow: '0 0 0 16px rgba(255, 0, 0, 0.0)',\n },\n },\n }\n})\nconst ValidationErrorsCard = ({\n formElementsValidation,\n display,\n currentPage,\n setPageId,\n}: {\n formElementsValidation: FormElementsValidation | undefined\n display: boolean\n currentPage: FormTypes.PageElement\n setPageId: (pageId: string) => void\n}) => {\n const [isExpanded, expand, contract] = useBooleanState(true)\n\n const form = useFormDefinition()\n\n const pagesWithValidationErrors = React.useMemo(() => {\n if (!formElementsValidation) return []\n const flatErrors = getValidationErrors({\n formElementsValidation,\n elements: form.elements,\n idPrefix: '',\n })\n\n // Organise into pages\n const pages = new Map<\n string,\n {\n page: ValidationErrorMetaData['page']\n errors: ValidationErrorMetaData[]\n }\n >()\n for (const error of flatErrors) {\n if (error.page) {\n // If error belongs to a page\n const existingSetEntry = pages.get(error.page.id)\n const errors = [...(existingSetEntry?.errors || []), error]\n const page = error.page\n\n pages.set(page.id, {\n page,\n errors,\n })\n } else {\n // No page associated with error\n const existingSetEntry = pages.get(NO_PAGE_KEY)\n const errors = [...(existingSetEntry?.errors || []), error]\n pages.set(NO_PAGE_KEY, {\n page: undefined,\n errors,\n })\n }\n }\n return Array.from(pages.values())\n }, [form.elements, formElementsValidation])\n if (!display) return null\n\n return (\n <Box\n sx={{\n position: 'fixed',\n bottom: 16,\n right: 16,\n zIndex: 10,\n }}\n >\n <PulsingCard\n isExpanded={isExpanded}\n elevation={!isExpanded ? 20 : 0}\n sx={(theme) => ({\n transition: `${theme.transitions.duration.standard}ms ${theme.transitions.easing.easeInOut}`,\n borderTopLeftRadius: 8,\n borderTopRightRadius: 8,\n borderBottomLeftRadius: 8,\n borderBottomRightRadius: 8,\n maxHeight: 350,\n overflowY: 'auto',\n borderColor: theme.palette.error.light,\n borderWidth: 2,\n borderStyle: 'solid',\n backgroundColor: !isExpanded ? theme.palette.error.light : undefined,\n color: !isExpanded ? theme.palette.error.contrastText : undefined,\n })}\n className={!isExpanded ? 'is-clickable' : ''}\n onClick={!isExpanded ? expand : undefined}\n >\n <CardContent\n sx={(theme) => ({\n transition: `${theme.transitions.duration.standard}ms ${theme.transitions.easing.easeInOut}`,\n paddingBottom: !isExpanded ? `8px !important` : undefined,\n paddingTop: !isExpanded ? `8px !important` : undefined,\n })}\n >\n <Grid container justifyContent=\"space-between\" alignItems=\"center\">\n <Grid item alignItems=\"center\" display=\"flex\">\n <MaterialIcon\n className={clsx({\n 'has-text-danger': isExpanded,\n 'has-text-white': !isExpanded,\n })}\n sx={{ mr: 1, fontSize: 22 }}\n >\n error\n </MaterialIcon>\n <Typography\n className={clsx({\n 'has-text-danger': isExpanded,\n 'has-text-white': !isExpanded,\n })}\n fontWeight={600}\n >\n Validation Errors\n </Typography>\n </Grid>\n <Grid item>\n {isExpanded ? (\n <IconButton onClick={contract}>\n <MaterialIcon className=\"icon-small\">\n expand_more\n </MaterialIcon>\n </IconButton>\n ) : (\n <IconButton onClick={expand}>\n <MaterialIcon className=\"icon-small has-text-white\">\n expand_less\n </MaterialIcon>\n </IconButton>\n )}\n </Grid>\n </Grid>\n <Box\n sx={(theme) => ({\n transition: `width ${theme.transitions.duration.standard}ms ${theme.transitions.easing.easeInOut}`,\n whiteSpace: 'nowrap',\n width: isExpanded ? 300 : 194,\n overflowX: 'hidden',\n opacity: isExpanded ? 1 : 0,\n })}\n >\n <Collapse in={isExpanded}>\n {pagesWithValidationErrors.map(({ page, errors }, pageIndex) => {\n const isNotFirstPage = pageIndex > 0\n return (\n <>\n {isNotFirstPage && <Box mt={1} />}\n {page && (\n <Typography\n variant=\"body2\"\n fontWeight=\"600\"\n color=\"text.primary\"\n >\n {page.label}\n </Typography>\n )}\n <Box mb={1} />\n {errors.map(({ errorMessage, label, id }, index, list) => {\n const isFirst = index === 0\n const isLast = index === list.length - 1\n return (\n <Box\n display=\"flex\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n key={index}\n p={1}\n sx={(theme) => ({\n borderColor: theme.palette.divider,\n borderWidth: 1,\n borderStyle: 'solid',\n borderTopLeftRadius: isFirst ? 8 : 0,\n borderTopRightRadius: isFirst ? 8 : 0,\n borderBottomWidth: isLast ? 1 : 0,\n borderBottomLeftRadius: isLast ? 8 : 0,\n borderBottomRightRadius: isLast ? 8 : 0,\n })}\n className=\"ob-list__item is-clickable\"\n onClick={() => {\n if (page && page.id !== currentPage.id) {\n setPageId(page.id)\n }\n const element = document.getElementById(id)\n if (element) {\n window.requestAnimationFrame(() => {\n element.scrollIntoView({\n behavior: 'smooth',\n })\n })\n }\n }}\n >\n <Box sx={{ whitespace: 'nowrap' }}>\n <Typography variant=\"body2\" color=\"text.primary\">\n {label}\n </Typography>\n <Typography\n variant=\"body2\"\n className=\"has-text-danger\"\n sx={{\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n }}\n >\n {errorMessage}\n </Typography>\n </Box>\n <MaterialIcon\n className=\"has-text-grey icon-small\"\n sx={{ ml: 1 }}\n >\n chevron_right\n </MaterialIcon>\n </Box>\n )\n })}\n </>\n )\n })}\n </Collapse>\n </Box>\n </CardContent>\n </PulsingCard>\n </Box>\n )\n}\n\nexport default React.memo(ValidationErrorsCard)\n"]}
|