Merge pull request #30 from Kitzanos/feature/46-forms-flow-preview

Feature/46 forms flow preview
This commit is contained in:
Vitalii Kiiko
2025-01-10 12:20:03 +01:00
committed by GitHub
11 changed files with 616 additions and 181 deletions

View File

@@ -4,38 +4,38 @@
"private": true,
"dependencies": {
"@babel/plugin-proposal-private-property-in-object": "7.21.11",
"@babel/preset-react": "7.24.7",
"@date-fns/tz": "1.1.2",
"@emailjs/browser": "^4.4.1",
"@emotion/styled": "11.13.0",
"@babel/preset-react": "7.25.9",
"@date-fns/tz": "1.2.0",
"@emailjs/browser": "4.4.1",
"@emotion/styled": "11.13.5",
"@number-flow/react": "0.4.2",
"@sentry/browser": "^8.42.0",
"@stomp/stompjs": "^7.0.0",
"@tanstack/react-table": "^8.20.5",
"@wordpress/i18n": "5.8.0",
"@wordpress/react-i18n": "4.8.0",
"@xyflow/react": "12.3.1",
"@wordpress/i18n": "5.13.0",
"@wordpress/react-i18n": "4.13.0",
"codice-fiscale-js": "2.3.22",
"copy-to-clipboard": "^3.3.3",
"deep-object-diff": "^1.1.9",
"dompurify": "3.1.7",
"copy-to-clipboard": "3.3.3",
"deep-object-diff": "1.1.9",
"dompurify": "3.2.2",
"fast-deep-equal": "3.1.3",
"hotkeys-js": "^3.13.7",
"html-react-parser": "5.1.16",
"hotkeys-js": "3.13.7",
"html-react-parser": "5.1.18",
"jwt-decode": "4.0.0",
"klona": "2.0.6",
"leader-line-new": "1.1.9",
"luxon": "3.5.0",
"object-path-immutable": "4.1.2",
"primeicons": "7.0.0",
"primereact": "10.8.4",
"quill": "2.0.2",
"primereact": "10.8.5",
"quill": "2.0.3",
"ramda": "0.30.1",
"react": "18.3.1",
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.3.1",
"react-hook-form": "7.53.0",
"react-router-dom": "6.26.2",
"react-hook-form": "7.53.2",
"react-router-dom": "7.0.1",
"react-scripts": "5.0.1",
"sockjs-client": "^1.6.1",
"validate.js": "0.13.1",
@@ -43,14 +43,14 @@
"zustand-x": "3.0.4"
},
"devDependencies": {
"@babel/cli": "7.25.6",
"@babel/core": "7.25.2",
"@babel/plugin-syntax-jsx": "7.24.7",
"@wordpress/babel-plugin-makepot": "6.8.0",
"@babel/cli": "7.25.9",
"@babel/core": "7.26.0",
"@babel/plugin-syntax-jsx": "7.25.9",
"@wordpress/babel-plugin-makepot": "6.13.0",
"babel-plugin-macros": "3.1.0",
"node-wp-i18n": "^1.2.7",
"sass": "1.79.3",
"sass-loader": "16.0.2"
"node-wp-i18n": "1.2.7",
"sass": "1.81.0",
"sass-loader": "16.0.3"
},
"scripts": {
"start": "GENERATE_SOURCEMAP=false react-scripts start",

View File

@@ -33,3 +33,135 @@
text-align: center;
}
}
.flowContainer {
width: 100%;
overflow-x: auto;
margin-top: 30px;
}
.flowContainerInner {
position: relative;
display: flex;
flex-direction: column;
width: max-content;
margin: 0 auto;
}
.flowContainer__level {
display: flex;
justify-content: center;
gap: 20px;
/*min-height: 240px;*/
/*margin: 0 auto;*/
&.initialLevel {
padding: 0 0 30px;
}
&.intermediateLevel, &.finalLevel {
padding: 30px 0 30px;
}
&.intermediateLevel {
border-bottom: 1px solid var(--table-border-color);
border-top: 1px solid var(--table-border-color);
}
}
.flowContainer__flowItem {
position: relative;
display: flex;
flex-direction: column;
width: 280px;
min-width: 280px;
padding: 15px;
border: 1px solid var(--table-border-color);
z-index: 9;
.flowContainer__flowItemInner > label {
border-color: #757575;
background-color: #757575;
color: white;
}
&.initialForm, &.finalForm {
.flowContainer__flowItemInner > label {
border-color: var(--card-full-background-color-3);
background-color: var(--card-full-background-color-3);
color: white;
}
}
&.levelForms, &.initialForm {
&:after {
position: absolute;
bottom: -31px;
left: 50%;
content: '';
width: 1px;
height: 31px;
background-color: var(--table-border-color);
}
}
&.levelForms, &.finalForm {
&:before {
position: absolute;
top: -31px;
left: 50%;
content: '';
width: 1px;
height: 31px;
background-color: var(--table-border-color);
}
}
}
.flowContainer__levelMaskStart, .flowContainer__levelMaskEnd {
position: absolute;
width: 140px;
height: 100% ;
top: -1px;
background-color: white;
}
.flowContainer__levelMaskStart {
left: 0;
}
.flowContainer__levelMaskEnd {
right: 0;
}
.flowContainer__flowItemInner {
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
max-width: 250px;
border: 1px solid var(--panel-content-borderColor);
height: 100%;
> label {
display: flex;
justify-content: center;
padding: 10px;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px;
text-align: center;
}
}
.flowContainer__flowItemContent {
padding: 5px;
display: flex;
flex-direction: column;
.appForm__field {
margin-top: 10px;
label {
text-align: center;
}
}
}

