From a8471ba7aa585d3b5c8c79c1f0335ff5c005e437 Mon Sep 17 00:00:00 2001 From: Vitalii Kiiko Date: Thu, 12 Sep 2024 17:17:48 +0200 Subject: [PATCH] updated form fields and application logic; --- package-lock.json | 58 +++ package.json | 1 + src/assets/scss/components/appPage.scss | 5 +- src/assets/scss/components/formBuilder.scss | 1 + src/assets/scss/components/layout.scss | 4 +- src/assets/scss/components/misc.scss | 7 + src/components/BlockingOverlay/index.js | 8 + .../components/NodeInitialForm/index.js | 16 +- src/components/FlowBuilder/index.js | 11 +- .../FormField/components/Checkboxes/index.js | 57 +++ .../FormField/components/Datepicker/index.js | 2 +- .../FormField/components/NumberInput/index.js | 9 +- .../FormField/components/Radio/index.js | 39 +- .../FormField/components/Select/index.js | 3 +- .../FormField/components/Switch/index.js | 2 +- .../FormField/components/TextArea/index.js | 2 +- .../FormField/components/TextInput/index.js | 2 +- .../FormField/components/Wysiwyg/index.js | 54 +++ src/components/FormField/index.js | 6 +- src/components/FormFieldRepeater/index.js | 9 +- .../FormFieldRepeaterCriteria/index.js | 22 +- .../components/AppSidebar/index.js | 2 +- src/pages/{Bids => Applications}/index.js | 14 +- .../Bandi/components/AllBandiTable/index.js | 2 +- src/pages/BandoApplication/index.js | 155 +++++++ .../components/BandoEditFormStep2/index.js | 5 +- src/pages/BandoEdit/index.js | 3 +- src/pages/BandoFlowEdit/index.js | 95 +++- .../components/ElementSetting/index.js | 28 ++ .../BuilderElementSettings/index.js | 16 +- .../components/FormBuilder/index.js | 3 + src/pages/BandoFormsEdit/index.js | 7 +- src/pages/BandoView/index.js | 26 +- src/pages/BandoViewBeneficiario/index.js | 271 ++++++++++++ .../components/LatestBandiTable/index.js | 27 +- .../components/LatestBandiTable/index.js | 172 ++++++++ .../MyLatestSubmissionsTable/index.js | 10 +- .../index.js | 8 +- src/routes.js | 16 +- src/service/flow-service.js | 14 + src/tempData.js | 413 +++++++++++++----- yarn.lock | 49 +++ 42 files changed, 1423 insertions(+), 231 deletions(-) create mode 100644 src/components/BlockingOverlay/index.js create mode 100644 src/components/FormField/components/Checkboxes/index.js create mode 100644 src/components/FormField/components/Wysiwyg/index.js rename src/pages/{Bids => Applications}/index.js (74%) create mode 100644 src/pages/BandoApplication/index.js create mode 100644 src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js create mode 100644 src/pages/BandoViewBeneficiario/index.js create mode 100644 src/pages/DashboardBeneficiario/components/LatestBandiTable/index.js rename src/pages/{DashboardBenefeciario => DashboardBeneficiario}/components/MyLatestSubmissionsTable/index.js (96%) rename src/pages/{DashboardBenefeciario => DashboardBeneficiario}/index.js (94%) create mode 100644 src/service/flow-service.js 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)} -
{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 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"/>