From eadb5959b5aeadca4d4e9c15dfb9aeeba1d42b23 Mon Sep 17 00:00:00 2001 From: Vitalii Kiiko Date: Thu, 19 Dec 2024 12:42:30 +0100 Subject: [PATCH] - saving progress; --- src/assets/scss/components/flowBuilder.scss | 18 +- src/pages/BandoFlowEdit/index.js | 450 +++++++++----------- 2 files changed, 203 insertions(+), 265 deletions(-) diff --git a/src/assets/scss/components/flowBuilder.scss b/src/assets/scss/components/flowBuilder.scss index c66987e..986665b 100644 --- a/src/assets/scss/components/flowBuilder.scss +++ b/src/assets/scss/components/flowBuilder.scss @@ -33,23 +33,26 @@ text-align: center; } } - .flowContainer { + width: 100%; + overflow-x: auto; + margin-top: 30px; +} + +.flowContainerInner { + position: relative; display: flex; flex-direction: column; - gap: 60px; - width: 100%; - margin-top: 30px; - overflow-x: auto; + width: max-content; } .flowContainer__level { display: flex; justify-content: center; gap: 20px; - padding: 10px 0; + padding: 0 0 60px; /*min-height: 240px;*/ - margin: 0 auto; + /*margin: 0 auto;*/ } .flowContainer__flowItem { @@ -82,6 +85,7 @@ width: 100%; max-width: 250px; border: 1px solid var(--panel-content-borderColor); + height: 100%; > label { display: flex; diff --git a/src/pages/BandoFlowEdit/index.js b/src/pages/BandoFlowEdit/index.js index d317aff..5a1b6a0 100644 --- a/src/pages/BandoFlowEdit/index.js +++ b/src/pages/BandoFlowEdit/index.js @@ -1,14 +1,14 @@ import React, { useEffect, useState, useCallback, useRef } from 'react'; import { __, sprintf } from '@wordpress/i18n'; import { useNavigate, useParams } from 'react-router-dom'; -import { isEmpty, head } from 'ramda'; -import LeaderLine from 'leader-line-new'; +import { isEmpty, head, pathOr } from 'ramda'; // store import { storeGet, storeSet, useStore } from '../../store'; // api import FormsService from '../../service/forms-service'; +import FlowService from '../../service/flow-service'; // tools import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; @@ -17,7 +17,6 @@ import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import { Button } from 'primereact/button'; import { Dropdown } from 'primereact/dropdown'; import { Messages } from 'primereact/messages'; -import FlowService from '../../service/flow-service'; import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup'; import { Toast } from 'primereact/toast'; @@ -29,8 +28,9 @@ const BandoFlowEdit = () => { const flowEdges = useStore().main.flowEdges(); const [formOptions, setFormOptions] = useState([]); const [initialForm, setInitialForm] = useState(0); - const [mainFieldOptions, setMainFieldOptions] = useState([]); - const [mainField, setMainField] = useState(''); + const [chosenMainFieldOptions, setChosenMainFieldOptions] = useState([]); + const [chosenMainField, setChosenMainField] = useState(''); + const [mainFieldSuboptions, setMainFieldSubOptions] = useState([]); const [bandoStatus, setBandoStatus] = useState(''); const [isFlowAllowed, setIsFlowAllowed] = useState(true); const [finalForm, setFinalForm] = useState(0); @@ -38,6 +38,7 @@ const BandoFlowEdit = () => { const toast = useRef(null); const [lines, setLines] = useState([]); const itemRefs = useRef({}); + const itemContainerRef = useRef(null); const getBandoId = () => { const parsed = parseInt(id) @@ -70,27 +71,69 @@ const BandoFlowEdit = () => { storeSet.main.flowData([]); storeSet.main.flowEdges([]); setInitialForm(0); - setMainFieldOptions([]); - setMainField(''); + setChosenMainFieldOptions([]); + setChosenMainField(''); setIsFlowAllowed(false); setFinalForm(0); + lines.forEach(line => line.remove()); } const updateInitialForm = (value) => { - setInitialForm(value); - if (forms.length === 2) { - const finalForm = head(forms.filter(o => o.id !== value)); - if (finalForm) { - setFinalForm(finalForm.id); + if (value !== finalForm) { + setInitialForm(value); + if (forms.length === 2) { + const finalForm = head(forms.filter(o => o.id !== value)); + if (finalForm) { + setFinalForm(finalForm.id); + } } } } + const updateFinalForm = (value) => { + if (value !== initialForm) { + setFinalForm(value); + } + } + + const updateItermediateForm = (value, formId) => { + const isUsed = flowData.map(o => o.chosenValue).filter(v => !isEmpty(v)).includes(value); + if (!isUsed) { + const data = { + formId: parseInt(formId), + chosenField: '', + chosenValue: value + } + storeSet.main.addFlowData(data); + } + } + + const displayChosenOptionValue = (id) => { + const suboptionId = pathOr('', ['chosenValue'], head(flowData.filter(f => parseInt(f.formId) === parseInt(id)))); + return pathOr('', ['label'], head(mainFieldSuboptions.filter(o => o.name === suboptionId))); + } + + const disabledOptionForIntermediateForm = (opt) => { + return flowData.map(o => o.chosenValue).filter(v => !isEmpty(v)).includes(opt.name); + } + const shoudDisableSaving = useCallback(() => { - return forms.length > 2 - ? isEmpty(flowData) || isEmpty(flowEdges) || isEmpty(initialForm) || isEmpty(finalForm) - || flowData.length < forms.length - 1 || 'PUBLISH' === bandoStatus - : isEmpty(flowEdges) || isEmpty(initialForm) || 'PUBLISH' === bandoStatus; + const flowForms = storeGet.main.flowForms(); + const nonEmptyFlowItems = flowData.filter(o => isEmpty(o.chosenField)).filter(o => !isEmpty(o.chosenValue)); + + /*if (flowForms.length > 2) { + console.log('disable BTN:', nonEmptyFlowItems.length !== flowForms.length - 2, isEmpty(flowEdges), 'PUBLISH' === bandoStatus, + isEmpty(initialForm), isEmpty(finalForm)); + } else { + console.log('disable BTN:', nonEmptyFlowItems.length !== 1, isEmpty(flowEdges), 'PUBLISH' === bandoStatus, + isEmpty(initialForm), isEmpty(finalForm)); + }*/ + + return flowForms.length > 2 + ? nonEmptyFlowItems.length !== flowForms.length - 2 || isEmpty(flowEdges) || 'PUBLISH' === bandoStatus + || isEmpty(initialForm) || isEmpty(finalForm) + : nonEmptyFlowItems.length !== 1 || isEmpty(flowEdges) || 'PUBLISH' === bandoStatus + || isEmpty(initialForm) || isEmpty(finalForm); }, [flowData, flowEdges]); const doSave = () => { @@ -134,7 +177,7 @@ const BandoFlowEdit = () => { setFormOptions([{ label: '', value: '' }, ...formOptions]); const bandoId = getBandoId(); storeSet.main.setAsyncRequest(); - FlowService.getFlow(bandoId, getFlowCallback, errGetFlowCallback); + FlowService.getFlow(bandoId, (resp) => getFlowCallback(resp, data.data), errGetFlowCallback); } storeSet.main.unsetAsyncRequest(); } @@ -144,7 +187,7 @@ const BandoFlowEdit = () => { storeSet.main.unsetAsyncRequest(); } - const getFlowCallback = (data) => { + const getFlowCallback = (data, forms) => { if (data.status === 'SUCCESS' && data.data) { storeSet.main.flowData(data.data.flowData); storeSet.main.flowEdges(data.data.flowEdges); @@ -153,12 +196,27 @@ const BandoFlowEdit = () => { setBandoStatus(data.data.callStatus); const chosenFieldItem = head(data.data.flowData.filter(o => !isEmpty(o.chosenField))); if (chosenFieldItem) { - setMainField(chosenFieldItem.chosenField); + setChosenMainField(chosenFieldItem.chosenField); + const form = head(forms.filter(o => o.id === data.data.initialForm)); + const relevantFields = form + ? form.content + .filter(o => ['radio', 'select'].includes(o.name)) + .map(o => { + const label = head(o.settings.filter(o => o.name === 'label')); + return { value: o.id, label: label ? label.value : o.label }; + }) + : []; + setChosenMainFieldOptions(relevantFields); + const field = form ? head(form.content.filter(o => o.id === chosenFieldItem.chosenField)) : null; + if (field) { + const options = head(field.settings.filter(o => o.name === 'options')); + setMainFieldSubOptions(options.value); + } } const flowDataItem = head(data.data.flowData.filter(o => !isEmpty(o.chosenField))); if (flowDataItem) { - setMainField(flowDataItem.chosenField); + setChosenMainField(flowDataItem.chosenField); } } storeSet.main.unsetAsyncRequest(); @@ -173,10 +231,54 @@ const BandoFlowEdit = () => { itemRefs.current[id] = element; }; + const buildFlowEdges = () => { + if (!isEmpty(initialForm) && !isEmpty(finalForm)) { + const flowForms = storeGet.main.flowForms(); + let edges = []; + // eslint-disable-next-line + flowForms.map(o => { + const formId = String(o.id); + + if (formId !== String(initialForm) && formId !== String(finalForm)) { + edges.push({ + id: `${initialForm}->${formId}`, + source: String(initialForm), + target: formId, + type: 'smoothstep' + }); + } + if (formId !== String(initialForm) && formId !== String(finalForm) && String(finalForm) !== '0') { + edges.push({ + id: `${formId}->${finalForm}`, + source: formId, + target: String(finalForm), + type: 'smoothstep' + }); + } + }); + + if (flowForms.length === 2 && initialForm && finalForm) { + edges.push({ + id: `${initialForm}->${finalForm}`, + source: String(initialForm), + target: String(finalForm), + type: 'smoothstep' + }); + } + + //console.log('edges', edges); + storeSet.main.flowEdges(edges); + } + } + useEffect(() => { + if ('PUBLISH' === bandoStatus) { + return; + } + storeSet.main.flowData([]); const flowForms = storeGet.main.flowForms(); const form = head(flowForms.filter(o => String(o.id) === String(initialForm))) - const field = form ? head(form.content.filter(o => o.id === mainField)) : null; + const field = form ? head(form.content.filter(o => o.id === chosenMainField)) : null; let options = []; if (field) { @@ -185,21 +287,30 @@ const BandoFlowEdit = () => { if (field && options.value && options.value.length === flowForms.length - 2) { setIsFlowAllowed(true); + const suboptions = [ + { label: __('Nessun scelta', 'gepafin'), name: '' }, + ...options.value + ] + setMainFieldSubOptions(suboptions); const data = { - formId: String(initialForm), - chosenField: mainField, + formId: parseInt(initialForm), + chosenField: chosenMainField, chosenValue: '' } storeSet.main.addFlowData(data); + if (flowMsgs.current && !isEmpty(chosenMainField)) { + flowMsgs.current.clear(); + } } else { setIsFlowAllowed(false); + setFinalForm(''); let msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.'; if (flowForms.length - 2 === 1) { - msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzione.'; + msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.'; } - if (flowMsgs.current && !isEmpty(mainField)) { + if (flowMsgs.current && !isEmpty(chosenMainField)) { flowMsgs.current.clear(); flowMsgs.current.show([ { @@ -214,11 +325,16 @@ const BandoFlowEdit = () => { ]); } } - }, [mainField]); + }, [chosenMainField]); useEffect(() => { - setMainField(''); - setMainFieldOptions([]); + if ('PUBLISH' === bandoStatus) { + return; + } + storeSet.main.flowData([]); + setChosenMainField(''); + setMainFieldSubOptions([]); + setChosenMainFieldOptions([]); const flowForms = storeGet.main.flowForms(); const form = head(flowForms.filter(o => String(o.id) === String(initialForm))) const relevantFields = form @@ -229,188 +345,27 @@ const BandoFlowEdit = () => { return { value: o.id, label: label ? label.value : o.label }; }) : []; - setMainFieldOptions([ - {label: isEmpty(relevantFields) ? __('Nessun scelta', 'gepafin') : '', value: ''}, + setChosenMainFieldOptions([ + { label: isEmpty(relevantFields) ? __('Nessun scelta', 'gepafin') : '', value: '' }, ...relevantFields] ); if (flowForms.length === 2) { setIsFlowAllowed(true) } + + buildFlowEdges(); }, [initialForm]); - /*useEffect(() => { - const flowForms = storeGet.main.flowForms(); - const form = head(flowForms.filter(o => String(o.id) === String(initialForm))) - const field = form ? head(form.content.filter(o => o.id === mainField)) : null; - let options = []; - - if (initialForm === 0) { - return; - } - - if (field) { - options = head(field.settings.filter(o => o.name === 'options')); - } - //console.log('isFlowAllowed', initialForm, mainField, field) - if (forms.length === 2 || (field && options.value && options.value.length === flowForms.length - 2)) { - setIsFlowAllowed(true); - const data = { - formId: String(initialForm), - chosenField: mainField, - chosenValue: '' - } - storeSet.main.addFlowData(data); + useEffect(() => { + if ('PUBLISH' === bandoStatus) { } else { - setIsFlowAllowed(false); - let msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.'; - - if (flowForms.length - 2 === 1) { - msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzione.'; - } - - if (flowMsgs.current && !isEmpty(mainField)) { - flowMsgs.current.clear(); - flowMsgs.current.show([ - { - id: '1', - sticky: true, severity: 'error', summary: '', - detail: sprintf( - __(msg, 'gepafin'), - flowForms.length - 2 - ), - closable: false - } - ]); - } - } - }, [mainField]); - - useEffect(() => { - setMainField(''); - setMainFieldOptions([]); - storeSet.main.flowData([]); - - const flowForms = storeGet.main.flowForms(); - const initialFormObj = head(flowForms.filter(o => String(o.id) === String(initialForm))); - let finalFormObj = null; - - if (!initialFormObj) { - return; - } - - const relevantFields = initialFormObj - ? initialFormObj.content - .filter(o => ['radio', 'select'].includes(o.name)) - .map(o => { - const label = head(o.settings.filter(o => o.name === 'label')); - return { value: o.id, label: label ? label.value : o.label }; - }) - : []; - setMainFieldOptions([ - { label: isEmpty(relevantFields) ? __('Nessun scelta', 'gepafin') : '', value: '' }, - ...relevantFields] - ); - - if (finalForm) { - finalFormObj = head(flowForms.filter(o => String(o.id) !== String(finalForm))); - } - - const flowItem1 = { - formId: String(initialFormObj.id), - chosenField: '', - chosenValue: '' - } - storeSet.main.addFlowData(flowItem1); - - if (flowForms.length === 2) { - setIsFlowAllowed(true); - finalFormObj = head(flowForms.filter(o => String(o.id) !== String(initialForm))); - //console.log('finalFormObj', finalFormObj); - setFinalForm(finalFormObj.id); - const flowItem2 = { - formId: String(finalFormObj.id), - chosenField: '', - chosenValue: '' - } - storeSet.main.addFlowData(flowItem2); - - const edge = { - id: `${initialFormObj.id}->${finalFormObj.id}`, - source: String(initialFormObj.id), - target: finalFormObj.id, - type: 'smoothstep' - } - storeSet.main.flowEdges([edge]); - } - - /!*lines.forEach(line => line.remove()); - - // Create new lines between consecutive items - const newLines = []; - console.log('itemRefs.current', itemRefs.current); - for (let i = 0; i < forms.length - 1; i++) { - const startElement = itemRefs.current[forms[i].id]; - const endElement = itemRefs.current[forms[i + 1].id]; - console.log('startElement', startElement, endElement); - if (startElement && endElement) { - const line = new LeaderLine( - startElement, - endElement, - { - color: '#2196F3', - size: 1 - } - ); - newLines.push(line); - } - } - - setLines(newLines);*!/ - }, [initialForm]); - - useEffect(() => { - const flowForms = storeGet.main.flowForms(); - const finalFormObj = head(flowForms.filter(o => String(o.id) === String(finalForm))); - - if (finalFormObj) { - const flowItem = { - formId: String(finalFormObj.id), - chosenField: '', - chosenValue: '' - } - storeSet.main.addFlowData(flowItem); - - const initialFormObj = head(flowForms.filter(o => String(o.id) === String(initialForm))); - const edge = { - id: `${initialFormObj.id}->${finalFormObj.id}`, - source: String(initialFormObj.id), - target: finalFormObj.id, - type: 'smoothstep' - } - storeSet.main.flowEdges([edge]); - - if (flowForms.length > 2) { - flowForms - .filter(o => ![initialForm, finalForm].includes(o.id)) - .map(o => { - const flowItem = { - formId: String(o.id), - chosenField: '', - chosenValue: '' - } - storeSet.main.addFlowData(flowItem); - }); - } + const filtered = flowData.filter(o => o.formId === initialForm); + storeSet.main.flowData(filtered); + buildFlowEdges(); } }, [finalForm]); - useEffect(() => { - return () => { - lines.forEach(line => line.remove()); - }; - }, [lines]);*/ - useEffect(() => { const bandoId = getBandoId(); storeSet.main.setAsyncRequest(); @@ -418,6 +373,7 @@ const BandoFlowEdit = () => { }, [id]); useEffect(() => { + console.log(forms) if (flowMsgs.current && forms.length < 2) { flowMsgs.current.clear(); flowMsgs.current.show([ @@ -430,13 +386,16 @@ const BandoFlowEdit = () => { ]); } else { flowMsgs.current.clear(); + if (itemContainerRef.current) { + itemContainerRef.current.dispatchEvent(new Event('scroll')); + } } }, [forms]); useEffect(() => { const chosenFieldItem = head(flowData.filter(o => !isEmpty(o.chosenField))); if (chosenFieldItem) { - setMainField(chosenFieldItem.chosenField); + setChosenMainField(chosenFieldItem.chosenField); } }, [flowData]) @@ -452,8 +411,8 @@ const BandoFlowEdit = () => { const finalFormData = head(forms.filter(o => o.id === finalForm)); const levelForms = forms.filter(o => o.id !== initialForm && o.id !== finalForm); - console.log('isFlowAllowed', isFlowAllowed, flowData, flowEdges); - console.log('mainField', mainField) + //console.log('isFlowAllowed', isFlowAllowed, flowData, flowEdges); + //console.log('forms:', initialForm, finalForm, chosenMainField, chosenMainFieldOptions) return (
@@ -481,29 +440,29 @@ const BandoFlowEdit = () => { placeholder={__('Scegli il form', 'gepafin')}/>
- {forms.length > 2 && initialForm && mainFieldOptions + {forms.length > 2 && initialForm && chosenMainFieldOptions ?
- + setMainField(e.value)} + value={chosenMainField} + onChange={(e) => setChosenMainField(e.value)} optionDisabled={(opt) => isEmpty(opt.value)} - options={mainFieldOptions} + options={chosenMainFieldOptions} optionLabel="label" optionValue="value" placeholder={__('Scegli il campo', 'gepafin')}/>
: null} - {(forms.length > 2 && mainField && isFlowAllowed) || (forms.length === 2 && isFlowAllowed) + {(forms.length > 2 && chosenMainField && isFlowAllowed) || (forms.length === 2 && isFlowAllowed) ?
setFinalForm(e.value)} + onChange={(e) => updateFinalForm(e.value)} optionDisabled={(opt) => initialForm === opt.value || isEmpty(opt.value)} options={formOptions} optionLabel="label" @@ -513,7 +472,7 @@ const BandoFlowEdit = () => {
- {/*
+
-
*/} +
{forms.length >= 2 && initialForm && finalForm - ?
+ ?
+
-
initialForm ? setItemRef(initialForm, el) : null}>
-
@@ -574,10 +506,24 @@ const BandoFlowEdit = () => { ?
{levelForms.map(o =>
setItemRef(o.id, el)} - className="flowContainer__flowItem levelForms" > + className="flowContainer__flowItem levelForms">
- +
+ {mainFieldSuboptions && !isEmpty(mainFieldSuboptions) + ? 'PUBLISH' !== bandoStatus + ? f.formId === parseInt(o.id))))} + onChange={(e) => updateItermediateForm(e.value, o.id)} + options={mainFieldSuboptions} + optionDisabled={disabledOptionForIntermediateForm} + optionLabel="label" + optionValue="name" + placeholder={__('Scegli il valore', 'gepafin')}/> + : + + : null}
)} @@ -588,26 +534,14 @@ const BandoFlowEdit = () => {
finalForm ? setItemRef(finalForm, el) : null}>
-
: null} +
: null}