- added new settings for call;
- added duplciate form field functionality to form builder; - added improvements to form builder; - fixed issue with saving data in evaluation;
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useDrag, useDrop } from 'react-dnd'
|
||||
import { ItemTypes } from '../ItemTypes';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { head, isEmpty } from 'ramda';
|
||||
import { klona } from 'klona';
|
||||
|
||||
// store
|
||||
import { storeSet, useStore } from '../../../../store';
|
||||
|
||||
// tools
|
||||
import uniqid from '../../../../helpers/uniqid';
|
||||
|
||||
// components
|
||||
import { Button } from 'primereact/button';
|
||||
import { Tag } from 'primereact/tag';
|
||||
@@ -19,6 +23,8 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
||||
const element = head(elements.filter(o => o.id === id));
|
||||
const [isVariable, setIsVariable] = useState('secondary');
|
||||
const [isFormula, setIsFormula] = useState('secondary');
|
||||
const [variableName, setVariableName] = useState('secondary');
|
||||
const [formulaName, setFormulaName] = useState('secondary');
|
||||
const [isRequestedAmount, setIsRequestedAmount] = useState(false);
|
||||
const [isDelegation, setIsDelegation] = useState(false);
|
||||
|
||||
@@ -97,6 +103,18 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
||||
storeSet.main.activeElement(id);
|
||||
}
|
||||
|
||||
const duplicateElement = useCallback((id) => {
|
||||
const duplicatedElement = head(elements.filter(o => o.id === id));
|
||||
|
||||
if (duplicatedElement) {
|
||||
const copyElement = klona(duplicatedElement);
|
||||
copyElement.id = uniqid();
|
||||
const originalIndex = elements.map(o => o.id).indexOf(id);
|
||||
const newElements = [...elements].toSpliced(originalIndex, 0, copyElement);
|
||||
storeSet.main.formElements(newElements);
|
||||
}
|
||||
}, [elements]);
|
||||
|
||||
const remove = (id) => {
|
||||
storeSet.main.removeElement(id);
|
||||
}
|
||||
@@ -112,10 +130,12 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
||||
|
||||
if (variable && !isEmpty(variable.value)) {
|
||||
setIsVariable('warning');
|
||||
setVariableName(variable.value)
|
||||
}
|
||||
|
||||
if (formula && !isEmpty(formula.value)) {
|
||||
setIsFormula('warning');
|
||||
setFormulaName(formula.value)
|
||||
}
|
||||
|
||||
if (isRequestedAmount && !isEmpty(isRequestedAmount.value) && isRequestedAmount.value) {
|
||||
@@ -137,9 +157,9 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
||||
<div className="tagHeader">
|
||||
<Tag value={label} severity="info"/>
|
||||
{['numberinput', 'criteria_table'].includes(name)
|
||||
? <Tag value="var" severity={isVariable}/> : null}
|
||||
? <Tag value="var" severity={isVariable} title={variableName}/> : null}
|
||||
{name === 'numberinput'
|
||||
? <Tag value="f(x)" severity={isFormula}/> : null}
|
||||
? <Tag value="f(x)" severity={isFormula} title={formulaName}/> : null}
|
||||
{isRequestedAmount
|
||||
? <Tag value="importo" severity={isRequestedAmount}/> : null}
|
||||
{isDelegation
|
||||
@@ -148,6 +168,7 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
||||
<BuilderElementProperLabel id={id} defaultLabel={label}/>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<Button icon="pi pi-clone" onClick={() => duplicateElement(id)} outlined severity="success"/>
|
||||
<Button icon="pi pi-cog" onClick={() => openSettings(id)} outlined severity="info"/>
|
||||
<Button icon="pi pi-trash" disabled={bandoStatus === 'PUBLISH'} onClick={() => remove(id)} outlined severity="danger"/>
|
||||
</div>
|
||||
|
||||
@@ -35,12 +35,13 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||
text: __('Testo formattato', 'gepafin'),
|
||||
table_columns: '',
|
||||
criteria_table_columns: '',
|
||||
variable: __('Variable (only letters and "_")', 'gepafin'),
|
||||
formula: __('Auto calculation formula', 'gepafin')
|
||||
variable: __('Variabile (lettere, cifre e "_"; il primo carattere deve essere una lettera!)', 'gepafin'),
|
||||
formula: __('Formula di calcolo automatico', 'gepafin'),
|
||||
isChecklistItem: __('Fa parte di "checklist"?', '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')
|
||||
formula: __('Crea una formula usando variabili dichiarate in precedenza. Utilizza questi operatori matematici: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>. Esempio: <code>{entrate}+{assicurazione}</code>.', 'gepafin')
|
||||
}
|
||||
|
||||
const renderHeader = () => {
|
||||
@@ -104,7 +105,7 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||
name={setting.name}
|
||||
bandoStatus={bandoStatus}
|
||||
setDataFn={updateDataFn}/>
|
||||
} else if (['isRequestedAmount', 'isDelegation'].includes(setting.name)) {
|
||||
} else if (['isRequestedAmount', 'isDelegation', 'isChecklistItem'].includes(setting.name)) {
|
||||
return <InputSwitch
|
||||
checked={setting.value}
|
||||
onChange={(e) => changeFn(e.value, setting.name)}/>
|
||||
|
||||
@@ -8,7 +8,7 @@ const ElementSettingChips = ({ restrictedValues = [], changeFn, value = [] }) =>
|
||||
const [lastTyped, setLastTyped] = useState([])
|
||||
|
||||
const isValidValue = (newVal) => {
|
||||
const validationRegex = /^[a-zA-Z_]+$/;
|
||||
const validationRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
||||
return validationRegex.test(newVal);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { MultiSelect } from 'primereact/multiselect';
|
||||
|
||||
import { dynamicDataOptions } from '../../../../configData';
|
||||
|
||||
const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
||||
const BuilderElementSettings = ({ closeSettingsFn, callStatus, context }) => {
|
||||
const elements = useStore().main.formElements();
|
||||
const activeElement = useStore().main.activeElement();
|
||||
const criteriaOptions = useStore().main.bandoCriteria();
|
||||
@@ -123,6 +123,10 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
||||
});
|
||||
}
|
||||
|
||||
settings = settings.filter(o => context === 'call'
|
||||
? !['isRequestedAmount', 'isDelegation'].includes(o.name)
|
||||
: !['isChecklistItem'].includes(o.name));
|
||||
|
||||
if (chosen) {
|
||||
setActiveElementData(klona(chosen));
|
||||
setSettings(settings);
|
||||
@@ -149,7 +153,7 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
||||
.map((o) => <ElementSetting
|
||||
key={o.name}
|
||||
setting={o}
|
||||
bandoStatus={bandoStatus}
|
||||
callStatus={callStatus}
|
||||
changeFn={onChange}
|
||||
updateDataFn={onUpdateOptions}/>)
|
||||
: null}
|
||||
@@ -220,7 +224,8 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
||||
</div> : null}
|
||||
</div>) : null}
|
||||
</TabPanel> : null}
|
||||
<TabPanel header={__('Criteri', 'gepafin')}>
|
||||
{context === 'application'
|
||||
? <TabPanel header={__('Criteri', 'gepafin')}>
|
||||
<div className="formElementSettings__field">
|
||||
<label htmlFor="criteria">{__('Criteri di valutazione', 'gepafin')}</label>
|
||||
<MultiSelect
|
||||
@@ -233,25 +238,28 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
||||
display="chip"
|
||||
placeholder={__('Scegli', 'gepafin')}/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</TabPanel> : null}
|
||||
{settings
|
||||
&& settings
|
||||
.filter(o => ['variable', 'formula'].includes(o.name)).length > 0
|
||||
? <TabPanel header={__('Calculation', 'gepafin')}>
|
||||
? <TabPanel header={__('Calcolo', 'gepafin')}>
|
||||
{settings
|
||||
? settings
|
||||
.filter(o => ['variable', 'formula'].includes(o.name))
|
||||
.map((o) => <ElementSetting
|
||||
key={o.name}
|
||||
setting={o}
|
||||
bandoStatus={bandoStatus}
|
||||
callStatus={callStatus}
|
||||
changeFn={onChange}
|
||||
updateDataFn={onUpdateOptions}/>)
|
||||
: null}
|
||||
</TabPanel> : null}
|
||||
</TabView>
|
||||
|
||||
<Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>
|
||||
<div style={{display: 'flex', gap: '0.5rem'}}>
|
||||
<Button label={__('Annulla', 'gepafin')} onClick={closeSettingsFn} severity="danger"/>
|
||||
<Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ import BuilderElementSettings from '../BuilderElementSettings';
|
||||
import BuilderDropzone from '../BuilderDropzone';
|
||||
import BlockingOverlay from '../../../../components/BlockingOverlay';
|
||||
|
||||
const FormBuilder = ({ bandoStatus }) => {
|
||||
const FormBuilder = ({ callStatus, context }) => {
|
||||
const elements = useStore().main.formElements();
|
||||
const elementItems = useStore().main.elementItems();
|
||||
const activeElement = useStore().main.activeElement();
|
||||
@@ -27,10 +27,10 @@ const FormBuilder = ({ bandoStatus }) => {
|
||||
id={field.id}
|
||||
label={field.label}
|
||||
name={field.name}
|
||||
bandoStatus={bandoStatus}
|
||||
callStatus={callStatus}
|
||||
/>
|
||||
)
|
||||
}, [bandoStatus]);
|
||||
}, [callStatus]);
|
||||
|
||||
const renderItem = useCallback((item) => {
|
||||
return (
|
||||
@@ -56,9 +56,11 @@ const FormBuilder = ({ bandoStatus }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sidebar visible={!isEmpty(activeElement)} onHide={closeSettings} className="formBuilder__elementSettings">
|
||||
<Sidebar visible={!isEmpty(activeElement)} onHide={closeSettings} dismissable={false} className="formBuilder__elementSettings">
|
||||
<h2>{__('Impostazioni del campo modulo', 'gepafin')}</h2>
|
||||
{!isEmpty(activeElement) ? <BuilderElementSettings closeSettingsFn={closeSettings} bandoStatus={bandoStatus}/> : null}
|
||||
{!isEmpty(activeElement)
|
||||
? <BuilderElementSettings closeSettingsFn={closeSettings} callStatus={callStatus} context={context}/>
|
||||
: null}
|
||||
</Sidebar>
|
||||
<div className="formBuilder">
|
||||
<div className="formBuilder__main">
|
||||
|
||||
@@ -24,7 +24,7 @@ import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
import BandoService from '../../service/bando-service';
|
||||
|
||||
// TODO temp data
|
||||
import { elementItems } from '../../tempData';
|
||||
//import { elementItems } from '../../tempData';
|
||||
|
||||
const BandoFormsEdit = () => {
|
||||
const { id, formId } = useParams();
|
||||
@@ -215,8 +215,8 @@ const BandoFormsEdit = () => {
|
||||
|
||||
const getElementItemsCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
|
||||
//storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder));
|
||||
//storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
|
||||
storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder));
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
@@ -317,7 +317,7 @@ const BandoFormsEdit = () => {
|
||||
|
||||
<div className="appPageSection">
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<FormBuilder bandoStatus={bandoStatus}/>
|
||||
<FormBuilder callStatus={bandoStatus} context="application"/>
|
||||
</DndProvider>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user