View File

@@ -147,6 +147,14 @@
max-width: 100%;
}
.p-password.p-inputwrapper {
width: 100%;
> div, input {
width: 100%;
}
}
.p-inputgroup.flex-1 {
align-items: center;
}

View File

@@ -73,3 +73,9 @@
margin-right: 7px;
}
}
@media (max-width: 500px) {
.topBar__endContent {
flex-wrap: wrap;
}
}

View File

@@ -21,6 +21,7 @@
--message-warning-color: #cc8925;
--message-info-background: rgba(183, 183, 183, 0.7);
--message-info-color: #3B82F6;
--panel-content-borderColor: #E5E7EB;
--card-full-background-color-2: #EEC137;
--card-full-background-color-3: #FA8E42;

View File

@@ -0,0 +1,54 @@
import React from 'react';
import { classNames } from 'primereact/utils';
import { Controller } from 'react-hook-form';
import { Password } from 'primereact/password';
const PasswordField = ({
fieldName,
label,
control,
errors,
defaultValue,
config = {},
infoText = null,
inputgroup = false,
icon = null,
placeholder = '',
disabled = false,
onBlurFn = () => {
}
}) => {
const input = <Controller
name={fieldName}
control={control}
defaultValue={defaultValue}
rules={config}
render={({ field, fieldState }) => (
<Password
id={field.name}
disabled={disabled}
{...field}
value={field.value ? field.value : ''}
onBlur={onBlurFn}
placeholder={placeholder}
className={classNames({ 'p-invalid': fieldState.invalid })}
toggleMask />
)}/>
return (
<>
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
{label}{config.required || config.isRequired ? <span className="appForm__field--required">*</span> : null}
</label>
{inputgroup
? <div className="p-inputgroup">
<span className="p-inputgroup-addon">
{icon}
</span>
{input}
</div>
: input}
{infoText ? <small>{infoText}</small> : null}
</>)
}
export default PasswordField;

View File

@@ -16,6 +16,7 @@ import Wysiwyg from './components/Wysiwyg';
import Checkboxes from './components/Checkboxes';
import Fileupload from './components/Fileupload';
import Table from './components/Table';
import PasswordField from './components/PasswordField';
const FormField = (props) => {
const fields = {
@@ -31,7 +32,8 @@ const FormField = (props) => {
radio: Radio,
wysiwyg: Wysiwyg,
checkboxes: Checkboxes,
table: Table
table: Table,
password: PasswordField
}
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;

View File

@@ -1,13 +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 { isEmpty, head, pathOr } from 'ramda';
// store
import { storeGet, storeSet, useStore } from '../../store';
import { storeSet } from '../../store';
// api
import FormsService from '../../service/forms-service';
import FlowService from '../../service/flow-service';
// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
@@ -15,27 +16,33 @@ import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
// components
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';
import { Toast } from 'primereact/toast';
const BandoFlowEdit = () => {
const { id } = useParams();
const navigate = useNavigate();
const forms = useStore().main.flowForms();
const flowData = useStore().main.flowData();
const flowEdges = useStore().main.flowEdges();
const [flowStructure, setFlowStructure] = useState({
initialForm: 0,
finalForm: 0,
flowData: [],
flowEdges: [],
chosenField: ''
});
const [forms, setForms] = useState([]);
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(false);
const [finalForm, setFinalForm] = useState(0);
const [isFlowAllowed, setIsFlowAllowed] = useState(true);
const flowMsgs = useRef(null);
const toast = useRef(null);
const itemRefs = useRef({});
const itemContainerRef = useRef(null);
const getBandoId = () => {
const parsed = parseInt(id)
@@ -56,7 +63,8 @@ const BandoFlowEdit = () => {
defaultFocus: 'reject',
acceptClassName: 'p-button-danger',
accept: doDelete,
reject: () => {}
reject: () => {
}
});
};
@@ -64,46 +72,120 @@ const BandoFlowEdit = () => {
if (flowMsgs.current) {
flowMsgs.current.clear();
}
storeSet.main.flowData([]);
storeSet.main.flowEdges([]);
setInitialForm(0);
setMainFieldOptions([]);
setMainField('');
setFlowStructure({
initialForm: 0,
finalForm: 0,
flowData: [],
flowEdges: [],
chosenField: ''
})
setIsFlowAllowed(false);
setFinalForm(0);
setChosenMainFieldOptions([]);
}
const updateInitialForm = (value) => {
setInitialForm(value);
if (forms.length === 2) {
const finalForm = head(forms.filter(o => o.id !== value));
if (finalForm) {
setFinalForm(finalForm.id);
const updateInitialForm = useCallback((value) => {
const finalFormObj = head(forms.filter(o => o.id !== value));
if (forms.length === 2 && finalFormObj) {
setFlowStructure({
...flowStructure,
initialForm: value,
finalForm: finalFormObj.id
});
} else {
setFlowStructure({
...flowStructure,
initialForm: value
});
}
}, [flowStructure])
const updateFinalForm = useCallback((value) => {
const filtered = flowStructure.flowData.filter(o => o.formId === flowStructure.initialForm);
const flowEdges = buildFlowEdges(flowStructure.initialForm, value);
setFlowStructure({
...flowStructure,
flowEdges,
flowData: filtered,
finalForm: value
});
}, [flowStructure]);
const updateChosenField = useCallback((value) => {
setFlowStructure({
...flowStructure,
chosenField: value
});
}, [flowStructure]);
const addFlowData = useCallback((data) => {
const initial = flowStructure.flowData;
const exists = initial ? initial.filter(o => parseInt(o.formId) === parseInt(data.formId)) : [];
let final = [];
if (exists.length) {
final = initial.map(o => parseInt(o.formId) === parseInt(data.formId) ? data : o);
} else {
final = [...initial, data];
}
setFlowStructure({
...flowStructure,
flowData: final
});
}, [flowStructure]);
const updateItermediateForm = (value, formId) => {
const isUsed = flowStructure.flowData.map(o => o.chosenValue).filter(v => !isEmpty(v)).includes(value);
if (!isUsed) {
const data = {
formId: parseInt(formId),
chosenField: '',
chosenValue: value
}
addFlowData(data);
}
}
const displayChosenOptionValue = (id) => {
const suboptionId = pathOr('', ['chosenValue'], head(flowStructure.flowData.filter(f => parseInt(f.formId) === parseInt(id))));
return pathOr('', ['label'], head(mainFieldSuboptions.filter(o => o.name === suboptionId)));
}
const disabledOptionForIntermediateForm = (opt) => {
return flowStructure.flowData.map(o => o.chosenValue).filter(v => !isEmpty(v)).includes(opt.name);
}
const shoudDisableSaving = useCallback(() => {
const nonEmptyFlowItems = flowStructure.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 forms.length > 2
? isEmpty(flowData) || isEmpty(flowEdges) || isEmpty(initialForm) || isEmpty(finalForm)
|| flowData.length < forms.length - 1 || 'PUBLISH' === bandoStatus
: isEmpty(flowEdges) || isEmpty(initialForm) || 'PUBLISH' === bandoStatus;
}, [flowData, flowEdges]);
? nonEmptyFlowItems.length !== forms.length - 2 || isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm)
: nonEmptyFlowItems.length !== 1 || isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm);
}, [flowStructure, forms]);
const 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);
FlowService.createFlow(bandoId, flowStructure, getFlowCreateCallback, errGetFlowCreateCallback);
}
const getFlowCreateCallback = (data) => {
@@ -126,12 +208,13 @@ const BandoFlowEdit = () => {
const getFormsCallback = (data) => {
if (data.status === 'SUCCESS') {
setForms(data.data);
const formOptions = data.data.map(o => ({ label: o.label, value: o.id }))
storeSet.main.flowForms(data.data);
setFormOptions([{label: '', value: ''}, ...formOptions]);
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();
}
@@ -141,21 +224,42 @@ 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);
setInitialForm(data.data.initialForm);
setFinalForm(data.data.finalForm);
setBandoStatus(data.data.callStatus);
const chosenFieldItem = head(data.data.flowData.filter(o => !isEmpty(o.chosenField)));
if (chosenFieldItem) {
setMainField(chosenFieldItem.chosenField);
}
const flowDataItem = head(data.data.flowData.filter(o => !isEmpty(o.chosenField)));
setBandoStatus(data.data.callStatus);
if (flowDataItem) {
setMainField(flowDataItem.chosenField);
if (chosenFieldItem) {
setFlowStructure({
initialForm: data.data.initialForm,
finalForm: data.data.finalForm,
flowData: data.data.flowData,
flowEdges: data.data.flowEdges,
chosenField: 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);
}
} else {
setFlowStructure({
initialForm: data.data.initialForm,
finalForm: data.data.finalForm,
flowData: data.data.flowData,
flowEdges: data.data.flowEdges,
chosenField: ''
});
}
}
storeSet.main.unsetAsyncRequest();
@@ -166,71 +270,48 @@ const BandoFlowEdit = () => {
storeSet.main.unsetAsyncRequest();
}
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 = [];
const setItemRef = (id, element) => {
itemRefs.current[id] = element;
};
if (field) {
options = head(field.settings.filter(o => o.name === 'options'));
}
const buildFlowEdges = (initialForm, finalForm) => {
let edges = [];
if (field && options.value && options.value.length === flowForms.length - 2) {
setIsFlowAllowed(true);
const data = {
formId: String(initialForm),
chosenField: mainField,
chosenValue: ''
}
storeSet.main.addFlowData(data);
} else {
setIsFlowAllowed(false);
let msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.';
if (!isEmpty(initialForm) && !isEmpty(finalForm)) {
// eslint-disable-next-line
forms.map(o => {
const formId = String(o.id);
if (flowForms.length - 2 === 1) {
msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzione.';
}
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 (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
}
]);
if (forms.length === 2 && initialForm && finalForm) {
edges.push({
id: `${initialForm}->${finalForm}`,
source: String(initialForm),
target: String(finalForm),
type: 'smoothstep'
});
}
}
}, [mainField]);
useEffect(() => {
setMainField('');
setMainFieldOptions([]);
const flowForms = storeGet.main.flowForms();
const form = head(flowForms.filter(o => String(o.id) === String(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 };
})
: [];
setMainFieldOptions([
{label: isEmpty(relevantFields) ? __('Nessun scelta', 'gepafin') : '', value: ''},
...relevantFields]
);
if (flowForms.length === 2) {
setIsFlowAllowed(true)
}
}, [initialForm]);
return edges;
};
useEffect(() => {
const bandoId = getBandoId();
@@ -251,23 +332,98 @@ 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);
}
}, [flowData])
const initialForm = flowStructure.initialForm;
const finalForm = flowStructure.finalForm;
const chosenField = flowStructure.chosenField;
useEffect(() => {
return () => {
storeSet.main.flowForms([]);
storeSet.main.flowData([]);
storeSet.main.flowEdges([]);
if (!isEmpty(initialForm) && !isEmpty(finalForm)) {
const form = head(forms.filter(o => String(o.id) === String(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([
{ label: isEmpty(relevantFields) ? __('Nessun scelta', 'gepafin') : '', value: '' },
...relevantFields]
);
if (forms.length === 2) {
setIsFlowAllowed(true);
}
//const flowEdges = buildFlowEdges(initialForm, finalForm);
if (!isEmpty(chosenField)) {
const field = form ? head(form.content.filter(o => o.id === chosenField)) : null;
let options = [];
if (field) {
options = head(field.settings.filter(o => o.name === 'options'));
}
if (field && options.value && options.value.length === forms.length - 2) {
setIsFlowAllowed(true);
const suboptions = [
{ label: __('Nessun scelta', 'gepafin'), name: '' },
...options.value
]
setMainFieldSubOptions(suboptions);
const data = {
formId: parseInt(initialForm),
chosenField: chosenField,
chosenValue: ''
}
addFlowData(data);
if (flowMsgs.current && !isEmpty(chosenField)) {
flowMsgs.current.clear();
}
} else {
setIsFlowAllowed(false);
let msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.';
if (forms.length - 2 === 1) {
msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.';
}
if (flowMsgs.current && !isEmpty(chosenField)) {
flowMsgs.current.clear();
flowMsgs.current.show([
{
id: '1',
sticky: true, severity: 'error', summary: '',
detail: sprintf(
__(msg, 'gepafin'),
forms.length - 2
),
closable: false
}
]);
}
}
}
}
}, []);
}, [flowStructure.initialForm, flowStructure.finalForm, flowStructure.chosenField]);
const { initialForm = 0, finalForm = 0, flowData = [], chosenField = '' } = flowStructure;
const initialFormData = head(forms.filter(o => o.id === initialForm));
const finalFormData = head(forms.filter(o => o.id === finalForm));
const levelForms = forms.filter(o => o.id !== initialForm && o.id !== finalForm);
return (
<div className="appPage">
@@ -296,29 +452,29 @@ const BandoFlowEdit = () => {
placeholder={__('Scegli il form', 'gepafin')}/>
</div>
{forms.length > 2 && initialForm && mainFieldOptions
{forms.length > 2 && initialForm && chosenMainFieldOptions
? <div className="appForm__field">
<label htmlFor="mainField">{__('Scegli il campo principale', 'gepafin')}</label>
<label htmlFor="chosenMainField">{__('Scegli il campo principale', 'gepafin')}</label>
<Dropdown
id="mainField"
id="chosenMainField"
disabled={'PUBLISH' === bandoStatus}
value={mainField}
onChange={(e) => setMainField(e.value)}
value={chosenField}
onChange={(e) => updateChosenField(e.value)}
optionDisabled={(opt) => isEmpty(opt.value)}
options={mainFieldOptions}
options={chosenMainFieldOptions}
optionLabel="label"
optionValue="value"
placeholder={__('Scegli il campo', 'gepafin')}/>
</div> : null}
{(forms.length > 2 && mainField && isFlowAllowed) || (forms.length === 2 && isFlowAllowed)
{(forms.length > 2 && chosenField && isFlowAllowed) || (forms.length === 2 && isFlowAllowed)
? <div className="appForm__field">
<label htmlFor="finalForm">{__('Scegli form finale', 'gepafin')}</label>
<Dropdown
id="finalForm"
disabled={'PUBLISH' === bandoStatus}
value={finalForm}
onChange={(e) => setFinalForm(e.value)}
onChange={(e) => updateFinalForm(e.value)}
optionDisabled={(opt) => initialForm === opt.value || isEmpty(opt.value)}
options={formOptions}
optionLabel="label"
@@ -343,11 +499,67 @@ const BandoFlowEdit = () => {
<div className="appPageSection">
<Messages ref={flowMsgs}/>
{forms.length >= 2 && isFlowAllowed
? <FlowBuilder
initialForm={initialForm}
finalForm={finalForm}
mainField={mainField}/> : null}
{forms.length >= 2 && initialForm && finalForm && isFlowAllowed
? <div className="flowContainer" ref={itemContainerRef}>
<div className="flowContainerInner">
<div className="flowContainer__level initialLevel">
<div className="flowContainer__flowItem initialForm"
ref={(el) => initialForm ? setItemRef(initialForm, el) : null}>
<div className="flowContainer__flowItemInner">
<label htmlFor="chosenMainField">
{initialFormData.label}
</label>
</div>
</div>
</div>
{levelForms.length && initialForm && finalForm
? <div className="flowContainer__level intermediateLevel">
{levelForms.map((o, i) => <div key={o.id}
ref={(el) => setItemRef(o.id, el)}
className="flowContainer__flowItem levelForms">
<div className="flowContainer__flowItemInner">
<label htmlFor="chosenMainField">{o.label}</label>
<div className="flowContainer__flowItemContent">
{mainFieldSuboptions && !isEmpty(mainFieldSuboptions)
? 'PUBLISH' !== bandoStatus
? <Dropdown
id="initialForm"
value={pathOr('', ['chosenValue'], head(flowData.filter(f => 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')}/>
:
<label>{displayChosenOptionValue(o.id)}</label>
: null}
</div>
</div>
</div>)}
{levelForms.length > 1
? <>
<div className="flowContainer__levelMaskEnd"></div>
<div className="flowContainer__levelMaskStart"></div>
</> : null}
</div> : null}
{forms.length >= 2 && initialForm && finalForm
? <div className="flowContainer__level finalLevel">
<div className="flowContainer__flowItem finalForm"
ref={(el) => finalForm ? setItemRef(finalForm, el) : null}>
<div className="flowContainer__flowItemInner">
<label htmlFor="chosenMainField">
{finalFormData.label}
</label>
</div>
</div>
</div>
: null}
</div>
</div> : null}
</div>
<div className="appPage__spacer"></div>

View File

@@ -1,9 +1,9 @@
import React, { useRef, useState, useEffect } from 'react';
import React, { useRef, useState, useEffect, useMemo } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useForm } from 'react-hook-form';
import { classNames } from 'primereact/utils';
import { isEmpty } from 'ramda';
import { useNavigate } from 'react-router-dom';
import { isEmpty, isNil } from 'ramda';
import { useNavigate, useSearchParams } from 'react-router-dom';
// tools
import AuthenticationService from '../../service/authentication-service';
@@ -24,7 +24,9 @@ const ResetPassword = () => {
const token = useStore().main.token();
const [loading, setLoading] = useState(false);
const [resetPassToken, setResetPassToken] = useState('');
const [resetPassEmail, setResetPassEmail] = useState('');
const errorMsgs = useRef(null);
let [searchParams] = useSearchParams();
const {
control,
handleSubmit,
@@ -47,12 +49,33 @@ const ResetPassword = () => {
}
if (request.token && !isEmpty(request.token)) {
AuthenticationService.resetPassword(request, getCallback, errCallback);
AuthenticationService.resetPassword(request, getCallbackReset, errCallback);
} else {
AuthenticationService.forgotPassword(request, getCallback, errCallback);
}
};
const getCallbackReset = (data) => {
if (data.status === 'SUCCESS') {
errorMsgs.current.show([
{
sticky: true, severity: 'success', summary: '',
detail: data.message,
closable: true
}
]);
} else {
errorMsgs.current.show([
{
sticky: true, severity: 'error', summary: '',
detail: data.message,
closable: true
}
]);
}
setLoading(false);
}
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setResetPassToken(data.data)
@@ -87,9 +110,18 @@ const ResetPassword = () => {
}, [token]);
useEffect(() => {
setValue('token', resetPassToken);
console.log(resetPassToken, resetPassEmail);
reset();
}, [resetPassToken])
setValue('token', resetPassToken);
setValue('email', resetPassEmail);
}, [resetPassToken, resetPassEmail]);
useEffect(() => {
const token = searchParams.get('token');
const email = searchParams.get('email');
setResetPassToken(token);
setResetPassEmail(email);
}, [searchParams]);
return (
<div className={classNames(['appPage', 'appPageLogin'])}>
@@ -113,7 +145,7 @@ const ResetPassword = () => {
placeholder="sample@example.com"
/>
{!isEmpty(resetPassToken)
{resetPassToken && !isEmpty(resetPassToken)
? <input
type="hidden"
name="token"
@@ -122,10 +154,9 @@ const ResetPassword = () => {
})}
/> : null}
{!isEmpty(resetPassToken)
{resetPassToken && !isEmpty(resetPassToken)
? <FormField
type="textinput"
inputtype="password"
type="password"
fieldName="newPassword"
label={__('Password', 'gepafin')}
control={control}
@@ -138,9 +169,9 @@ const ResetPassword = () => {
}}
/> : null}
{!isEmpty(resetPassToken)
{resetPassToken && !isEmpty(resetPassToken)
? <FormField
type="textinput"
type="password"
inputtype="password"
fieldName="confirmPassword"
label={__('Conferma password', 'gepafin')}

View File

@@ -43,16 +43,5 @@ export const actionsBeta = (set, get, api) => ({
const newElements = newFields.toSpliced(hoverIndex, 0, prevFields[dragIndex]);
set.formElements(newElements);
}
},
addFlowData: (data) => {
const initial = get.flowData();
const exists = initial ? initial.filter(o => parseInt(o.formId) === parseInt(data.formId)) : [];
if (exists.length) {
const newData = initial.map(o => parseInt(o.formId) === parseInt(data.formId) ? data : o);
set.flowData(newData);
} else {
set.flowData([...initial, data]);
}
}
});