diff --git a/package-lock.json b/package-lock.json
index 9ddc77c..aa9dd9f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"luxon": "3.5.0",
"primeicons": "^7.0.0",
"primereact": "^10.8.2",
+ "quill": "^2.0.2",
"ramda": "0.30.1",
"react": "18.3.1",
"react-dnd": "^16.0.1",
@@ -8384,6 +8385,11 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
+ "node_modules/fast-diff": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="
+ },
"node_modules/fast-glob": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
@@ -12672,11 +12678,26 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+ },
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+ },
"node_modules/lodash.mapvalues": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz",
@@ -13373,6 +13394,11 @@
"tslib": "^2.0.3"
}
},
+ "node_modules/parchment": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz",
+ "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A=="
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -15025,6 +15051,38 @@
}
]
},
+ "node_modules/quill": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.2.tgz",
+ "integrity": "sha512-QfazNrhMakEdRG57IoYFwffUIr04LWJxbS/ZkidRFXYCQt63c1gK6Z7IHUXMx/Vh25WgPBU42oBaNzQ0K1R/xw==",
+ "dependencies": {
+ "eventemitter3": "^5.0.1",
+ "lodash-es": "^4.17.21",
+ "parchment": "^3.0.0",
+ "quill-delta": "^5.1.0"
+ },
+ "engines": {
+ "npm": ">=8.2.3"
+ }
+ },
+ "node_modules/quill-delta": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz",
+ "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==",
+ "dependencies": {
+ "fast-diff": "^1.3.0",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.isequal": "^4.5.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/quill/node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
+ },
"node_modules/raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
diff --git a/package.json b/package.json
index 244230d..59b74c2 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"luxon": "3.5.0",
"primeicons": "^7.0.0",
"primereact": "^10.8.2",
+ "quill": "^2.0.2",
"ramda": "0.30.1",
"react": "18.3.1",
"react-dnd": "^16.0.1",
diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss
index f81f2ef..5ae1937 100644
--- a/src/assets/scss/components/appPage.scss
+++ b/src/assets/scss/components/appPage.scss
@@ -102,7 +102,7 @@
.appPageSection__withBorder {
display: flex;
flex-direction: column;
- gap: 7px;
+ gap: 16px;
width: 100%;
padding: 17px;
border-radius: 6px;
@@ -131,7 +131,7 @@
padding: 5px 0;
&.rowContent {
- padding: 17px 0;
+ padding: 7px 0;
}
p {
@@ -194,6 +194,7 @@
display: flex;
gap: 0.5rem;
justify-content: space-between;
+ margin: 0;
span {
font-size: 14px;
diff --git a/src/assets/scss/components/formBuilder.scss b/src/assets/scss/components/formBuilder.scss
index 4d8a512..8289733 100644
--- a/src/assets/scss/components/formBuilder.scss
+++ b/src/assets/scss/components/formBuilder.scss
@@ -1,4 +1,5 @@
.formBuilder {
+ position: relative;
display: flex;
gap: 20px;
width: 100%;
diff --git a/src/assets/scss/components/layout.scss b/src/assets/scss/components/layout.scss
index e57c2d3..07fa909 100644
--- a/src/assets/scss/components/layout.scss
+++ b/src/assets/scss/components/layout.scss
@@ -12,8 +12,8 @@ body {
margin: 0;
font-family: "Montserrat", sans-serif;
- p, span:not(.p-button-label, .p-button-icon, .p-badge, .p-message-detail), input, label:not(.p-error),
- textarea, a, li, h1, h2, h3, h4, h5, h6, div, th, td {
+ p, span:not(.p-button-label, .p-button-icon, .p-badge, .p-message-detail, .p-highlight),
+ input, label:not(.p-error), textarea, a, li, h1, h2, h3, h4, h5, h6, div, th, td {
color: var(--global-textColor);
}
}
diff --git a/src/assets/scss/components/misc.scss b/src/assets/scss/components/misc.scss
index f4de501..d2f6c23 100644
--- a/src/assets/scss/components/misc.scss
+++ b/src/assets/scss/components/misc.scss
@@ -83,6 +83,13 @@
margin: 0;
}
+.blockingOverlay {
+ position: absolute;
+ z-index: 999;
+ inset: 0;
+ background-color: rgba(255,255,255,0.3)
+}
+
.mb-2 {
margin-bottom: 4px;
}
diff --git a/src/components/BlockingOverlay/index.js b/src/components/BlockingOverlay/index.js
new file mode 100644
index 0000000..02601d6
--- /dev/null
+++ b/src/components/BlockingOverlay/index.js
@@ -0,0 +1,8 @@
+import React from 'react';
+
+const BlockingOverlay = ({ shouldDisplay = false }) => {
+ return shouldDisplay
+ ?
: null;
+}
+
+export default BlockingOverlay;
\ No newline at end of file
diff --git a/src/components/FlowBuilder/components/NodeInitialForm/index.js b/src/components/FlowBuilder/components/NodeInitialForm/index.js
index ad01314..1573ba4 100644
--- a/src/components/FlowBuilder/components/NodeInitialForm/index.js
+++ b/src/components/FlowBuilder/components/NodeInitialForm/index.js
@@ -22,13 +22,15 @@ const NodeInitialForm = ({ data: { id, label = '' } }) => {
useEffect(() => {
const forms = storeGet.main.flowForms();
- const form = head(forms.filter(o => String(o.id) === String(id)))
- const relevantFields = form
- ? form.content
- .filter(o => ['radio', 'select'].includes(o.name))
- .map(o => ({ name: o.id, label: o.label }))
- : [];
- setOptions(relevantFields);
+ if (forms.length > 2) {
+ const form = head(forms.filter(o => String(o.id) === String(id)))
+ const relevantFields = form
+ ? form.content
+ .filter(o => ['radio', 'select'].includes(o.name))
+ .map(o => ({ name: o.id, label: o.label }))
+ : [];
+ setOptions(relevantFields);
+ }
}, [id]);
return (
diff --git a/src/components/FlowBuilder/index.js b/src/components/FlowBuilder/index.js
index fb67452..f0939a1 100644
--- a/src/components/FlowBuilder/index.js
+++ b/src/components/FlowBuilder/index.js
@@ -55,11 +55,10 @@ const FlowBuilder = ({ initialForm = 0, finalForm = 0 }) => {
id: formId,
type: 'output',
data: { label: o.label, id: formId },
- position: { x: 0, y: 300 },
+ position: { x: 0, y: forms.length === 2 ? 150 : 300 },
}
} else {
const x = coordinates.splice(0, 1);
- console.log('x', x)
obj = {
id: formId,
type: 'intermediateForm',
@@ -78,11 +77,15 @@ const FlowBuilder = ({ initialForm = 0, finalForm = 0 }) => {
if (formId !== String(initialForm) && formId !== String(finalForm)) {
edges.push({ id: `${initialForm}->${formId}`, source: String(initialForm), target: formId, type: 'smoothstep' });
}
- if (formId !== String(finalForm) && formId !== String(initialForm) && String(finalForm) !== '0') {
+ if (formId !== String(initialForm) && formId !== String(finalForm) && String(finalForm) !== '0') {
edges.push({ id: `${formId}->${finalForm}`, source: formId, target: String(finalForm), type: 'smoothstep' });
}
});
- console.log('edges', edges, initialNodes);
+
+ if (forms.length === 2 && initialForm && finalForm) {
+ edges.push({ id: `${initialForm}->${finalForm}`, source: String(initialForm), target: String(finalForm), type: 'smoothstep' });
+ }
+
setNodes(initialNodes);
setEdges(edges);
storeSet.main.flowEdges(edges);
diff --git a/src/components/FormField/components/Checkboxes/index.js b/src/components/FormField/components/Checkboxes/index.js
new file mode 100644
index 0000000..6b5d4fb
--- /dev/null
+++ b/src/components/FormField/components/Checkboxes/index.js
@@ -0,0 +1,57 @@
+import React, { useState, useCallback } from 'react';
+import { classNames } from 'primereact/utils';
+import { Controller } from 'react-hook-form';
+import { Checkbox } from 'primereact/checkbox';
+
+const Checkboxes = ({
+ fieldName,
+ label,
+ control,
+ errors,
+ defaultValue = [],
+ config = {},
+ infoText = null,
+ options = []
+ }) => {
+ const [fieldVal, setFieldVal] = useState(defaultValue);
+
+ const onCheckboxesChange = useCallback((e, updateFn) => {
+ let data = [...fieldVal];
+
+ if (e.checked) {
+ data.push(e.value);
+ } else {
+ data.splice(data.indexOf(e.value), 1);
+ }
+
+ setFieldVal(data);
+ updateFn(data);
+ }, [fieldVal]);
+
+ const input =
+ options.map(o =>
+ onCheckboxesChange(e, field.onChange)}
+ checked={field.value.includes(o.name)}
+ className={classNames({ 'p-invalid': fieldState.invalid })}/>
+
+
)}/>
+ return (
+ <>
+
+ {input}
+ {infoText ? {infoText} : null}
+ >)
+}
+
+export default Checkboxes;
\ No newline at end of file
diff --git a/src/components/FormField/components/Datepicker/index.js b/src/components/FormField/components/Datepicker/index.js
index 0732b2e..7d92cb9 100644
--- a/src/components/FormField/components/Datepicker/index.js
+++ b/src/components/FormField/components/Datepicker/index.js
@@ -18,7 +18,7 @@ const Datepicker = ({
return (
<>
{
@@ -31,13 +31,14 @@ const NumberInput = ({
onValueChange={(e) => field.onChange(e.value)}
min={min}
max={max}
- locale={locale} minFractionDigits={minFractionDigits} step={step}
+ locale={locale}
+ minFractionDigits={minFractionDigits}
className={classNames({ 'p-invalid': fieldState.invalid })}/>
)}/>
return (
<>
{inputgroup
?
diff --git a/src/components/FormField/components/Radio/index.js b/src/components/FormField/components/Radio/index.js
index 6606e0a..476a01a 100644
--- a/src/components/FormField/components/Radio/index.js
+++ b/src/components/FormField/components/Radio/index.js
@@ -4,34 +4,35 @@ import { Controller } from 'react-hook-form';
import { RadioButton } from 'primereact/radiobutton';
const Radio = ({
- fieldName,
- label,
- control,
- errors,
- defaultValue,
- config = {},
- infoText = null,
- options = []
- }) => {
+ fieldName,
+ label,
+ control,
+ errors,
+ defaultValue,
+ config = {},
+ infoText = null,
+ options = []
+ }) => {
const input =
- options.map(o =>
- field.onChange(e.value)}
- checked={field.value === o.name}/>
-
-
)}/>
+ options.map(o =>
+ field.onChange(e.value)}
+ checked={field.value === o.name}
+ className={classNames({ 'p-invalid': fieldState.invalid })}/>
+
+
)}/>
return (
<>
{input}
{infoText ? {infoText} : null}
diff --git a/src/components/FormField/components/Select/index.js b/src/components/FormField/components/Select/index.js
index b1a40c6..6006e9a 100644
--- a/src/components/FormField/components/Select/index.js
+++ b/src/components/FormField/components/Select/index.js
@@ -27,13 +27,14 @@ const Select = ({
onChange={(e) => field.onChange(e.value)}
options={options}
optionLabel="label"
+ optionValue="name"
placeholder={placeholder}
className={classNames({ 'p-invalid': fieldState.invalid })}/>
)}/>
return (
<>
{inputgroup
?
diff --git a/src/components/FormField/components/Switch/index.js b/src/components/FormField/components/Switch/index.js
index eb5fb8d..59bb7d1 100644
--- a/src/components/FormField/components/Switch/index.js
+++ b/src/components/FormField/components/Switch/index.js
@@ -34,7 +34,7 @@ const Switch = ({
<>
{offLabel ?
{offLabel} : null}
diff --git a/src/components/FormField/components/TextArea/index.js b/src/components/FormField/components/TextArea/index.js
index 89d113c..a868af3 100644
--- a/src/components/FormField/components/TextArea/index.js
+++ b/src/components/FormField/components/TextArea/index.js
@@ -16,7 +16,7 @@ const TextArea = ({
return (
<>
{inputgroup
?
diff --git a/src/components/FormField/components/Wysiwyg/index.js b/src/components/FormField/components/Wysiwyg/index.js
new file mode 100644
index 0000000..ebcee7c
--- /dev/null
+++ b/src/components/FormField/components/Wysiwyg/index.js
@@ -0,0 +1,54 @@
+import React from 'react';
+import { classNames } from 'primereact/utils';
+import { Controller } from 'react-hook-form';
+import { Editor } from 'primereact/editor';
+
+const Wysiwyg = ({
+ fieldName,
+ label,
+ control,
+ rows = 3,
+ errors,
+ defaultValue,
+ config = {},
+ infoText = null
+ }) => {
+
+ const renderHeader = () => {
+ return (
+
+
+
+
+
+
+ );
+ };
+
+ const header = renderHeader();
+
+ return (
+ <>
+
+
(
+ field.onChange(e.htmlValue)}
+ style={{ height: 80 * rows }}
+ className={classNames({ 'p-invalid': fieldState.invalid })}
+ />
+ )}/>
+ {infoText ? {infoText} : null}
+ >)
+}
+
+export default Wysiwyg;
\ No newline at end of file
diff --git a/src/components/FormField/index.js b/src/components/FormField/index.js
index 45adffa..eb0839e 100644
--- a/src/components/FormField/index.js
+++ b/src/components/FormField/index.js
@@ -12,6 +12,8 @@ import NumberInput from './components/NumberInput';
import Switch from './components/Switch';
import Select from './components/Select';
import Radio from './components/Radio';
+import Wysiwyg from './components/Wysiwyg';
+import Checkboxes from './components/Checkboxes';
const FormField = (props) => {
const fields = {
@@ -23,7 +25,9 @@ const FormField = (props) => {
numberinput: NumberInput,
switch: Switch,
select: Select,
- radio: Radio
+ radio: Radio,
+ wysiwyg: Wysiwyg,
+ checkboxes: Checkboxes
}
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;
diff --git a/src/components/FormFieldRepeater/index.js b/src/components/FormFieldRepeater/index.js
index f4cdf49..299c62e 100644
--- a/src/components/FormFieldRepeater/index.js
+++ b/src/components/FormFieldRepeater/index.js
@@ -3,6 +3,7 @@ import { classNames } from 'primereact/utils';
import { __ } from '@wordpress/i18n';
import { head, isEmpty, isNil, pluck } from 'ramda';
import { diff } from 'deep-object-diff';
+import { klona } from 'klona';
// components
import { InputText } from 'primereact/inputtext';
@@ -97,8 +98,10 @@ const FormFieldRepeater = ({
const storeFieldData = data ?? [];
setStateFieldData(storeFieldData);
setStateOptionsData(prevState => {
- const ids = pluck('id', storeFieldData)
- const objectsToAdd = storeFieldData.filter(o => ids.includes(o.id));
+ const ids = pluck('lookUpDataId', prevState)
+ const objectsToAdd = klona(storeFieldData)
+ .filter(o => !ids.includes(o.lookUpDataId))
+ .map(o => ({...o, id: null}));
return [...prevState, ...objectsToAdd];
});
}
@@ -120,7 +123,7 @@ const FormFieldRepeater = ({
{stateFieldData.map((o, i) =>
{properField(o, i)}
-
{isNil(o.lookUpDataId) && infoText ?
{infoText} : null}
)}
diff --git a/src/components/FormFieldRepeaterCriteria/index.js b/src/components/FormFieldRepeaterCriteria/index.js
index ce388a2..e322a67 100644
--- a/src/components/FormFieldRepeaterCriteria/index.js
+++ b/src/components/FormFieldRepeaterCriteria/index.js
@@ -1,7 +1,7 @@
import React, { useRef, useEffect, useState, useCallback } from 'react';
import { classNames } from 'primereact/utils';
import { __ } from '@wordpress/i18n';
-import { head, isNil, pluck } from 'ramda';
+import { head, isEmpty, isNil, pluck } from 'ramda';
// components
import { InputText } from 'primereact/inputtext';
@@ -9,6 +9,8 @@ import { Button } from 'primereact/button';
import { Menu } from 'primereact/menu';
import { Dropdown } from 'primereact/dropdown';
import { InputNumber } from 'primereact/inputnumber';
+import { diff } from 'deep-object-diff';
+import { klona } from 'klona';
const FormFieldRepeaterCriteria = ({
data,
@@ -99,6 +101,22 @@ const FormFieldRepeaterCriteria = ({
})
}, []);
+ useEffect(() => {
+ const diffData = diff(data[fieldName], stateFieldData);
+
+ if (!isEmpty(diffData)) {
+ const storeFieldData = data[fieldName] ?? [];
+ setStateFieldData(storeFieldData);
+ setStateOptionsData(prevState => {
+ const ids = pluck('lookUpDataId', prevState)
+ const objectsToAdd = klona(storeFieldData)
+ .filter(o => !ids.includes(o.lookUpDataId))
+ .map(o => ({...o, id: null, score: 0}));
+ return [...prevState, ...objectsToAdd];
+ });
+ }
+ }, [data]);
+
useEffect(() => {
setStateOptionsData([...options]);
}, [options]);
@@ -126,7 +144,7 @@ const FormFieldRepeaterCriteria = ({
{properField(o, i)}
- removeItem(i)}/>
+ removeItem(i)}/>
{isNil(o.lookUpDataId) && infoText ? {infoText} : null}
diff --git a/src/layouts/DefaultLayout/components/AppSidebar/index.js b/src/layouts/DefaultLayout/components/AppSidebar/index.js
index e12f005..ca1718e 100644
--- a/src/layouts/DefaultLayout/components/AppSidebar/index.js
+++ b/src/layouts/DefaultLayout/components/AppSidebar/index.js
@@ -30,7 +30,7 @@ const AppSidebar = () => {
{
label: __('Domande in lavorazione', 'gepafin'),
icon: 'pi pi-file',
- href: '/bids',
+ href: '/applications',
id: 11,
enable: intersection(permissions, ['APPLY_CALLS']).length
},
diff --git a/src/pages/Bids/index.js b/src/pages/Applications/index.js
similarity index 74%
rename from src/pages/Bids/index.js
rename to src/pages/Applications/index.js
index c88bbfc..b3da524 100644
--- a/src/pages/Bids/index.js
+++ b/src/pages/Applications/index.js
@@ -3,12 +3,16 @@ import { __ } from '@wordpress/i18n';
import { useNavigate } from 'react-router-dom';
// components
-import MyLatestSubmissionsTable from '../DashboardBenefeciario/components/MyLatestSubmissionsTable';
+import MyLatestSubmissionsTable from '../DashboardBeneficiario/components/MyLatestSubmissionsTable';
import { Button } from 'primereact/button';
-const Bandi = () => {
+const Applications = () => {
const navigate = useNavigate();
+ const gotToBandiDisponibili = () => {
+ navigate('')
+ }
+
return(
@@ -29,6 +33,10 @@ const Bandi = () => {
+
{
)
}
-export default Bandi;
\ No newline at end of file
+export default Applications;
\ No newline at end of file
diff --git a/src/pages/Bandi/components/AllBandiTable/index.js b/src/pages/Bandi/components/AllBandiTable/index.js
index 47b86c5..a690d28 100644
--- a/src/pages/Bandi/components/AllBandiTable/index.js
+++ b/src/pages/Bandi/components/AllBandiTable/index.js
@@ -146,7 +146,7 @@ const AllBandiTable = () => {
style={{ minWidth: '10rem' }}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
diff --git a/src/pages/BandoApplication/index.js b/src/pages/BandoApplication/index.js
new file mode 100644
index 0000000..81ad810
--- /dev/null
+++ b/src/pages/BandoApplication/index.js
@@ -0,0 +1,155 @@
+import React, { useState, useEffect } from 'react';
+import { __ } from '@wordpress/i18n';
+import { useNavigate, useParams } from 'react-router-dom';
+import { klona } from 'klona';
+import { head, is, isNil } from 'ramda';
+import { useForm } from 'react-hook-form';
+
+// store
+import { storeSet, useStore } from '../../store';
+
+// api
+import FormsService from '../../service/forms-service';
+
+// components
+import { Skeleton } from 'primereact/skeleton';
+import { Button } from 'primereact/button';
+import FormField from '../../components/FormField';
+import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
+
+import { formData as testformData } from '../../tempData';
+import BandoService from '../../service/bando-service';
+
+const BandoApplication = () => {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const [formData, setFormData] = useState([]);
+ const [formName, setFormName] = useState('');
+ const isAsyncRequest = useStore().main.isAsyncRequest();
+ const {
+ control,
+ handleSubmit,
+ formState: { errors },
+ getValues,
+ } = useForm({ defaultValues: {}, mode: 'onChange' });
+ const values = getValues();
+
+ const onSubmit = (formData) => {
+ const newFormData = Object.keys(formData).reduce((acc, cur) => {
+ acc.push({
+ 'fieldId': cur,
+ 'fieldValue': formData[cur] && formData[cur].getMonth ? formData[cur].toISOString() : formData[cur]
+ });
+ return acc;
+ }, []);
+ console.log('newFormData', newFormData)
+ };
+
+ const getBandoId = () => {
+ const parsed = parseInt(id)
+ return !isNaN(parsed) ? parsed : 0;
+ }
+
+ const getCallback = (data) => {
+ if (data.status === 'SUCCESS') {
+ /*const forms = data.data;
+ setFormName(forms[0].label);
+ const elements = klona(forms[0].content);
+ setFormData(elements);*/
+ //console.log('testformData.content', testformData.content);
+ setFormName(testformData.label);
+ setFormData(testformData.content);
+ }
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ const errGetCallbacks = (data) => {
+ set404FromErrorResponse(data);
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ useEffect(() => {
+ const bandoId = getBandoId();
+
+ if (bandoId) {
+ storeSet.main.setAsyncRequest();
+ FormsService.getFormsForCall(bandoId, getCallback, errGetCallbacks);
+ }
+ }, [id]);
+
+ return (
+
+ {!isAsyncRequest
+ ?
+
{formName}
+
+ : <>
+
+
+ >}
+
+
+
+ {!isAsyncRequest
+ ?
+ : <>
+
+
+
+
+
+
+
+
+ >}
+
+ )
+
+}
+
+export default BandoApplication;
\ No newline at end of file
diff --git a/src/pages/BandoEdit/components/BandoEditFormStep2/index.js b/src/pages/BandoEdit/components/BandoEditFormStep2/index.js
index 80b3258..7aa289a 100644
--- a/src/pages/BandoEdit/components/BandoEditFormStep2/index.js
+++ b/src/pages/BandoEdit/components/BandoEditFormStep2/index.js
@@ -66,8 +66,9 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, getFormErrors },
summary: '',
detail: __('Il bando è stato aggiornato corretamente!', 'gepafin')
});
- setFormInitialData(data.data);
- reset();
+ const newFormData = {...formInitialData, ...data.data};
+ setFormInitialData(newFormData);
+ reset(newFormData);
}
}
diff --git a/src/pages/BandoEdit/index.js b/src/pages/BandoEdit/index.js
index efbfab6..973e400 100644
--- a/src/pages/BandoEdit/index.js
+++ b/src/pages/BandoEdit/index.js
@@ -21,6 +21,7 @@ import BandoEditFormStep2 from './components/BandoEditFormStep2';
import { Messages } from 'primereact/messages';
import FormsService from '../../service/forms-service';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
+import BlockingOverlay from '../../components/BlockingOverlay';
const BandoEdit = () => {
const isAsyncRequest = useStore().main.isAsyncRequest();
@@ -280,7 +281,7 @@ const BandoEdit = () => {
model={stepItems}
activeIndex={activeStep}
readOnly={false}/>
- : null}
+ : }
diff --git a/src/pages/BandoFlowEdit/index.js b/src/pages/BandoFlowEdit/index.js
index 654c497..f6d280a 100644
--- a/src/pages/BandoFlowEdit/index.js
+++ b/src/pages/BandoFlowEdit/index.js
@@ -1,7 +1,7 @@
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
-import { isEmpty } from 'ramda';
+import { isEmpty, head } from 'ramda';
// store
import { storeSet, useStore } from '../../store';
@@ -17,6 +17,8 @@ import { Button } from 'primereact/button';
import { Dropdown } from 'primereact/dropdown';
import FlowBuilder from '../../components/FlowBuilder';
import { Messages } from 'primereact/messages';
+import FlowService from '../../service/flow-service';
+import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup';
const BandoFlowEdit = () => {
const { id } = useParams();
@@ -39,17 +41,76 @@ const BandoFlowEdit = () => {
navigate(`/tenders/${bandoId}/forms`);
}
+ const confirmDelete = (event) => {
+ confirmPopup({
+ target: event.currentTarget,
+ message: __('Sei sicuro di reset questo flow?', 'gepafin'),
+ acceptLabel: __('Si', 'gepafin'),
+ icon: 'pi pi-info-circle',
+ defaultFocus: 'reject',
+ acceptClassName: 'p-button-danger',
+ accept: doDelete,
+ reject: () => {}
+ });
+ };
+
+ const doDelete = () => {
+ storeSet.main.flowData([]);
+ storeSet.main.flowEdges([]);
+ setInitialForm(0);
+ setFinalForm(0);
+ }
+
+ const updateInitialForm = (value) => {
+ setInitialForm(value);
+ if (forms.length === 2) {
+ const finalForm = head(forms.filter(o => o.id !== value));
+ if (finalForm) {
+ setFinalForm(finalForm.id);
+ }
+ }
+ }
+
const shoudDisableSaving = useCallback(() => {
- return isEmpty(flowData) || isEmpty(flowEdges) || isEmpty(initialForm) || isEmpty(finalForm);
+ return forms.length > 2
+ ? isEmpty(flowData) || isEmpty(flowEdges) || isEmpty(initialForm) || isEmpty(finalForm)
+ : isEmpty(flowEdges) || isEmpty(initialForm);
}, [flowData, flowEdges]);
const doSave = () => {
- console.log('doSave', {
+ storeSet.main.setAsyncRequest();
+ const bandoId = getBandoId();
+ const body = {
initialForm,
finalForm,
flowData,
flowEdges
- });
+ };
+ if (flowMsgs.current) {
+ flowMsgs.current.clear();
+ }
+ FlowService.createFlow(bandoId, body, getFlowCreateCallback, errGetFlowCreateCallback);
+ }
+
+ const getFlowCreateCallback = (data) => {
+ if (data.status === 'SUCCESS') {
+ if (flowMsgs.current) {
+ flowMsgs.current.show([
+ {
+ id: '99',
+ sticky: true, severity: 'success', summary: '',
+ detail: __('Flow è salvato.', 'gepafin'),
+ closable: false
+ }
+ ]);
+ }
+ }
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ const errGetFlowCreateCallback = (data) => {
+ set404FromErrorResponse(data);
+ storeSet.main.unsetAsyncRequest();
}
const getFormsCallback = (data) => {
@@ -66,10 +127,27 @@ const BandoFlowEdit = () => {
storeSet.main.unsetAsyncRequest();
}
+ const getFlowCallback = (data) => {
+ if (data.status === 'SUCCESS' && data.data) {
+ storeSet.main.flowData(data.data.flowData);
+ storeSet.main.flowEdges(data.data.flowEdges);
+ setInitialForm(data.data.initialForm);
+ setFinalForm(data.data.finalForm);
+
+ }
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ const errGetFlowCallback = (data) => {
+ set404FromErrorResponse(data);
+ storeSet.main.unsetAsyncRequest();
+ }
+
useEffect(() => {
const bandoId = getBandoId();
storeSet.main.setAsyncRequest();
FormsService.getFormsForCall(bandoId, getFormsCallback, errGetFormsCallback);
+ FlowService.getFlow(bandoId, getFlowCallback, errGetFlowCallback)
}, [id]);
useEffect(() => {
@@ -112,7 +190,7 @@ const BandoFlowEdit = () => {
setInitialForm(e.value)}
+ onChange={(e) => updateInitialForm(e.value)}
optionDisabled={(opt) => finalForm === opt.value}
options={formOptions}
optionLabel="label"
@@ -157,6 +235,13 @@ const BandoFlowEdit = () => {
disabled={shoudDisableSaving()}
label={__('Salva', 'gepafin')} icon="pi pi-save" iconPos="right"/>
+
+
+
+
)
diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js
new file mode 100644
index 0000000..9e6d982
--- /dev/null
+++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import { __ } from '@wordpress/i18n';
+
+// components
+import ElementSettingRepeater from '../ElementSettingRepeater';
+import { InputText } from 'primereact/inputtext';
+
+const ElementSetting = ({ setting, changeFn, updateDataFn }) => {
+
+ const settingLabels = {
+ label: __('Label', 'gepafin'),
+ placeholder: __('Segnaposto', 'gepafin'),
+ step: __('Precisione decimale', 'gepafin'),
+ options: __('Opzioni', 'gepafin'),
+ mime: __('Tipo di file', 'gepafin'),
+ }
+
+ return
+
+ {setting.name === 'options'
+ ?
+ : changeFn(e.target.value, setting.name)}/>}
+
+}
+
+export default ElementSetting;
\ No newline at end of file
diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/index.js
index de48434..e91d52c 100644
--- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/index.js
+++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/index.js
@@ -12,7 +12,7 @@ import { Button } from 'primereact/button';
import { Tag } from 'primereact/tag';
import { TabView, TabPanel } from 'primereact/tabview';
import { InputSwitch } from 'primereact/inputswitch';
-import ElementSettingRepeater from './components/ElementSettingRepeater';
+import ElementSetting from './components/ElementSetting';
const BuilderElementSettings = ({ closeSettings }) => {
const elements = useStore().main.formElements();
@@ -97,15 +97,11 @@ const BuilderElementSettings = ({ closeSettings }) => {
{settings
- ? settings.map((o) =>
-
- {o.name === 'options'
- ?
-
- : onChange(e.target.value, o.name)}/>}
-
)
+ ? settings.map((o) => )
: null}
diff --git a/src/pages/BandoFormsEdit/components/FormBuilder/index.js b/src/pages/BandoFormsEdit/components/FormBuilder/index.js
index f2a4533..8a346c8 100644
--- a/src/pages/BandoFormsEdit/components/FormBuilder/index.js
+++ b/src/pages/BandoFormsEdit/components/FormBuilder/index.js
@@ -11,11 +11,13 @@ import BuilderElementItem from '../BuilderElementItem';
import { Sidebar } from 'primereact/sidebar';
import BuilderElementSettings from '../BuilderElementSettings';
import BuilderDropzone from '../BuilderDropzone';
+import BlockingOverlay from '../../../../components/BlockingOverlay';
const FormBuilder = () => {
const elements = useStore().main.formElements();
const elementItems = useStore().main.elementItems();
const activeElement = useStore().main.activeElement();
+ const isAsyncRequest = useStore().main.isAsyncRequest();
const renderField = useCallback((field, index) => {
return (
@@ -65,6 +67,7 @@ const FormBuilder = () => {
{elementItems.map((item) => renderItem(item))}
+
>
)
diff --git a/src/pages/BandoFormsEdit/index.js b/src/pages/BandoFormsEdit/index.js
index 4499de3..972f988 100644
--- a/src/pages/BandoFormsEdit/index.js
+++ b/src/pages/BandoFormsEdit/index.js
@@ -113,7 +113,7 @@ const BandoFormsEdit = () => {
const getElementItemsCallback = (data) => {
if (data.status === 'SUCCESS') {
- storeSet.main.elementItems(elementItems);
+ storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
//storeSet.main.elementItems(data.data);
}
storeSet.main.unsetAsyncRequest();
@@ -184,7 +184,7 @@ const BandoFormsEdit = () => {
- {!isAsyncRequest ? : null}
+
@@ -198,10 +198,12 @@ const BandoFormsEdit = () => {
label={__('Indietro', 'gepafin')} icon="pi pi-arrow-left" iconPos="left"/>
doSave()}
+ disabled={isAsyncRequest}
label={__('Salva progressi', 'gepafin')} icon="pi pi-save" iconPos="right"/>
{/* {
diff --git a/src/pages/BandoView/index.js b/src/pages/BandoView/index.js
index 78f5033..de8c212 100644
--- a/src/pages/BandoView/index.js
+++ b/src/pages/BandoView/index.js
@@ -32,22 +32,6 @@ const BandoView = () => {
navigate(`/tenders/${id}`);
}
- const scaricaBando = () => {
-
- }
-
- const scaricaModulistica = () => {
-
- }
-
- const submitQuestion = () => {
-
- }
-
- const saveToFavourites = () => {
-
- }
-
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setData(getFormattedBandiData(data.data));
@@ -196,7 +180,7 @@ const BandoView = () => {
{__('FAQ', 'gepafin')}
- {data.faq.map((o, i) =>
+ {data.faq.map((o, i) =>
{o.response}
@@ -228,20 +212,20 @@ const BandoView = () => {
type="button"
disabled={true}
outlined
- onClick={scaricaBando}
+ onClick={() => {}}
label={__('Scarica Bando Completo', 'gepafin')}
icon="pi pi-download" iconPos="right"/>
{}}
label={__('Scarica Modulistica', 'gepafin')}
icon="pi pi-download" iconPos="right"/>
{}}
label={__('Presenta Domanda', 'gepafin')}
icon="pi pi-save" iconPos="right"/>
{
outlined
rounded
disabled={true}
- onClick={saveToFavourites}
+ onClick={() => {}}
label={__('Aggiungi a Preferiti', 'gepafin')}
icon="pi pi-heart" iconPos="left"/>
diff --git a/src/pages/BandoViewBeneficiario/index.js b/src/pages/BandoViewBeneficiario/index.js
new file mode 100644
index 0000000..d57bcb4
--- /dev/null
+++ b/src/pages/BandoViewBeneficiario/index.js
@@ -0,0 +1,271 @@
+import React, { useState, useEffect, useRef } from 'react';
+import { __, sprintf } from '@wordpress/i18n';
+import { useNavigate, useParams } from 'react-router-dom';
+import { is, isEmpty } from 'ramda';
+
+// store
+import { storeSet, useStore } from '../../store';
+
+// tools
+import getNumberWithCurrency from '../../helpers/getNumberWithCurrency';
+import getDateFromISOstring from '../../helpers/getDateFromISOstring';
+
+// components
+import { Skeleton } from 'primereact/skeleton';
+import { Accordion } from 'primereact/accordion';
+import { AccordionTab } from 'primereact/accordion';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Button } from 'primereact/button';
+import BandoService from '../../service/bando-service';
+import { Messages } from 'primereact/messages';
+import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
+
+const BandoViewBeneficiario = () => {
+ const isAsyncRequest = useStore().main.isAsyncRequest();
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const [data, setData] = useState({});
+ const [newQuestion, setNewQuestion] = useState('');
+ const bandoMsgs = useRef(null);
+
+ const closePreview = () => {
+ navigate(`/tenders/${id}`);
+ }
+
+ const scaricaBando = () => {
+
+ }
+
+ const scaricaModulistica = () => {
+
+ }
+
+ const submitApplication = () => {
+ navigate(`/tenders/${id}/application`);
+ }
+
+ const saveToFavourites = () => {
+
+ }
+
+ const getCallback = (data) => {
+ if (data.status === 'SUCCESS') {
+ setData(getFormattedBandiData(data.data));
+ }
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ const errGetCallback = (data) => {
+ if (bandoMsgs.current && data.message) {
+ bandoMsgs.current.show([
+ {
+ sticky: true, severity: 'error', summary: '',
+ detail: data.message,
+ closable: true
+ }
+ ]);
+ }
+ set404FromErrorResponse(data);
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ const getFormattedBandiData = (data) => {
+ data.dates = data.dates.map(v => is(String, v) ? new Date(v) : (v ? v : ''));
+ return data;
+ };
+
+ useEffect(() => {
+ const parsed = parseInt(id)
+ const bandoId = !isNaN(parsed) ? parsed : 0;
+
+ BandoService.getBando(bandoId, getCallback, errGetCallback);
+ }, [id]);
+
+ return (
+
+ {!isAsyncRequest && !isEmpty(data)
+ ?
+
{data.name}
+
+ {__('Data:', 'gepafin')}
+ {getDateFromISOstring(data.createdDate)}
+
+
+ : <>
+
+
+ >}
+
+
+
+
+ {!isAsyncRequest && !isEmpty(data)
+ ?
+
+
+
+
+
+
+
{__('Descrizione breve', 'gepafin')}
+
+
{data.descriptionShort}
+
+
+
+
+
+
+ {__('Importo totale', 'gepafin')}
+ {getNumberWithCurrency(data.amount)}
+
+
+ {__('Importo massimo per progetto', 'gepafin')}
+ {getNumberWithCurrency(data.amountMax)}
+
+
+
+
+
+ {__('Data apertura', 'gepafin')}
+ {getDateFromISOstring(data.dates[0])}
+
+
+ {__('Data chiusura', 'gepafin')}
+ {getDateFromISOstring(data.dates[1])}
+
+
+
+
+
+
{__('Descrizione dettagliata', 'gepafin')}
+
+
{data.descriptionLong}
+
+
+
+
+
{__('Requisiti di Partecipazione', 'gepafin')}
+
+
+ {data.aimedTo.map((o, i) => -
+ {o.value}
+
)}
+
+
+
+
+
+
{__('Documentazione Richiesta', 'gepafin')}
+
+
{data.documentationRequested}
+
+
+
+
+
{__('Criteri di Valutazione', 'gepafin')}
+
+
+ {data.criteria.map((o, i) => -
+ {`${o.value} ${sprintf(__('(%d punti)'), o.score)}`}
+
)}
+
+
+
+
+
+
{__('Allegati', 'gepafin')}
+
+
+ {data.docs.map((o, i) => -
+ {o.name}
+
)}
+
+
+
+
+
+
{__('FAQ', 'gepafin')}
+
+ {data.faq.map((o, i) =>
+
+ {o.response}
+
+ )}
+
+
+
+
+
{__('Non hai trovato la risposta che cercavi?', 'gepafin')}
+
+
+ setNewQuestion(e.target.value)}
+ aria-describedby="newQuestion-help"/>
+
+ {__('Riceverai una notifica quando ti risponderemo', 'gepafin')}
+
+
+
+
+
+
{__('Download Documenti', 'gepafin')}
+
+
+
+
+
+
+
+
+
+
{__('Contatti per Assistenza', 'gepafin')}
+
+
Email: bandi@gepafin.it
+
Telefono: +39 075 123 4567
+
+
+
+ : <>
+
+
+
+
+
+
+
+
+ >}
+
+ )
+
+}
+
+export default BandoViewBeneficiario;
\ No newline at end of file
diff --git a/src/pages/Dashboard/components/LatestBandiTable/index.js b/src/pages/Dashboard/components/LatestBandiTable/index.js
index db27510..1deacbd 100644
--- a/src/pages/Dashboard/components/LatestBandiTable/index.js
+++ b/src/pages/Dashboard/components/LatestBandiTable/index.js
@@ -25,6 +25,7 @@ import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import { Tag } from 'primereact/tag';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
+import { Link } from 'react-router-dom';
const LatestBandiTable = () => {
@@ -73,7 +74,8 @@ const LatestBandiTable = () => {
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
- setItems(getFormattedBandiData(data.data));
+ const newItems = data.data.filter(o => o.status === 'PUBLISH');
+ setItems(getFormattedBandiData(newItems));
setStatuses(uniq(data.data.map(o => o.status)))
initFilters();
}
@@ -87,8 +89,8 @@ const LatestBandiTable = () => {
const getFormattedBandiData = (data) => {
return [...(data || [])].map((d) => {
- d.start_date = new Date(d.start_date);
- d.end_date = new Date(d.end_date);
+ d.start_date = new Date(d.dates[0]);
+ d.end_date = new Date(d.dates[1]);
return d;
});
@@ -122,8 +124,7 @@ const LatestBandiTable = () => {
name: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
start_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
end_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
- submissions: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
- status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
+ status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] }
});
setGlobalFilterValue('');
};
@@ -168,6 +169,12 @@ const LatestBandiTable = () => {
return
;
};
+ const actionsBodyTemplate = (rowData) => {
+ return
+
+
+ }
+
const header = renderHeader();
return(
@@ -185,12 +192,10 @@ const LatestBandiTable = () => {
-
-
+
+
)
diff --git a/src/pages/DashboardBeneficiario/components/LatestBandiTable/index.js b/src/pages/DashboardBeneficiario/components/LatestBandiTable/index.js
new file mode 100644
index 0000000..82bf47d
--- /dev/null
+++ b/src/pages/DashboardBeneficiario/components/LatestBandiTable/index.js
@@ -0,0 +1,172 @@
+import React, { useState, useEffect} from 'react';
+import { __ } from '@wordpress/i18n';
+import { uniq } from 'ramda';
+
+// tools
+import getBandoLabel from '../../../../helpers/getBandoLabel';
+import getBandoSeverity from '../../../../helpers/getBandoSeverity';
+
+// store
+import { storeSet } from '../../../../store';
+
+// api
+import BandoService from '../../../../service/bando-service';
+
+// components
+import { FilterMatchMode, FilterOperator } from 'primereact/api';
+import { DataTable } from 'primereact/datatable';
+import { Column } from 'primereact/column';
+import { InputText } from 'primereact/inputtext';
+import { IconField } from 'primereact/iconfield';
+import { InputIcon } from 'primereact/inputicon';
+import { Dropdown } from 'primereact/dropdown';
+import { InputNumber } from 'primereact/inputnumber';
+import { Button } from 'primereact/button';
+import { Calendar } from 'primereact/calendar';
+import { Tag } from 'primereact/tag';
+import ProperBandoLabel from '../../../../components/ProperBandoLabel';
+import { Link } from 'react-router-dom';
+
+
+const LatestBandiTable = () => {
+ const [items, setItems] = useState(null);
+ const [filters, setFilters] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [globalFilterValue, setGlobalFilterValue] = useState('');
+ const [statuses, setStatuses] = useState([]);
+
+ useEffect(() => {
+ storeSet.main.setAsyncRequest();
+ BandoService.getBandi(getCallback, errGetCallbacks);
+ }, []);
+
+ const getCallback = (data) => {
+ if (data.status === 'SUCCESS') {
+ const newItems = data.data.filter(o => o.status === 'PUBLISH');
+ setItems(getFormattedBandiData(newItems));
+ setStatuses(uniq(data.data.map(o => o.status)))
+ initFilters();
+ }
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ const errGetCallbacks = (data) => {
+ console.log('errGetCallbacks', data)
+ storeSet.main.unsetAsyncRequest();
+ }
+
+ const getFormattedBandiData = (data) => {
+ return [...(data || [])].map((d) => {
+ d.start_date = new Date(d.dates[0]);
+ d.end_date = new Date(d.dates[1]);
+
+ return d;
+ });
+ };
+
+ const formatDate = (value) => {
+ return value.toLocaleDateString('it-IT', {
+ day: '2-digit',
+ month: '2-digit',
+ year: 'numeric'
+ });
+ };
+
+ const clearFilter = () => {
+ initFilters();
+ };
+
+ const onGlobalFilterChange = (e) => {
+ const value = e.target.value;
+ let _filters = { ...filters };
+
+ _filters['global'].value = value;
+
+ setFilters(_filters);
+ setGlobalFilterValue(value);
+ };
+
+ const initFilters = () => {
+ setFilters({
+ global: { value: null, matchMode: FilterMatchMode.CONTAINS },
+ name: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
+ start_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
+ end_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
+ status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] }
+ });
+ setGlobalFilterValue('');
+ };
+
+ const renderHeader = () => {
+ return (
+
+
+
+
+
+
+
+ );
+ };
+
+ const dateStartBodyTemplate = (rowData) => {
+ return formatDate(rowData.start_date);
+ };
+
+ const dateEndBodyTemplate = (rowData) => {
+ return formatDate(rowData.end_date);
+ };
+
+ const dateFilterTemplate = (options) => {
+ return options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
+ };
+
+ const balanceFilterTemplate = (options) => {
+ return options.filterCallback(e.value, options.index)} />;
+ };
+
+ const statusBodyTemplate = (rowData) => {
+ return ;
+ };
+
+ const statusFilterTemplate = (options) => {
+ return options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder="Select One" className="p-column-filter" showClear />;
+ };
+
+ const statusItemTemplate = (option) => {
+ return ;
+ };
+
+ const actionsBodyTemplate = (rowData) => {
+ return
+
+
+ }
+
+ const header = renderHeader();
+
+ return(
+
+ setFilters(e.filters)}>
+
+
+
+
+
+
+
+ )
+}
+
+export default LatestBandiTable;
\ No newline at end of file
diff --git a/src/pages/DashboardBenefeciario/components/MyLatestSubmissionsTable/index.js b/src/pages/DashboardBeneficiario/components/MyLatestSubmissionsTable/index.js
similarity index 96%
rename from src/pages/DashboardBenefeciario/components/MyLatestSubmissionsTable/index.js
rename to src/pages/DashboardBeneficiario/components/MyLatestSubmissionsTable/index.js
index 965f79d..2e940ed 100644
--- a/src/pages/DashboardBenefeciario/components/MyLatestSubmissionsTable/index.js
+++ b/src/pages/DashboardBeneficiario/components/MyLatestSubmissionsTable/index.js
@@ -38,7 +38,8 @@ const MyLatestSubmissionsTable = () => {
modify_date: '2024-08-30T00:00:00+00:00',
progress: 50,
status: 'DRAFT',
- id: 11
+ id: 11,
+ callId: 11
},
{
name: 'Bando Sostenibilità 2024',
@@ -46,7 +47,8 @@ const MyLatestSubmissionsTable = () => {
modify_date: '2024-08-15T00:00:00+00:00',
progress: 25,
status: 'DRAFT',
- id: 9
+ id: 9,
+ callId: 12
}
]
setItems(getFormattedBandiData(items));
@@ -138,7 +140,7 @@ const MyLatestSubmissionsTable = () => {
};
const actionsBodyTemplate = (rowData) => {
- return
+ return
}
@@ -161,7 +163,7 @@ const MyLatestSubmissionsTable = () => {
style={{ minWidth: '10rem' }}
body={dateModifyBodyTemplate} filter filterElement={dateFilterTemplate}/>
{
+const DashboardBeneficiario = () => {
const navigate = useNavigate();
const goToAllSubmissions = () => {
- navigate('/bids/new');
+ navigate('/bids');
}
return(
@@ -83,4 +83,4 @@ const DashboardBenefeciario = () => {
)
}
-export default DashboardBenefeciario;
\ No newline at end of file
+export default DashboardBeneficiario;
\ No newline at end of file
diff --git a/src/routes.js b/src/routes.js
index 8996b93..e499e91 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -5,7 +5,8 @@ import PageNotFound from './pages/PageNotFound';
import Login from './pages/Login';
import ProtectedRoute from './components/ProtectedRoute';
import Dashboard from './pages/Dashboard';
-import DashboardBenefeciario from './pages/DashboardBenefeciario';
+import DashboardBeneficiario from './pages/DashboardBeneficiario';
+import BandoViewBeneficiario from './pages/BandoViewBeneficiario';
import DefaultLayout from './layouts/DefaultLayout';
import Bandi from './pages/Bandi';
import BandoEdit from './pages/BandoEdit';
@@ -14,7 +15,8 @@ import BandoFormsEdit from './pages/BandoFormsEdit';
import BandoForms from './pages/BandoForms';
import BandoFormsPreview from './pages/BandoFormsPreview';
import BandoFlowEdit from './pages/BandoFlowEdit';
-import Bids from './pages/Bids';
+import Applications from './pages/Applications';
+import BandoApplication from './pages/BandoApplication';
const routes = ({ role }) => {
return (
@@ -22,7 +24,7 @@ const routes = ({ role }) => {
}>
{'ROLE_SUPER_ADMIN' === role ? : null}
- {'ROLE_BENEFICIARY' === role ? : null}
+ {'ROLE_BENEFICIARY' === role ? : null}
}/>
{'ROLE_SUPER_ADMIN' === role ? : null}
@@ -32,6 +34,7 @@ const routes = ({ role }) => {
}/>
{'ROLE_SUPER_ADMIN' === role ? : null}
+ {'ROLE_BENEFICIARY' === role ? : null}
}/>
{'ROLE_SUPER_ADMIN' === role ? : null}
@@ -48,8 +51,11 @@ const routes = ({ role }) => {
{'ROLE_SUPER_ADMIN' === role ? : null}
}/>
-
- {'ROLE_BENEFICIARY' === role ? : null}
+
+ {'ROLE_BENEFICIARY' === role ? : null}
+ }/>
+
+ {'ROLE_BENEFICIARY' === role ? : null}
}/>
}/>
diff --git a/src/service/flow-service.js b/src/service/flow-service.js
new file mode 100644
index 0000000..517ec69
--- /dev/null
+++ b/src/service/flow-service.js
@@ -0,0 +1,14 @@
+import { NetworkService } from './network-service';
+
+const API_BASE_URL = process.env.REACT_APP_API_EXECUTION_ADDRESS;
+
+export default class FlowService {
+
+ static getFlow = (id, callback, errCallback) => {
+ NetworkService.get(`${API_BASE_URL}/flow/call/${id}`, callback, errCallback);
+ };
+
+ static createFlow = (id, body, callback, errCallback) => {
+ NetworkService.put(`${API_BASE_URL}/flow/call/${id}`, body, callback, errCallback);
+ };
+}
diff --git a/src/tempData.js b/src/tempData.js
index 0f7c9a0..696ac79 100644
--- a/src/tempData.js
+++ b/src/tempData.js
@@ -95,22 +95,22 @@ export const formData = {
label: 'La forma per Innovazione digitale 2024',
content: [
{
- "id": "aec5ee1885",
+ "id": "a9a8aeb479",
"name": "textinput",
- "label": "Text Input",
+ "label": "Testo Breve",
"settings": [
{
"name": "label",
- "value": "Text input"
+ "value": "Testo Breve"
},
{
"name": "placeholder",
- "value": "Placeholder text"
+ "value": ""
}
],
"validators": {
- "isRequired": false,
- "minLength": null,
+ "isRequired": true,
+ "minLength": "3",
"maxLength": null,
"pattern": null,
"custom": null
@@ -118,17 +118,17 @@ export const formData = {
"dbId": 1
},
{
- "id": "a730f1f4d0",
+ "id": "a20469fc97",
"name": "textarea",
- "label": "Text Area",
+ "label": "Testo Lungo",
"settings": [
{
"name": "label",
- "value": "Text area"
+ "value": "Testo Lungo"
},
{
"name": "placeholder",
- "value": "Placeholder text"
+ "value": ""
}
],
"validators": {
@@ -141,69 +141,46 @@ export const formData = {
"dbId": 2
},
{
- "id": "aa8746a7c3",
- "name": "textinput",
- "label": "P.IVA",
+ "id": "a21dc560f6",
+ "name": "wysiwyg",
+ "label": "Campo di Testo Formattato",
"settings": [
{
"name": "label",
- "value": "P.IVA"
- },
- {
- "name": "placeholder",
- "value": "Insert p.iva number"
- }
- ],
- "validators": {
- "isRequired": true,
- "minLength": null,
- "maxLength": null,
- "pattern": null,
- "custom": "isValidVAT"
- },
- "dbId": 4
- },
- {
- "id": "ae3dde17cd",
- "name": "radio",
- "label": "Radio Input",
- "settings": [
- {
- "name": "label",
- "value": "Radio input"
- },
- {
- "name": "options",
- "value": [
- {
- "name": "opt1",
- "label": "Opt1"
- }
- ]
- }
- ],
- "validators": {
- "isRequired": false,
- "min": null,
- "max": null,
- "custom": null
- },
- "dbId": 5
- },
- {
- "id": "abf838016f",
- "name": "textinput",
- "label": "Number Input",
- "settings": [
- {
- "name": "label",
- "value": "Number"
+ "value": "Testo Formattato"
},
{
"name": "placeholder",
"value": ""
}
],
+ "validators": {
+ "isRequired": false,
+ "minLength": null,
+ "maxLength": null,
+ "pattern": null,
+ "custom": null
+ },
+ "dbId": 3
+ },
+ {
+ "id": "a5c3860c1a",
+ "name": "numberinput",
+ "label": "Campo Numerico",
+ "settings": [
+ {
+ "name": "label",
+ "value": "Numero"
+ },
+ {
+ "name": "placeholder",
+ "value": 0
+ },
+ {
+ "name": "step",
+ "value": 0
+ }
+ ],
"validators": {
"isRequired": false,
"min": null,
@@ -211,7 +188,146 @@ export const formData = {
"pattern": null,
"custom": null
},
- "dbId": 3
+ "dbId": 4
+ },
+ {
+ "id": "a7252ecc8d",
+ "name": "radio",
+ "label": "Scelta Singola",
+ "settings": [
+ {
+ "name": "label",
+ "value": "Scelta Singola"
+ },
+ {
+ "name": "options",
+ "value": [
+ {
+ "name": "o8df4ffa62",
+ "label": "Radio opzione A"
+ },
+ {
+ "name": "o3ed6fb4d8",
+ "label": "Radio opzione B"
+ }
+ ]
+ }
+ ],
+ "validators": {
+ "isRequired": true,
+ "custom": null
+ },
+ "dbId": 5
+ },
+ {
+ "id": "a778783c9d",
+ "name": "select",
+ "label": "Menu a Tendina",
+ "settings": [
+ {
+ "name": "label",
+ "value": "Menu a Tendina"
+ },
+ {
+ "name": "options",
+ "value": [
+ {
+ "name": "od9f50d8a8",
+ "label": "Opzione A"
+ },
+ {
+ "name": "o8cb208732",
+ "label": "Opzione B"
+ }
+ ]
+ }
+ ],
+ "validators": {
+ "isRequired": false,
+ "custom": null
+ },
+ "dbId": 6
+ },
+ {
+ "id": "afee29df1a",
+ "name": "switch",
+ "label": "Casella di Spunta",
+ "settings": [
+ {
+ "name": "label",
+ "value": "Casella di Spunta"
+ }
+ ],
+ "validators": {
+ "isRequired": false
+ },
+ "dbId": 8
+ },
+ {
+ "id": "a5fdbd77df",
+ "name": "checkboxes",
+ "label": "Scelta Multipla",
+ "settings": [
+ {
+ "name": "label",
+ "value": "Scelta Multipla"
+ },
+ {
+ "name": "options",
+ "value": [
+ {
+ "name": "o55ea20665",
+ "label": "Opz checkbox A"
+ },
+ {
+ "name": "oc10db3d79",
+ "label": "Opz checkbox B"
+ }
+ ]
+ }
+ ],
+ "validators": {
+ "isRequired": true,
+ "custom": null
+ },
+ "dbId": 7
+ },
+ {
+ "id": "a2810fd8a1",
+ "name": "fileupload",
+ "label": "Caricamento File",
+ "settings": [
+ {
+ "name": "label",
+ "value": "Caricamento File"
+ },
+ {
+ "name": "mime",
+ "value": ['image/jpeg', 'image/png']
+ }
+ ],
+ "validators": {
+ "isRequired": true,
+ "maxSize": 100000,
+ "custom": null
+ },
+ "dbId": 10
+ },
+ {
+ "id": "ae14c94da7",
+ "name": "datepicker",
+ "label": "Data",
+ "settings": [
+ {
+ "name": "label",
+ "value": "Data"
+ }
+ ],
+ "validators": {
+ "isRequired": true,
+ "custom": null
+ },
+ "dbId": 9
}
]
};
@@ -219,16 +335,18 @@ export const formData = {
export const elementItems = [
{
id: 1,
+ sortOrder: 1,
name: 'textinput',
- label: 'Text Input',
+ label: 'Testo Breve',
+ description: 'Per risposte concise (nomi, titoli, brevi descrizioni)',
settings: [
{
name: "label",
- value: "Text input"
+ value: "Testo Breve"
},
{
name: "placeholder",
- value: "Placeholder text"
+ value: ""
}
],
validators: {
@@ -241,16 +359,18 @@ export const elementItems = [
},
{
id: 2,
+ sortOrder: 2,
name: 'textarea',
- label: 'Text Area',
+ label: 'Testo Lungo',
+ description: 'Campo di testo esteso per paragrafi, descrizioni, proposte',
settings: [
{
name: "label",
- value: "Text area"
+ value: "Testo Lungo"
},
{
name: "placeholder",
- value: "Placeholder text"
+ value: ""
}
],
validators: {
@@ -263,15 +383,44 @@ export const elementItems = [
},
{
id: 3,
- name: 'numberinput',
- label: 'Number Input',
+ sortOrder: 3,
+ name: 'wysiwyg',
+ label: 'Campo di Testo Formattato',
+ description: 'Editor avanzato per testo con formattazione',
settings: [
{
name: "label",
- value: "Number"
+ value: "Testo Formattato"
},
{
name: "placeholder",
+ value: ""
+ }
+ ],
+ validators: {
+ isRequired: false,
+ minLength: null,
+ maxLength: null,
+ custom: null
+ }
+ },
+ {
+ id: 4,
+ sortOrder: 4,
+ name: 'numberinput',
+ label: 'Campo Numerico',
+ description: "Per l'inserimento di valori numerici (quantità, importi, percentuali)",
+ settings: [
+ {
+ name: "label",
+ value: "Numero"
+ },
+ {
+ name: "placeholder",
+ value: 0
+ },
+ {
+ name: "step",
value: 0
}
],
@@ -283,43 +432,20 @@ export const elementItems = [
custom: null
}
},
- {
- id: 4,
- name: 'textinput',
- label: 'P.IVA',
- settings: [
- {
- name: "label",
- value: "P.IVA"
- },
- {
- name: "placeholder",
- value: "Insert p.iva number"
- }
- ],
- validators: {
- isRequired: true,
- minLength: null,
- maxLength: null,
- pattern: null,
- custom: 'isValidVAT'
- }
- },
{
id: 5,
+ sortOrder: 5,
name: 'radio',
- label: 'Radio Input',
+ label: 'Scelta Singola',
+ description: 'Gruppo di opzioni per selezione singola',
settings: [
{
name: "label",
- value: "Radio input"
+ value: "Scelta Singola"
},
{
name: "options",
- value: [
- { name: "opt1", label: "Opt1" },
- { name: "opt2", label: "Opt2" }
- ]
+ value: []
}
],
validators: {
@@ -329,19 +455,18 @@ export const elementItems = [
},
{
id: 6,
+ sortOrder: 6,
name: 'select',
- label: 'Select',
+ label: 'Menu a Tendina',
+ description: 'Selezione da opzioni predefinite',
settings: [
{
name: "label",
- value: "Select"
+ value: "Menu a Tendina"
},
{
name: "options",
- value: [
- { name: "opt1", label: "Opt1" },
- { name: "opt2", label: "Opt2" }
- ]
+ value: []
}
],
validators: {
@@ -351,21 +476,85 @@ export const elementItems = [
},
{
id: 7,
- name: 'datepicker',
- label: 'Datepicker',
+ sortOrder: 7,
+ name: 'checkboxes',
+ label: 'Scelta Multipla',
+ description: 'Gruppo di opzioni per selezione singola o multipla',
settings: [
{
name: "label",
- value: "Datepicker"
+ value: "Scelta Multipla"
+ },
+ {
+ name: "options",
+ value: []
+ }
+ ],
+ validators: {
+ isRequired: false,
+ min: null,
+ max: null,
+ custom: null
+ }
+ },
+ {
+ id: 8,
+ sortOrder: 8,
+ name: 'switch',
+ label: 'Casella di Spunta',
+ description: 'Per selezioni binarie, accettazioni, conferme',
+ settings: [
+ {
+ name: "label",
+ value: "Casella di Spunta"
+ }
+ ],
+ validators: {
+ isRequired: false
+ }
+ },
+ {
+ id: 9,
+ sortOrder: 9,
+ name: 'datepicker',
+ label: 'Data',
+ description: 'Selezione di data',
+ settings: [
+ {
+ name: "label",
+ value: "Data"
}
],
validators: {
isRequired: false,
custom: null
}
+ },
+ {
+ id: 10,
+ sortOrder: 10,
+ name: 'fileupload',
+ label: 'Caricamento File',
+ description: "Per l'upload di documenti o immagini",
+ settings: [
+ {
+ name: "label",
+ value: "Caricamento File"
+ },
+ {
+ name: "mime",
+ value: []
+ }
+ ],
+ validators: {
+ isRequired: false,
+ maxSize: 100000,
+ custom: null
+ }
}
]
+/*
const flowData = {
"initialForm":9,
"finalForm":13,
@@ -412,4 +601,4 @@ const flowData = {
"type":"smoothstep"
}
]
-}
\ No newline at end of file
+}*/
diff --git a/yarn.lock b/yarn.lock
index 4483843..6ca8478 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4962,6 +4962,11 @@ eventemitter3@^4.0.0:
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+eventemitter3@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz"
+ integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
+
events@^3.2.0:
version "3.3.0"
resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz"
@@ -5039,6 +5044,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+fast-diff@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz"
+ integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
+
fast-glob@^3.2.9, fast-glob@^3.3.0:
version "3.3.2"
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz"
@@ -6939,11 +6949,26 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
+lodash-es@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
+ integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
+lodash.clonedeep@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
+ integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
+
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
+lodash.isequal@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz"
+ integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
lodash.mapvalues@^4.6.0:
version "4.6.0"
resolved "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz"
@@ -7510,6 +7535,11 @@ param-case@^3.0.4:
dot-case "^3.0.4"
tslib "^2.0.3"
+parchment@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz"
+ integrity sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==
+
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
@@ -8331,6 +8361,25 @@ queue-microtask@^1.2.2:
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+quill-delta@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz"
+ integrity sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==
+ dependencies:
+ fast-diff "^1.3.0"
+ lodash.clonedeep "^4.5.0"
+ lodash.isequal "^4.5.0"
+
+quill@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/quill/-/quill-2.0.2.tgz"
+ integrity sha512-QfazNrhMakEdRG57IoYFwffUIr04LWJxbS/ZkidRFXYCQt63c1gK6Z7IHUXMx/Vh25WgPBU42oBaNzQ0K1R/xw==
+ dependencies:
+ eventemitter3 "^5.0.1"
+ lodash-es "^4.17.21"
+ parchment "^3.0.0"
+ quill-delta "^5.1.0"
+
raf@^3.4.1:
version "3.4.1"
resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz"