- finished new flow builder UI;

- fixed reset pass functionality;
This commit is contained in:
Vitalii Kiiko
2025-01-10 12:18:53 +01:00
parent a418548e45
commit f2f844d388
6 changed files with 138 additions and 164 deletions

View File

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

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

View File

@@ -1,10 +1,10 @@
import React, { useEffect, useState, useCallback, useRef } from 'react'; import React, { useEffect, useState, useCallback, useRef } from 'react';
import { __, sprintf } from '@wordpress/i18n'; import { __, sprintf } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { isEmpty, head, pathOr, isNil } from 'ramda'; import { isEmpty, head, pathOr } from 'ramda';
// store // store
import { storeGet, storeSet, useStore } from '../../store'; import { storeSet } from '../../store';
// api // api
import FormsService from '../../service/forms-service'; import FormsService from '../../service/forms-service';
@@ -28,14 +28,14 @@ const BandoFlowEdit = () => {
initialForm: 0, initialForm: 0,
finalForm: 0, finalForm: 0,
flowData: [], flowData: [],
flowWdges: [], flowEdges: [],
chosenField: '' chosenField: ''
}); });
const [forms, setForms] = useState([]); const [forms, setForms] = useState([]);
const [formOptions, setFormOptions] = useState([]); const [formOptions, setFormOptions] = useState([]);
const [chosenMainFieldOptions, setChosenMainFieldOptions] = useState([]); const [chosenMainFieldOptions, setChosenMainFieldOptions] = useState([]);
const [chosenMainField, setChosenMainField] = useState(''); //const [chosenMainField, setChosenMainField] = useState('');
const [mainFieldSuboptions, setMainFieldSubOptions] = useState([]); const [mainFieldSuboptions, setMainFieldSubOptions] = useState([]);
const [bandoStatus, setBandoStatus] = useState(''); const [bandoStatus, setBandoStatus] = useState('');
const [isFlowAllowed, setIsFlowAllowed] = useState(true); const [isFlowAllowed, setIsFlowAllowed] = useState(true);
@@ -77,7 +77,7 @@ const BandoFlowEdit = () => {
initialForm: 0, initialForm: 0,
finalForm: 0, finalForm: 0,
flowData: [], flowData: [],
flowWdges: [], flowEdges: [],
chosenField: '' chosenField: ''
}) })
@@ -85,7 +85,7 @@ const BandoFlowEdit = () => {
setChosenMainFieldOptions([]); setChosenMainFieldOptions([]);
} }
const updateInitialForm = (value) => { const updateInitialForm = useCallback((value) => {
const finalFormObj = head(forms.filter(o => o.id !== value)); const finalFormObj = head(forms.filter(o => o.id !== value));
if (forms.length === 2 && finalFormObj) { if (forms.length === 2 && finalFormObj) {
@@ -100,9 +100,9 @@ const BandoFlowEdit = () => {
initialForm: value initialForm: value
}); });
} }
} }, [flowStructure])
const updateFinalForm = (value) => { const updateFinalForm = useCallback((value) => {
const filtered = flowStructure.flowData.filter(o => o.formId === flowStructure.initialForm); const filtered = flowStructure.flowData.filter(o => o.formId === flowStructure.initialForm);
const flowEdges = buildFlowEdges(flowStructure.initialForm, value); const flowEdges = buildFlowEdges(flowStructure.initialForm, value);
@@ -112,7 +112,14 @@ const BandoFlowEdit = () => {
flowData: filtered, flowData: filtered,
finalForm: value finalForm: value
}); });
} }, [flowStructure]);
const updateChosenField = useCallback((value) => {
setFlowStructure({
...flowStructure,
chosenField: value
});
}, [flowStructure]);
const addFlowData = useCallback((data) => { const addFlowData = useCallback((data) => {
const initial = flowStructure.flowData; const initial = flowStructure.flowData;
@@ -227,7 +234,7 @@ const BandoFlowEdit = () => {
initialForm: data.data.initialForm, initialForm: data.data.initialForm,
finalForm: data.data.finalForm, finalForm: data.data.finalForm,
flowData: data.data.flowData, flowData: data.data.flowData,
flowWdges: data.data.flowWdges, flowEdges: data.data.flowEdges,
chosenField: chosenFieldItem.chosenField chosenField: chosenFieldItem.chosenField
}); });
const form = head(forms.filter(o => o.id === data.data.initialForm)); const form = head(forms.filter(o => o.id === data.data.initialForm));
@@ -250,7 +257,7 @@ const BandoFlowEdit = () => {
initialForm: data.data.initialForm, initialForm: data.data.initialForm,
finalForm: data.data.finalForm, finalForm: data.data.finalForm,
flowData: data.data.flowData, flowData: data.data.flowData,
flowWdges: data.data.flowWdges, flowEdges: data.data.flowEdges,
chosenField: '' chosenField: ''
}); });
} }
@@ -332,8 +339,9 @@ const BandoFlowEdit = () => {
}, [forms]); }, [forms]);
useEffect(() => { useEffect(() => {
console.log('updated flowStructure:', flowStructure); const initialForm = flowStructure.initialForm;
const { initialForm = 0, finalForm = 0, chosenField = '' } = flowStructure; const finalForm = flowStructure.finalForm;
const chosenField = flowStructure.chosenField;
if (!isEmpty(initialForm) && !isEmpty(finalForm)) { if (!isEmpty(initialForm) && !isEmpty(finalForm)) {
const form = head(forms.filter(o => String(o.id) === String(initialForm))) const form = head(forms.filter(o => String(o.id) === String(initialForm)))
@@ -351,10 +359,10 @@ const BandoFlowEdit = () => {
); );
if (forms.length === 2) { if (forms.length === 2) {
setIsFlowAllowed(true) setIsFlowAllowed(true);
} }
const flowEdges = buildFlowEdges(initialForm, finalForm); //const flowEdges = buildFlowEdges(initialForm, finalForm);
if (!isEmpty(chosenField)) { if (!isEmpty(chosenField)) {
const field = form ? head(form.content.filter(o => o.id === chosenField)) : null; const field = form ? head(form.content.filter(o => o.id === chosenField)) : null;
@@ -393,7 +401,7 @@ const BandoFlowEdit = () => {
msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.'; msg = 'Non è possibile creare il flusso. Il campo principale deve avere esattamente %s opzioni.';
} }
if (flowMsgs.current && !isEmpty(chosenMainField)) { if (flowMsgs.current && !isEmpty(chosenField)) {
flowMsgs.current.clear(); flowMsgs.current.clear();
flowMsgs.current.show([ flowMsgs.current.show([
{ {
@@ -410,131 +418,13 @@ const BandoFlowEdit = () => {
} }
} }
} }
}, [flowStructure]); }, [flowStructure.initialForm, flowStructure.finalForm, flowStructure.chosenField]);
/*useEffect(() => { const { initialForm = 0, finalForm = 0, flowData = [], chosenField = '' } = flowStructure;
const isAsyncRequest = storeGet.main.isAsyncRequest();
if ('PUBLISH' === bandoStatus || isAsyncRequest || isNil(initialForm)) {
return;
}
//storeSet.main.flowData([]);
setChosenMainField('');
console.log('suboptions3', [], initialForm)
setMainFieldSubOptions([]);
setChosenMainFieldOptions([]);
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 };
})
: [];
setChosenMainFieldOptions([
{ label: isEmpty(relevantFields) ? __('Nessun scelta', 'gepafin') : '', value: '' },
...relevantFields]
);
if (flowForms.length === 2) {
setIsFlowAllowed(true)
}
buildFlowEdges();
}, [initialForm]);
useEffect(() => {
const isAsyncRequest = storeGet.main.isAsyncRequest();
if (isAsyncRequest) {
return;
}
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 === chosenMainField)) : null;
let options = [];
if (field) {
options = head(field.settings.filter(o => o.name === 'options'));
}
if (field && options.value && options.value.length === flowForms.length - 2) {
setIsFlowAllowed(true);
const suboptions = [
{ label: __('Nessun scelta', 'gepafin'), name: '' },
...options.value
]
console.log('suboptions2', suboptions, initialForm)
setMainFieldSubOptions(suboptions);
const data = {
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 opzioni.';
}
if (flowMsgs.current && !isEmpty(chosenMainField)) {
flowMsgs.current.clear();
flowMsgs.current.show([
{
id: '1',
sticky: true, severity: 'error', summary: '',
detail: sprintf(
__(msg, 'gepafin'),
flowForms.length - 2
),
closable: false
}
]);
}
}
}, [chosenMainField]);
useEffect(() => {
const isAsyncRequest = storeGet.main.isAsyncRequest();
if (isAsyncRequest || isNil(finalForm)) {
return;
}
if ('PUBLISH' === bandoStatus) {
} else {
const filtered = flowData.filter(o => o.formId === initialForm);
storeSet.main.flowData(filtered);
buildFlowEdges();
}
}, [finalForm]);
useEffect(() => {
const isAsyncRequest = storeGet.main.isAsyncRequest();
if (isAsyncRequest) {
return;
}
const chosenFieldItem = head(flowData.filter(o => !isEmpty(o.chosenField)));
if (chosenFieldItem) {
setChosenMainField(chosenFieldItem.chosenField);
}
}, [flowData]);*/
const { initialForm = 0, finalForm = 0, flowData = [] } = flowStructure;
const initialFormData = head(forms.filter(o => o.id === initialForm)); const initialFormData = head(forms.filter(o => o.id === initialForm));
const finalFormData = head(forms.filter(o => o.id === finalForm)); const finalFormData = head(forms.filter(o => o.id === finalForm));
const levelForms = forms.filter(o => o.id !== initialForm && o.id !== finalForm); const levelForms = forms.filter(o => o.id !== initialForm && o.id !== finalForm);
console.log('mainFieldSuboptions', mainFieldSuboptions, flowStructure);
return ( return (
<div className="appPage"> <div className="appPage">
<div className="appPage__pageHeader"> <div className="appPage__pageHeader">
@@ -568,8 +458,8 @@ const BandoFlowEdit = () => {
<Dropdown <Dropdown
id="chosenMainField" id="chosenMainField"
disabled={'PUBLISH' === bandoStatus} disabled={'PUBLISH' === bandoStatus}
value={chosenMainField} value={chosenField}
onChange={(e) => setChosenMainField(e.value)} onChange={(e) => updateChosenField(e.value)}
optionDisabled={(opt) => isEmpty(opt.value)} optionDisabled={(opt) => isEmpty(opt.value)}
options={chosenMainFieldOptions} options={chosenMainFieldOptions}
optionLabel="label" optionLabel="label"
@@ -577,7 +467,7 @@ const BandoFlowEdit = () => {
placeholder={__('Scegli il campo', 'gepafin')}/> placeholder={__('Scegli il campo', 'gepafin')}/>
</div> : null} </div> : null}
{(forms.length > 2 && chosenMainField && isFlowAllowed) || (forms.length === 2 && isFlowAllowed) {(forms.length > 2 && chosenField && isFlowAllowed) || (forms.length === 2 && isFlowAllowed)
? <div className="appForm__field"> ? <div className="appForm__field">
<label htmlFor="finalForm">{__('Scegli form finale', 'gepafin')}</label> <label htmlFor="finalForm">{__('Scegli form finale', 'gepafin')}</label>
<Dropdown <Dropdown
@@ -610,7 +500,7 @@ const BandoFlowEdit = () => {
<div className="appPageSection"> <div className="appPageSection">
<Messages ref={flowMsgs}/> <Messages ref={flowMsgs}/>
{forms.length >= 2 && initialForm && finalForm {forms.length >= 2 && initialForm && finalForm && isFlowAllowed
? <div className="flowContainer" ref={itemContainerRef}> ? <div className="flowContainer" ref={itemContainerRef}>
<div className="flowContainerInner"> <div className="flowContainerInner">
<div className="flowContainer__level initialLevel"> <div className="flowContainer__level initialLevel">

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

View File

@@ -43,16 +43,5 @@ export const actionsBeta = (set, get, api) => ({
const newElements = newFields.toSpliced(hoverIndex, 0, prevFields[dragIndex]); const newElements = newFields.toSpliced(hoverIndex, 0, prevFields[dragIndex]);
set.formElements(newElements); 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]);
}
} }
}); });