- saving progress;

This commit is contained in:
Vitalii Kiiko
2025-01-21 11:08:37 +01:00
parent 61763a961b
commit 07cecda529
23 changed files with 915 additions and 62 deletions

View File

@@ -1,10 +1,13 @@
import React, { useState, useEffect, useRef, useMemo } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useParams } from 'react-router-dom';
import { head, is, pluck, isEmpty, pathOr } from 'ramda';
import { head, is, pluck, isEmpty, pathOr, isNil } from 'ramda';
import { useForm } from 'react-hook-form';
import 'quill/dist/quill.core.css';
import { wrap } from 'object-path-immutable';
import { evaluate } from 'mathjs';
import equal from 'fast-deep-equal';
import { klona } from 'klona';
// store
import { storeSet, storeGet, useStore } from '../../store';
@@ -26,6 +29,10 @@ import {
import renderHtmlContent from '../../helpers/renderHtmlContent';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
import renderWithDataVars from '../../helpers/renderWithDataVars';
import getTokens from '../../helpers/getTokens';
import formatDateString from '../../helpers/formatDateString';
import isDateTimeInPast from '../../helpers/isDateTimeInPast';
// components
import { Skeleton } from 'primereact/skeleton';
@@ -39,8 +46,6 @@ import { Dialog } from 'primereact/dialog';
import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
import { defaultMaxFileSize } from '../../configData';
import formatDateString from '../../helpers/formatDateString';
import isDateTimeInPast from '../../helpers/isDateTimeInPast';
const BandoApplication = () => {
const chosenCompanyId = useStore().main.chosenCompanyId();
@@ -48,6 +53,8 @@ const BandoApplication = () => {
const [isExpired, setIsExpired] = useState(false);
const [formData, setFormData] = useState([]);
const [formInitialData, setFormInitialData] = useState(null);
const [fieldsWithVars, setFieldsWithVars] = useState({});
const [fieldsWithFormula, setFieldsWithFormula] = useState({});
const [bandoTitle, setBandoTitle] = useState('');
const [bandoId, setBandoId] = useState(0);
const [formId, setFormId] = useState('');
@@ -67,6 +74,7 @@ const BandoApplication = () => {
trigger,
register,
getValues,
watch,
reset
} = useForm({
defaultValues: useMemo(() => {
@@ -89,6 +97,7 @@ const BandoApplication = () => {
}
const activeStepIndex = activeStep - 1;
const values = getValues();
const formValues = watch();
const onValidate = () => {
const applId = getApplicationId();
@@ -342,6 +351,8 @@ const BandoApplication = () => {
dynamicData = wrap(dynamicData).set(['custom', 'userFullName'], userFullName).value();
const legalRepresentantName = company.isLegalRepresentant ? userFullName : '';
dynamicData = wrap(dynamicData).set(['custom', 'legalRepresentant'], legalRepresentantName).value();
let allvars = {};
let allformulas = {};
if (data.data.applicationFormResponse.content) {
// eslint-disable-next-line array-callback-return
@@ -349,7 +360,15 @@ const BandoApplication = () => {
if (o.dynamicData && !isEmpty(o.dynamicData)) {
formDataInitial[o.id] = pathOr('', o.dynamicData.split('.'), dynamicData);
}
})
const variable = head(o.settings.filter(o => o.name === 'variable'));
if (variable && !isEmpty(variable.value)) {
allvars[o.id] = variable.value[0];
}
const formula = head(o.settings.filter(o => o.name === 'formula'));
if (formula && !isEmpty(formula.value)) {
allformulas[o.id] = formula.value;
}
});
}
if (data.data.applicationFormResponse.formFields) {
@@ -366,6 +385,8 @@ const BandoApplication = () => {
}
reset();
setFieldsWithVars(allvars);
setFieldsWithFormula(allformulas);
setFormInitialData(formDataInitial);
}
storeSet.main.unsetAsyncRequest();
@@ -501,10 +522,45 @@ const BandoApplication = () => {
// TODO hardcoded for now
const signedDocMime = bandoId === 10
? ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime', '.pdf,application/pdf']
: ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime']
: ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime'];
const signedDocValidationString = bandoId === 10
? ['.p7m', '.pdf']
: ['.p7m']
: ['.p7m'];
useEffect(() => {
if (!isEmpty(fieldsWithVars) && !isEmpty(fieldsWithFormula)) {
const updatedFormValues = klona(formValues);
let context = {};
// eslint-disable-next-line array-callback-return
Object.keys(updatedFormValues).map(fieldId => {
if (!isNil(fieldsWithFormula[fieldId])) {
const formula = fieldsWithFormula[fieldId];
context = getTokens(formula)
.filter(v => !['false', 'null', 'true'].includes(v))
.reduce((acc, cur) => {
acc[cur] = isNil(context[cur]) ? 0 : context[cur];
return acc;
}, {});
const mathFormula = renderWithDataVars(formula, context);
try {
updatedFormValues[fieldId] = evaluate(mathFormula);
} catch (e) {
console.log('Error in math formula: "', mathFormula, '"', e.message);
updatedFormValues[fieldId] = 0;
}
}
if (!isNil(fieldsWithVars[fieldId])) {
context[fieldsWithVars[fieldId]] = updatedFormValues[fieldId]
}
});
if (!isEmpty(updatedFormValues) && !equal(updatedFormValues, formValues)) {
reset(updatedFormValues);
}
}
}, [formValues]);
useEffect(() => {
if ('SUBMIT' === applicationStatus) {
@@ -595,6 +651,7 @@ const BandoApplication = () => {
const tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
const step = head(o.settings.filter(o => o.name === 'step'));
const mime = head(o.settings.filter(o => o.name === 'mime'));
const formula = head(o.settings.filter(o => o.name === 'formula'));
let mimeValue = '';
if (mime) {
@@ -630,6 +687,7 @@ const BandoApplication = () => {
</div>
: <FormField
key={o.id}
readOnly={formula && !isEmpty(formula.value)}
type={o.name}
fieldName={o.id}
label={label ? label.value : ''}

View File

@@ -35,7 +35,6 @@ const BandoFlowEdit = () => {
const [forms, setForms] = useState([]);
const [formOptions, setFormOptions] = useState([]);
const [chosenMainFieldOptions, setChosenMainFieldOptions] = useState([]);
//const [chosenMainField, setChosenMainField] = useState('');
const [mainFieldSuboptions, setMainFieldSubOptions] = useState([]);
const [bandoStatus, setBandoStatus] = useState('');
const [isFlowAllowed, setIsFlowAllowed] = useState(true);
@@ -162,18 +161,18 @@ const BandoFlowEdit = () => {
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));
/*if (forms.length > 2) {
console.log('disable BTN:', nonEmptyFlowItems.length !== forms.length - 2, isEmpty(flowStructure.flowEdges), 'PUBLISH' === bandoStatus,
isEmpty(flowStructure.initialForm), isEmpty(flowStructure.finalForm));
} else {
console.log('disable BTN:', nonEmptyFlowItems.length !== 1, isEmpty(flowEdges), 'PUBLISH' === bandoStatus,
isEmpty(initialForm), isEmpty(finalForm));
console.log('disable BTN (2 forms):', isEmpty(flowStructure.flowEdges), 'PUBLISH' === bandoStatus,
isEmpty(flowStructure.initialForm), isEmpty(flowStructure.finalForm));
}*/
return forms.length > 2
? 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.flowEdges) || 'PUBLISH' === bandoStatus
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm);
}, [flowStructure, forms]);

View File

@@ -124,7 +124,7 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
<div className="meta">
<div className="tagHeader">
<Tag value={label} severity="info"/>
{name === 'numberinput'
{['numberinput', 'criteria_table'].includes(name)
? <Tag value="var" severity={isVariable}/> : null}
{name === 'numberinput'
? <Tag value="f(x)" severity={isFormula}/> : null}

View File

@@ -2,19 +2,23 @@ import React from 'react';
import { __ } from '@wordpress/i18n';
import { is } from 'ramda';
// tools
import renderHtmlContent from '../../../../../../helpers/renderHtmlContent';
// components
import ElementSettingRepeater from '../ElementSettingRepeater';
import { InputText } from 'primereact/inputtext';
import { MultiSelect } from 'primereact/multiselect';
import { Editor } from 'primereact/editor';
import { mimeTypes } from '../../../../../../configData';
import ElementSettingTableColumns from '../ElementSettingTableColumns';
import { InputSwitch } from 'primereact/inputswitch';
import ElementSettingChips from '../ElementSettingChips';
import ElementSettingCriteriaTableColumns from '../ElementSettingCriteriaTableColumns';
import { mimeTypes } from '../../../../../../configData';
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
const settingLabels = {
label: __('Label', 'gepafin'),
placeholder: __('Segnaposto', 'gepafin'),
@@ -25,10 +29,15 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
mime: __('Tipo di file', 'gepafin'),
text: __('Testo formattato', 'gepafin'),
table_columns: '',
criteria_table_columns: '',
variable: __('Variable (only letters and "_")', 'gepafin'),
formula: __('Auto calculation formula', 'gepafin')
}
const settingDescription = {
formula: __('Create formula using previously declared variables. Use these math operators: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>. Example of formula: <code>{entrate}+{assicurazione}</code>.', 'gepafin')
}
const renderHeader = () => {
return (
<span className="ql-formats">
@@ -84,6 +93,12 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
name={setting.name}
bandoStatus={bandoStatus}
setDataFn={updateDataFn}/>
} else if (setting.name === 'criteria_table_columns') {
return <ElementSettingCriteriaTableColumns
value={is(Object, setting.value) ? setting.value : {}}
name={setting.name}
bandoStatus={bandoStatus}
setDataFn={updateDataFn}/>
} else if (['isRequestedAmount', 'isDelegation'].includes(setting.name)) {
return <InputSwitch
checked={setting.value}
@@ -103,6 +118,10 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
return <div className="formElementSettings__field" key={setting.name}>
<label htmlFor={setting.name}>{settingLabels[setting.name]}</label>
{getProperField(setting)}
{settingDescription[setting.name]
? <div className="formElementSettings__fieldDescription">
<p>{renderHtmlContent(settingDescription[setting.name])}</p>
</div> : null}
</div>
}

View File

@@ -2,8 +2,9 @@ import React, { useState } from 'react';
// components
import { Chips } from 'primereact/chips';
import { isEmpty } from 'ramda';
const ElementSettingChips = ({ restrictedValues = [], changeFn, value }) => {
const ElementSettingChips = ({ restrictedValues = [], changeFn, value = [] }) => {
const [lastTyped, setLastTyped] = useState([])
const isValidValue = (newVal) => {
@@ -12,7 +13,7 @@ const ElementSettingChips = ({ restrictedValues = [], changeFn, value }) => {
};
const handleAdd = (e) => {
const newValue = e.value[e.value.length - 1];
const newValue = isEmpty(e.value) ? '' : e.value[e.value.length - 1];
if (restrictedValues.includes(newValue)) {
changeFn([]);

View File

@@ -0,0 +1,326 @@
import React, { useCallback, useEffect, useState } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { wrap } from 'object-path-immutable';
import { isEmpty, pathOr } from 'ramda';
// components
import { InputText } from 'primereact/inputtext';
import { Button } from 'primereact/button';
import { InputSwitch } from 'primereact/inputswitch';
// tools
import uniqid from '../../../../../../helpers/uniqid';
import { Dropdown } from 'primereact/dropdown';
import { Accordion, AccordionTab } from 'primereact/accordion';
const ElementSettingCriteriaTableColumns = ({
value,
name,
setDataFn,
bandoStatus
}) => {
const [stateFieldData, setStateFieldData] = useState([]);
const [rowsData, setRowsData] = useState([]);
const removeItem = (index) => {
let newData = stateFieldData
.toSpliced(index, 1)
newData = newData.map((o, i) => {
return i === newData.length - 1
? {...o, fieldtype: 'numeric', predefined: false, enableFormula: true}
: {...o, fieldtype: 'text', predefined: true, enableFormula: false}
});
setStateFieldData(newData);
}
const addNewItem = () => {
setStateFieldData([
...stateFieldData.map(o => ({...o, fieldtype: 'text', predefined: true, enableFormula: false})),
{ name: uniqid('o'), label: '', fieldtype: 'numeric', predefined: false, enableFormula: true }
]);
}
const addNewRow = () => {
const obj = stateFieldData
.filter(o => o.predefined)
.reduce((acc, cur) => {
acc[cur.name] = ''
return acc;
}, {});
setRowsData([...rowsData, obj]);
}
const removeRow = (index) => {
const newRowsData = wrap(rowsData).del([index]).value();
setRowsData(newRowsData);
}
const onInputChange = (e, index) => {
const { value } = e.target;
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.label = value;
}
return o;
})
setStateFieldData(newData);
}
const onLastRowInputChange = (e, index) => {
const { value } = e.target;
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.lastRowText = value;
}
return o;
})
setStateFieldData(newData);
}
const onTypeChange = (value, index) => {
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.fieldtype = value;
}
return o;
})
setStateFieldData(newData);
}
const onLastRowFormulaChange = (value, index) => {
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.lastRowFormula = value;
}
return o;
})
setStateFieldData(newData);
}
const onSubInputChange = (e, name, index) => {
const { value } = e.target;
const newRowsData = wrap(rowsData).set([index, name], value).value();
setRowsData(newRowsData);
}
const setChecked = (value, index) => {
let name = '';
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.predefined = value;
name = o.name;
}
return o;
});
let newRowsData = [];
if (value === false) {
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
} else {
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
}
setRowsData(newRowsData);
setStateFieldData(newData);
}
const setColFormulaChecked = (index) => {
const newData = stateFieldData.map((o, i) => {
if (i === index) {
const newVal = o.enableFormula !== true;
o.enableFormula = newVal;
if (newVal) {
o.lastRowFormula = 'sum';
o.fieldtype = 'numeric';
delete o.lastRowText;
} else {
delete o.lastRowFormula;
delete o.fieldtype;
o.lastRowText = '';
}
}
return o;
});
setStateFieldData(newData);
}
const handleClearLastRowData = useCallback(() => {
const newData = stateFieldData.map((o) => {
delete o.lastRowFormula;
o.lastRowText = '';
delete o.enableFormula;
return o;
});
setStateFieldData(newData);
}, [stateFieldData]);
const properFields = (item, i) => {
return <>
<div>
<InputText
value={item.label}
placeholder={sprintf(__('Colonna %d', 'gepafin'), i + 1)}
onInput={(e) => onInputChange(e, i)}/>
</div>
<div>
<Dropdown
disabled={true}
value={item.fieldtype ? item.fieldtype : 'text'}
onChange={(e) => onTypeChange(e.value, i)}
options={[
{ value: 'text', label: __('Testo', 'gepafin') },
{ value: 'numeric', label: __('Numerico', 'gepafin') }
]}/>
</div>
<div>
<button
disabled={true}
className="formElementSettings__repeaterItemIconBtn"
onClick={() => setColFormulaChecked(i)}
data-active={item.enableFormula ? item.enableFormula : false}
type="button">
<i className="pi pi-calculator"></i>
</button>
</div>
<div>
<InputSwitch
checked={item.predefined}
disabled={true}
onChange={(e) => setChecked(e.value, i)}/>
</div>
<div>
<Button icon="pi pi-times"
disabled={bandoStatus === 'PUBLISH'}
className="p-button-danger"
onClick={() => removeItem(i)}/>
</div>
</>
}
const properSubField = (item, i, name) => {
return <>
<div>
<InputText
value={item[name]}
onInput={(e) => onSubInputChange(e, name, i)}/>
</div>
<div>
<Button icon="pi pi-times"
className="p-button-danger"
onClick={() => removeRow(i)}/>
</div>
</>
}
const properFieldsLastRow = useCallback((item, i) => {
return <>
<div>
<span>{sprintf(__('Colonna %d'), i + 1)}</span>
</div>
{item.enableFormula
? <div>
<Dropdown
disabled={bandoStatus === 'PUBLISH'}
value={item.lastRowFormula}
onChange={(e) => onLastRowFormulaChange(e.value, i)}
options={[
{ value: 'sum', label: __('Somma automatica', 'gepafin') }
]}/>
</div>
: <div>
<InputText
value={item.lastRowText ? item.lastRowText : ''}
onInput={(e) => onLastRowInputChange(e, i)}/>
</div>}
</>
}, [stateFieldData]);
const lastRow = <div className="formElementSettings__repeater">
<div className="formElementSettings__lastRowHeader">
<div className="formElementSettings__lastRowHeaderTitle">
{__('Definisci ultima righa', 'gepafin')}
</div>
<Button type="button"
disabled={bandoStatus === 'PUBLISH'}
outlined
label={__('Pulisci', 'gepafin')}
iconPos="right"
icon="pi pi-refresh"
onClick={handleClearLastRowData}/>
</div>
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__lastRowItem">
{properFieldsLastRow(o, i)}
</div>)}
</div>;
useEffect(() => {
const stateFieldData = pathOr([], ['stateFieldData'], value);
setStateFieldData(stateFieldData);
const rowsData = pathOr([], ['rowsData'], value);
setRowsData(rowsData);
}, []);
useEffect(() => {
setDataFn(name, {
stateFieldData,
rowsData
});
}, [stateFieldData, rowsData]);
return (
<>
<div className="formElementSettings__repeater">
{stateFieldData.length > 0
? <div className="formElementSettings__repeaterItem">
<div>{__('Colonne', 'gepafin')}</div>
<div>{__('Tipo', 'gepafin')}</div>
<div>{__('Calcola', 'gepafin')}</div>
<div>{__('Predefinito?', 'gepafin')}</div>
<div></div>
</div> : null}
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
{properFields(o, i)}
</div>)}
<Button
type="button"
disabled={bandoStatus === 'PUBLISH'}
outlined
label={__('Aggiungi colonna', 'gepafin')}
onClick={addNewItem}/>
</div>
{stateFieldData
.filter(o => o.predefined).length > 0
? <div className="formElementSettings__subRepeaterWrapper">
<Accordion activeIndex={0}>
{stateFieldData
//.filter(o => o.predefined)
.map((o, i) =>
o.predefined
? <AccordionTab
key={i}
header={sprintf(__('Righe per colonna: %s'), !isEmpty(o.label) ? o.label : i + 1)}>
<div className="formElementSettings__subRepeaterWrapper">
{rowsData.map((c, k) => {
return <div key={k} className="formElementSettings__subRepeaterItem">
{properSubField(c, k, o.name)}
</div>
})}
<Button type="button"
outlined
disabled={bandoStatus === 'PUBLISH'}
label={__('Aggiungi una riga', 'gepafin')}
onClick={addNewRow}/>
</div>
</AccordionTab> : null)}
</Accordion>
</div>
: null}
{lastRow}
</>
)
}
export default ElementSettingCriteriaTableColumns;

View File

@@ -158,7 +158,7 @@ const ElementSettingTableColumns = ({
</div>
<div>
<Dropdown
disabled={item.enableFormula}
disabled={item.enableFormula || bandoStatus === 'PUBLISH'}
value={item.fieldtype ? item.fieldtype : 'text'}
onChange={(e) => onTypeChange(e.value, i)}
options={[
@@ -168,6 +168,7 @@ const ElementSettingTableColumns = ({
</div>
<div>
<button
disabled={bandoStatus === 'PUBLISH'}
className="formElementSettings__repeaterItemIconBtn"
onClick={() => setColFormulaChecked(i)}
data-active={item.enableFormula ? item.enableFormula : false}
@@ -193,11 +194,12 @@ const ElementSettingTableColumns = ({
const properSubField = (item, i, name) => {
return <>
<div>
<InputText value={item[name]} onInput={(e) => onSubInputChange(e, name, i)}/>
<InputText
value={item[name]}
onInput={(e) => onSubInputChange(e, name, i)}/>
</div>
<div>
<Button icon="pi pi-times"
disabled={bandoStatus === 'PUBLISH'}
className="p-button-danger"
onClick={() => removeRow(i)}/>
</div>
@@ -212,6 +214,7 @@ const ElementSettingTableColumns = ({
{item.enableFormula
? <div>
<Dropdown
disabled={bandoStatus === 'PUBLISH'}
value={item.lastRowFormula}
onChange={(e) => onLastRowFormulaChange(e.value, i)}
options={[
@@ -232,6 +235,7 @@ const ElementSettingTableColumns = ({
{__('Definisci ultima righa', 'gepafin')}
</div>
<Button type="button"
disabled={bandoStatus === 'PUBLISH'}
outlined
label={__('Pulisci', 'gepafin')}
iconPos="right"
@@ -271,8 +275,12 @@ const ElementSettingTableColumns = ({
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
{properFields(o, i)}
</div>)}
<Button type="button" disabled={bandoStatus === 'PUBLISH'} outlined
label={__('Aggiungi colonna', 'gepafin')} onClick={addNewItem}/>
<Button
type="button"
disabled={bandoStatus === 'PUBLISH'}
outlined
label={__('Aggiungi colonna', 'gepafin')}
onClick={addNewItem}/>
</div>
{stateFieldData
.filter(o => o.predefined).length > 0

View File

@@ -110,22 +110,6 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
return dynamicDataOptions[type] ?? [];
}
/*const searchDynamicTags = (event) => {
const type = activeElementData.name;
const available = dynamicDataOptions[type];
let filtered;
if (!event.query.trim().length) {
filtered = [...available];
} else {
filtered = available.filter((tag) => {
return tag.label.toLowerCase().startsWith(event.query.toLowerCase());
});
}
setFilteredDynamicDataOptions(filtered);
}*/
useEffect(() => {
const chosen = head(elements.filter(o => o.id === activeElement));
const elementItems = storeGet.main.elementItems();
@@ -163,11 +147,11 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
? settings
.filter(o => !['variable', 'formula'].includes(o.name))
.map((o) => <ElementSetting
key={o.name}
setting={o}
bandoStatus={bandoStatus}
changeFn={onChange}
updateDataFn={onUpdateOptions}/>)
key={o.name}
setting={o}
bandoStatus={bandoStatus}
changeFn={onChange}
updateDataFn={onUpdateOptions}/>)
: null}
{!isNil(dynamicDataOptions[activeElementData.name])
? <div className="formElementSettings__field">
@@ -250,18 +234,21 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
placeholder={__('Scegli', 'gepafin')}/>
</div>
</TabPanel>
<TabPanel header={__('Calculation', 'gepafin')}>
{settings
? settings
.filter(o => ['variable', 'formula'].includes(o.name))
.map((o) => <ElementSetting
key={o.name}
setting={o}
bandoStatus={bandoStatus}
changeFn={onChange}
updateDataFn={onUpdateOptions}/>)
: null}
</TabPanel>
{settings
&& settings
.filter(o => ['variable', 'formula'].includes(o.name)).length > 0
? <TabPanel header={__('Calculation', 'gepafin')}>
{settings
? settings
.filter(o => ['variable', 'formula'].includes(o.name))
.map((o) => <ElementSetting
key={o.name}
setting={o}
bandoStatus={bandoStatus}
changeFn={onChange}
updateDataFn={onUpdateOptions}/>)
: null}
</TabPanel> : null}
</TabView>
<Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>

View File

@@ -2,9 +2,11 @@ import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { klona } from 'klona';
import { head, isNil } from 'ramda';
import { head, isNil , isEmpty } from 'ramda';
import { useForm } from 'react-hook-form';
import 'quill/dist/quill.core.css';
import { evaluate } from 'mathjs';
import equal from 'fast-deep-equal';
// store
import { storeSet, useStore } from '../../store';
@@ -30,12 +32,16 @@ import {
isUrl, minChecks, maxChecks, nonEmptyTables
} from '../../helpers/validators';
import renderHtmlContent from '../../helpers/renderHtmlContent';
import renderWithDataVars from '../../helpers/renderWithDataVars';
import getTokens from '../../helpers/getTokens';
const BandoFormsPreview = () => {
const { id, formId } = useParams();
const navigate = useNavigate();
const [formData, setFormData] = useState([]);
const [formName, setFormName] = useState('');
const [fieldsWithVars, setFieldsWithVars] = useState({});
const [fieldsWithFormula, setFieldsWithFormula] = useState({});
const isAsyncRequest = useStore().main.isAsyncRequest();
const {
control,
@@ -43,9 +49,12 @@ const BandoFormsPreview = () => {
formState: { errors },
getValues,
register,
setValue
setValue,
watch,
reset
} = useForm({ defaultValues: {}, mode: 'onChange' });
const values = getValues();
const formValues = watch();
const validationFns = {
isPIVA,
isCodiceFiscale,
@@ -75,6 +84,23 @@ const BandoFormsPreview = () => {
if (data.status === 'SUCCESS') {
setFormName(data.data.label);
const elements = klona(data.data.content);
let allvars = {};
let allformulas = {};
// eslint-disable-next-line array-callback-return
elements.map((o) => {
const variable = head(o.settings.filter(o => o.name === 'variable'));
if (variable && !isEmpty(variable.value)) {
allvars[o.id] = variable.value[0];
}
const formula = head(o.settings.filter(o => o.name === 'formula'));
if (formula && !isEmpty(formula.value)) {
allformulas[o.id] = formula.value;
}
});
setFieldsWithVars(allvars);
setFieldsWithFormula(allformulas);
setFormData(elements);
}
storeSet.main.unsetAsyncRequest();
@@ -85,6 +111,41 @@ const BandoFormsPreview = () => {
storeSet.main.unsetAsyncRequest();
}
useEffect(() => {
if (!isEmpty(fieldsWithVars) && !isEmpty(fieldsWithFormula)) {
const updatedFormValues = klona(formValues);
let context = {};
// eslint-disable-next-line array-callback-return
Object.keys(updatedFormValues).map(fieldId => {
if (!isNil(fieldsWithFormula[fieldId])) {
const formula = fieldsWithFormula[fieldId];
context = getTokens(formula)
.filter(v => !['false', 'null', 'true'].includes(v))
.reduce((acc, cur) => {
acc[cur] = isNil(context[cur]) ? 0 : context[cur];
return acc;
}, {});
const mathFormula = renderWithDataVars(formula, context);
try {
updatedFormValues[fieldId] = evaluate(mathFormula);
} catch (e) {
console.log('Error in math formula: "', mathFormula, '"', e.message);
updatedFormValues[fieldId] = 0;
}
}
if (!isNil(fieldsWithVars[fieldId])) {
context[fieldsWithVars[fieldId]] = updatedFormValues[fieldId]
}
});
if (!isEmpty(updatedFormValues) && !equal(updatedFormValues, formValues)) {
reset(updatedFormValues);
}
}
}, [formValues]);
useEffect(() => {
const parsedFormId = parseInt(formId)
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
@@ -126,9 +187,13 @@ const BandoFormsPreview = () => {
const text = head(o.settings.filter(o => o.name === 'text'));
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
const options = head(o.settings.filter(o => o.name === 'options'));
const tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
let tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
if (!tableColumns) {
tableColumns = head(o.settings.filter(o => o.name === 'criteria_table_columns'));
}
const step = head(o.settings.filter(o => o.name === 'step'));
const mime = head(o.settings.filter(o => o.name === 'mime'));
const formula = head(o.settings.filter(o => o.name === 'formula'));
let mimeValue = '';
if (mime) {
@@ -162,6 +227,7 @@ const BandoFormsPreview = () => {
</div>
: <FormField
key={o.id}
readOnly={formula && !isEmpty(formula.value)}
type={o.name}
fieldName={o.id}
label={label ? label.value : ''}