- saving progress;
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"copy-to-clipboard": "3.3.3",
|
"copy-to-clipboard": "3.3.3",
|
||||||
"deep-object-diff": "1.1.9",
|
"deep-object-diff": "1.1.9",
|
||||||
"dompurify": "3.2.2",
|
"dompurify": "3.2.2",
|
||||||
|
"expression-language": "^1.2.0",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
"hotkeys-js": "3.13.7",
|
"hotkeys-js": "3.13.7",
|
||||||
"html-react-parser": "5.1.18",
|
"html-react-parser": "5.1.18",
|
||||||
@@ -25,6 +26,8 @@
|
|||||||
"klona": "2.0.6",
|
"klona": "2.0.6",
|
||||||
"leader-line-new": "1.1.9",
|
"leader-line-new": "1.1.9",
|
||||||
"luxon": "3.5.0",
|
"luxon": "3.5.0",
|
||||||
|
"mathjs": "^14.0.1",
|
||||||
|
"mustache": "^4.2.0",
|
||||||
"object-path-immutable": "4.1.2",
|
"object-path-immutable": "4.1.2",
|
||||||
"primeicons": "7.0.0",
|
"primeicons": "7.0.0",
|
||||||
"primereact": "10.8.5",
|
"primereact": "10.8.5",
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
background-color: #e3e3e3;
|
background-color: #e3e3e3;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.table {
|
&.table, &.criteria_table {
|
||||||
div.addNewTableRow {
|
div.addNewTableRow {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -181,6 +181,27 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.formElementSettings__fieldDescription {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #ffe0c5;
|
||||||
|
border: 1px solid #e6a973;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
color: #c68e5e;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
border: 1px solid #e1b48b;
|
||||||
|
background-color: #fbeadb;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.formElementSettings__tabs {
|
.formElementSettings__tabs {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-inputnumber-input[readonly] {
|
||||||
|
background-color: #e1e1e1;
|
||||||
|
}
|
||||||
|
|
||||||
.p-inputgroup.flex-1 {
|
.p-inputgroup.flex-1 {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
const DefaultCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
||||||
|
const initialValue = getValue();
|
||||||
|
const disabled = table.options.meta?.disabled;
|
||||||
|
|
||||||
|
const onBlur = (e) => {
|
||||||
|
table.options.meta?.updateData(index, id, e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onFocus = (e) => {
|
||||||
|
e.target.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
disabled={disabled}
|
||||||
|
value={initialValue ?? ''}
|
||||||
|
onChange={(e) => table.options.meta?.updateData(index, id, e.target.value)}
|
||||||
|
onBlur={onBlur}
|
||||||
|
onFocus={onFocus}
|
||||||
|
className="w-full px-2 py-1 border rounded"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DefaultCell;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { head, isEmpty, isNil, sum } from 'ramda';
|
||||||
|
|
||||||
|
const LastRowCell = ({columnId, lastRows, columnMeta = {}, getColumnDataFn}) => {
|
||||||
|
const cellData = head(lastRows.filter(o => !isNil(o[columnId])));
|
||||||
|
let cellValue = cellData[columnId];
|
||||||
|
|
||||||
|
if (columnMeta.enableFormula) {
|
||||||
|
const getAllRowsValues = getColumnDataFn(columnId)
|
||||||
|
.map(v => isEmpty(v) || isNil(v) ? 0 : v);
|
||||||
|
|
||||||
|
if (cellValue === 'sum') {
|
||||||
|
cellValue = sum(getAllRowsValues);
|
||||||
|
} else {
|
||||||
|
cellValue = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return <td>{cellValue}</td>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LastRowCell;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const NumericFormulaCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
||||||
|
const initialValue = getValue();
|
||||||
|
const disabled = table.options.meta?.disabled;
|
||||||
|
|
||||||
|
const onBlur = (e) => {
|
||||||
|
const numValue = e.target.value === 0 ? null : Number(e.target.value);
|
||||||
|
table.options.meta?.updateData(index, id, numValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onFocus = (e) => {
|
||||||
|
e.target.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChange = (e) => {
|
||||||
|
if (e.target.value === 0 || !isNaN(e.target.value)) {
|
||||||
|
table.options.meta?.updateData(index, id, e.target.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
disabled={disabled}
|
||||||
|
value={initialValue ?? 0}
|
||||||
|
onChange={onChange}
|
||||||
|
onFocus={onFocus}
|
||||||
|
onBlur={onBlur}
|
||||||
|
step="any"
|
||||||
|
className="w-full px-2 py-1 border rounded"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NumericFormulaCell;
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { isEmpty } from 'ramda';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import DefaultCell from './components/DefaultCell';
|
||||||
|
import LastRowCell from './components/LastRowCell';
|
||||||
|
|
||||||
|
const RenderTable = ({ data, columns, lastRow, setRowsFn, disabled }) => {
|
||||||
|
const table = useReactTable({
|
||||||
|
data,
|
||||||
|
columns,
|
||||||
|
defaultColumn: {
|
||||||
|
cell: DefaultCell
|
||||||
|
},
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
meta: {
|
||||||
|
disabled,
|
||||||
|
updateData: (rowIndex, columnId, value) => {
|
||||||
|
const newRowsData = wrap(data).set([rowIndex, columnId], value).value();
|
||||||
|
setRowsFn(newRowsData);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getColumnData = (columnId) => {
|
||||||
|
const rows = table.getRowModel().rows;
|
||||||
|
return rows.map(row => row.getValue(columnId));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<tr key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header) => {
|
||||||
|
return (
|
||||||
|
<th key={header.id} colSpan={header.colSpan}>
|
||||||
|
{header.isPlaceholder ? null : (
|
||||||
|
<>
|
||||||
|
{flexRender(
|
||||||
|
header.column.columnDef.header,
|
||||||
|
header.getContext()
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{table.getRowModel().rows.map((row) => {
|
||||||
|
return (
|
||||||
|
<tr key={row.id}>
|
||||||
|
{row.getVisibleCells().map((cell) => {
|
||||||
|
return (
|
||||||
|
<td key={cell.id}>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{!isEmpty(lastRow)
|
||||||
|
? <tr>
|
||||||
|
{columns.map((o) => <LastRowCell
|
||||||
|
key={o.accessorKey}
|
||||||
|
columnId={o.accessorKey}
|
||||||
|
columnMeta={o.meta}
|
||||||
|
lastRows={lastRow}
|
||||||
|
getColumnDataFn={getColumnData}/>)}
|
||||||
|
</tr>
|
||||||
|
: null}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RenderTable
|
||||||
132
src/components/FormField/components/CriteriaTable/index.js
Normal file
132
src/components/FormField/components/CriteriaTable/index.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import React, { useEffect, useState, useCallback } from 'react';
|
||||||
|
import { classNames } from 'primereact/utils';
|
||||||
|
import { pathOr, isEmpty } from 'ramda';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import { nonEmptyTables } from '../../../../helpers/validators';
|
||||||
|
|
||||||
|
//components
|
||||||
|
import RenderTable from './RenderTable';
|
||||||
|
import NumericFormulaCell from './RenderTable/components/NumericFormulaCell';
|
||||||
|
|
||||||
|
const Table = ({
|
||||||
|
fieldName,
|
||||||
|
setDataFn,
|
||||||
|
label,
|
||||||
|
register,
|
||||||
|
errors,
|
||||||
|
disabled = false,
|
||||||
|
config = {},
|
||||||
|
defaultValue = [],
|
||||||
|
tableColumns = []
|
||||||
|
}) => {
|
||||||
|
const [columnsCfg, setColumnsCfg] = useState([]);
|
||||||
|
const [rowsCfg, setRowsCfg] = useState([]);
|
||||||
|
const [columns, setColumns] = useState([]);
|
||||||
|
const [lastRow, setLastRow] = useState([]);
|
||||||
|
const [rows, setRows] = useState(null);
|
||||||
|
|
||||||
|
const updateRows = useCallback((data) => {
|
||||||
|
setRows(data);
|
||||||
|
setDataFn(fieldName, data, { shouldValidate: true });
|
||||||
|
}, [rows, defaultValue]);
|
||||||
|
|
||||||
|
const properConfig = (config) => {
|
||||||
|
let newConfig = klona(config);
|
||||||
|
if (config.validate && config.validate.nonEmptyTables) {
|
||||||
|
newConfig = wrap(newConfig)
|
||||||
|
.set(['validate', 'nonEmptyTables'], (v) => nonEmptyTables(v, tableColumns))
|
||||||
|
.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let newColumns = columnsCfg.map((o) => {
|
||||||
|
const item = {
|
||||||
|
accessorKey: o.name,
|
||||||
|
header: () => o.label,
|
||||||
|
footer: (props) => props.column.id,
|
||||||
|
meta: {
|
||||||
|
predefined: o.predefined,
|
||||||
|
enableFormula: o.enableFormula,
|
||||||
|
fieldtype: o.fieldtype
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o.predefined) {
|
||||||
|
item.cell = (info) => info.getValue();
|
||||||
|
} else if (o.enableFormula || o.fieldtype === 'numeric') {
|
||||||
|
item.cell = NumericFormulaCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
|
||||||
|
setColumns(newColumns);
|
||||||
|
}, [columnsCfg, disabled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setRows(rowsCfg);
|
||||||
|
}, [rowsCfg]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const stateFieldData = pathOr([], ['stateFieldData'], tableColumns);
|
||||||
|
const obj = stateFieldData
|
||||||
|
.reduce((acc, cur) => {
|
||||||
|
acc[cur.name] = ''
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
let rowsData = pathOr([obj], ['rowsData'], tableColumns);
|
||||||
|
rowsData = isEmpty(rowsData) ? [obj] : rowsData;
|
||||||
|
setColumnsCfg(stateFieldData);
|
||||||
|
setRowsCfg(rowsData);
|
||||||
|
|
||||||
|
let lastRowData = stateFieldData.reduce((acc, cur) => {
|
||||||
|
const value = cur.enableFormula ? cur.lastRowFormula : (cur.lastRowText ? cur.lastRowText : '');
|
||||||
|
acc.push({ [cur.name]: value });
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const lastRowValues = lastRowData
|
||||||
|
.map(o => {
|
||||||
|
const values = Object.values(o);
|
||||||
|
return values[0];
|
||||||
|
})
|
||||||
|
.filter(v => !isEmpty(v));
|
||||||
|
|
||||||
|
setLastRow(!isEmpty(lastRowValues) ? lastRowData : []);
|
||||||
|
}, [tableColumns]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!equal(rows, defaultValue)) {
|
||||||
|
setRows(defaultValue);
|
||||||
|
}
|
||||||
|
}, [defaultValue]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setRows(defaultValue);
|
||||||
|
register(fieldName, properConfig(config));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
console.log('rows', rows, lastRow, tableColumns)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||||
|
{label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables)
|
||||||
|
? <span className="appForm__field--required">*</span> : null}
|
||||||
|
</label>
|
||||||
|
{rows ? <RenderTable
|
||||||
|
columns={columns}
|
||||||
|
data={rows}
|
||||||
|
lastRow={lastRow}
|
||||||
|
setRowsFn={updateRows}
|
||||||
|
disabled={disabled}/> : null}
|
||||||
|
</>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Table;
|
||||||
@@ -21,6 +21,7 @@ const NumberInput = ({
|
|||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
|
readOnly = false,
|
||||||
useGrouping = true
|
useGrouping = true
|
||||||
}) => {
|
}) => {
|
||||||
const minAttr = config.min ? config.min : min;
|
const minAttr = config.min ? config.min : min;
|
||||||
@@ -33,11 +34,13 @@ const NumberInput = ({
|
|||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
<InputNumber inputId={field.name}
|
<InputNumber inputId={field.name}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
readOnly={readOnly}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onValueChange={(e) => field.onChange(e.value)}
|
onValueChange={(e) => field.onChange(e.value)}
|
||||||
min={minAttr}
|
min={minAttr}
|
||||||
max={maxAttr}
|
max={maxAttr}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
showButtons
|
||||||
useGrouping={useGrouping}
|
useGrouping={useGrouping}
|
||||||
maxFractionDigits={!isNaN(parseInt(maxFractionDigits)) ? parseInt(maxFractionDigits) : 0}
|
maxFractionDigits={!isNaN(parseInt(maxFractionDigits)) ? parseInt(maxFractionDigits) : 0}
|
||||||
minFractionDigits={!isNaN(parseInt(minFractionDigits)) ? parseInt(minFractionDigits) : 0}
|
minFractionDigits={!isNaN(parseInt(minFractionDigits)) ? parseInt(minFractionDigits) : 0}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ 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';
|
import PasswordField from './components/PasswordField';
|
||||||
|
import CriteriaTable from './components/CriteriaTable';
|
||||||
|
|
||||||
const FormField = (props) => {
|
const FormField = (props) => {
|
||||||
const fields = {
|
const fields = {
|
||||||
@@ -33,6 +34,7 @@ const FormField = (props) => {
|
|||||||
wysiwyg: Wysiwyg,
|
wysiwyg: Wysiwyg,
|
||||||
checkboxes: Checkboxes,
|
checkboxes: Checkboxes,
|
||||||
table: Table,
|
table: Table,
|
||||||
|
criteria_table: CriteriaTable,
|
||||||
password: PasswordField
|
password: PasswordField
|
||||||
}
|
}
|
||||||
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;
|
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;
|
||||||
|
|||||||
11
src/helpers/getTokens.js
Normal file
11
src/helpers/getTokens.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { tokenize } from 'expression-language';
|
||||||
|
|
||||||
|
const getTokens = expr => tokenize(expr).tokens
|
||||||
|
.filter((o, i, arr) => o.type === 'name'
|
||||||
|
&& (typeof arr[i+1] === 'undefined'
|
||||||
|
|| (typeof arr[i+1] !== 'undefined' && arr[i+1].value !== '('))
|
||||||
|
)
|
||||||
|
.map(o => o.value)
|
||||||
|
.filter((v, i, arr) => arr.indexOf(v) === i);
|
||||||
|
|
||||||
|
export default getTokens;
|
||||||
23
src/helpers/renderWithDataVars.js
Normal file
23
src/helpers/renderWithDataVars.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import mustache from 'mustache';
|
||||||
|
import { replace } from 'ramda';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use mustachejs to parse content and replace variables with their values
|
||||||
|
* Each variable (everything in brackets) is expression for EE
|
||||||
|
*
|
||||||
|
* @param {string} content
|
||||||
|
* @param {object} context
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
const renderWithDataVars = (content = '', context = {}) => {
|
||||||
|
try {
|
||||||
|
let newContent = replace(/{/g, '{{&', content);
|
||||||
|
newContent = replace(/}/g, '}}', newContent);
|
||||||
|
return mustache.render(newContent, context);
|
||||||
|
} catch {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default renderWithDataVars;
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { useParams } from 'react-router-dom';
|
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 { useForm } from 'react-hook-form';
|
||||||
import 'quill/dist/quill.core.css';
|
import 'quill/dist/quill.core.css';
|
||||||
import { wrap } from 'object-path-immutable';
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { evaluate } from 'mathjs';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { storeSet, storeGet, useStore } from '../../store';
|
import { storeSet, storeGet, useStore } from '../../store';
|
||||||
@@ -26,6 +29,10 @@ import {
|
|||||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
|
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
|
// components
|
||||||
import { Skeleton } from 'primereact/skeleton';
|
import { Skeleton } from 'primereact/skeleton';
|
||||||
@@ -39,8 +46,6 @@ import { Dialog } from 'primereact/dialog';
|
|||||||
import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
|
import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
|
||||||
|
|
||||||
import { defaultMaxFileSize } from '../../configData';
|
import { defaultMaxFileSize } from '../../configData';
|
||||||
import formatDateString from '../../helpers/formatDateString';
|
|
||||||
import isDateTimeInPast from '../../helpers/isDateTimeInPast';
|
|
||||||
|
|
||||||
const BandoApplication = () => {
|
const BandoApplication = () => {
|
||||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||||
@@ -48,6 +53,8 @@ const BandoApplication = () => {
|
|||||||
const [isExpired, setIsExpired] = useState(false);
|
const [isExpired, setIsExpired] = useState(false);
|
||||||
const [formData, setFormData] = useState([]);
|
const [formData, setFormData] = useState([]);
|
||||||
const [formInitialData, setFormInitialData] = useState(null);
|
const [formInitialData, setFormInitialData] = useState(null);
|
||||||
|
const [fieldsWithVars, setFieldsWithVars] = useState({});
|
||||||
|
const [fieldsWithFormula, setFieldsWithFormula] = useState({});
|
||||||
const [bandoTitle, setBandoTitle] = useState('');
|
const [bandoTitle, setBandoTitle] = useState('');
|
||||||
const [bandoId, setBandoId] = useState(0);
|
const [bandoId, setBandoId] = useState(0);
|
||||||
const [formId, setFormId] = useState('');
|
const [formId, setFormId] = useState('');
|
||||||
@@ -67,6 +74,7 @@ const BandoApplication = () => {
|
|||||||
trigger,
|
trigger,
|
||||||
register,
|
register,
|
||||||
getValues,
|
getValues,
|
||||||
|
watch,
|
||||||
reset
|
reset
|
||||||
} = useForm({
|
} = useForm({
|
||||||
defaultValues: useMemo(() => {
|
defaultValues: useMemo(() => {
|
||||||
@@ -89,6 +97,7 @@ const BandoApplication = () => {
|
|||||||
}
|
}
|
||||||
const activeStepIndex = activeStep - 1;
|
const activeStepIndex = activeStep - 1;
|
||||||
const values = getValues();
|
const values = getValues();
|
||||||
|
const formValues = watch();
|
||||||
|
|
||||||
const onValidate = () => {
|
const onValidate = () => {
|
||||||
const applId = getApplicationId();
|
const applId = getApplicationId();
|
||||||
@@ -342,6 +351,8 @@ const BandoApplication = () => {
|
|||||||
dynamicData = wrap(dynamicData).set(['custom', 'userFullName'], userFullName).value();
|
dynamicData = wrap(dynamicData).set(['custom', 'userFullName'], userFullName).value();
|
||||||
const legalRepresentantName = company.isLegalRepresentant ? userFullName : '';
|
const legalRepresentantName = company.isLegalRepresentant ? userFullName : '';
|
||||||
dynamicData = wrap(dynamicData).set(['custom', 'legalRepresentant'], legalRepresentantName).value();
|
dynamicData = wrap(dynamicData).set(['custom', 'legalRepresentant'], legalRepresentantName).value();
|
||||||
|
let allvars = {};
|
||||||
|
let allformulas = {};
|
||||||
|
|
||||||
if (data.data.applicationFormResponse.content) {
|
if (data.data.applicationFormResponse.content) {
|
||||||
// eslint-disable-next-line array-callback-return
|
// eslint-disable-next-line array-callback-return
|
||||||
@@ -349,7 +360,15 @@ const BandoApplication = () => {
|
|||||||
if (o.dynamicData && !isEmpty(o.dynamicData)) {
|
if (o.dynamicData && !isEmpty(o.dynamicData)) {
|
||||||
formDataInitial[o.id] = pathOr('', o.dynamicData.split('.'), 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) {
|
if (data.data.applicationFormResponse.formFields) {
|
||||||
@@ -366,6 +385,8 @@ const BandoApplication = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
setFieldsWithVars(allvars);
|
||||||
|
setFieldsWithFormula(allformulas);
|
||||||
setFormInitialData(formDataInitial);
|
setFormInitialData(formDataInitial);
|
||||||
}
|
}
|
||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
@@ -501,10 +522,45 @@ const BandoApplication = () => {
|
|||||||
// TODO hardcoded for now
|
// TODO hardcoded for now
|
||||||
const signedDocMime = bandoId === 10
|
const signedDocMime = bandoId === 10
|
||||||
? ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime', '.pdf,application/pdf']
|
? ['.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
|
const signedDocValidationString = bandoId === 10
|
||||||
? ['.p7m', '.pdf']
|
? ['.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(() => {
|
useEffect(() => {
|
||||||
if ('SUBMIT' === applicationStatus) {
|
if ('SUBMIT' === applicationStatus) {
|
||||||
@@ -595,6 +651,7 @@ const BandoApplication = () => {
|
|||||||
const tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
|
const tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
|
||||||
const step = head(o.settings.filter(o => o.name === 'step'));
|
const step = head(o.settings.filter(o => o.name === 'step'));
|
||||||
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
||||||
|
const formula = head(o.settings.filter(o => o.name === 'formula'));
|
||||||
let mimeValue = '';
|
let mimeValue = '';
|
||||||
|
|
||||||
if (mime) {
|
if (mime) {
|
||||||
@@ -630,6 +687,7 @@ const BandoApplication = () => {
|
|||||||
</div>
|
</div>
|
||||||
: <FormField
|
: <FormField
|
||||||
key={o.id}
|
key={o.id}
|
||||||
|
readOnly={formula && !isEmpty(formula.value)}
|
||||||
type={o.name}
|
type={o.name}
|
||||||
fieldName={o.id}
|
fieldName={o.id}
|
||||||
label={label ? label.value : ''}
|
label={label ? label.value : ''}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ const BandoFlowEdit = () => {
|
|||||||
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 [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);
|
||||||
@@ -162,18 +161,18 @@ const BandoFlowEdit = () => {
|
|||||||
const shoudDisableSaving = useCallback(() => {
|
const shoudDisableSaving = useCallback(() => {
|
||||||
const nonEmptyFlowItems = flowStructure.flowData.filter(o => isEmpty(o.chosenField)).filter(o => !isEmpty(o.chosenValue));
|
const nonEmptyFlowItems = flowStructure.flowData.filter(o => isEmpty(o.chosenField)).filter(o => !isEmpty(o.chosenValue));
|
||||||
|
|
||||||
/*if (flowForms.length > 2) {
|
/*if (forms.length > 2) {
|
||||||
console.log('disable BTN:', nonEmptyFlowItems.length !== flowForms.length - 2, isEmpty(flowEdges), 'PUBLISH' === bandoStatus,
|
console.log('disable BTN:', nonEmptyFlowItems.length !== forms.length - 2, isEmpty(flowStructure.flowEdges), 'PUBLISH' === bandoStatus,
|
||||||
isEmpty(initialForm), isEmpty(finalForm));
|
isEmpty(flowStructure.initialForm), isEmpty(flowStructure.finalForm));
|
||||||
} else {
|
} else {
|
||||||
console.log('disable BTN:', nonEmptyFlowItems.length !== 1, isEmpty(flowEdges), 'PUBLISH' === bandoStatus,
|
console.log('disable BTN (2 forms):', isEmpty(flowStructure.flowEdges), 'PUBLISH' === bandoStatus,
|
||||||
isEmpty(initialForm), isEmpty(finalForm));
|
isEmpty(flowStructure.initialForm), isEmpty(flowStructure.finalForm));
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
return forms.length > 2
|
return forms.length > 2
|
||||||
? nonEmptyFlowItems.length !== forms.length - 2 || isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|
? nonEmptyFlowItems.length !== forms.length - 2 || isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|
||||||
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm)
|
|| 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);
|
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm);
|
||||||
}, [flowStructure, forms]);
|
}, [flowStructure, forms]);
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
|||||||
<div className="meta">
|
<div className="meta">
|
||||||
<div className="tagHeader">
|
<div className="tagHeader">
|
||||||
<Tag value={label} severity="info"/>
|
<Tag value={label} severity="info"/>
|
||||||
{name === 'numberinput'
|
{['numberinput', 'criteria_table'].includes(name)
|
||||||
? <Tag value="var" severity={isVariable}/> : null}
|
? <Tag value="var" severity={isVariable}/> : null}
|
||||||
{name === 'numberinput'
|
{name === 'numberinput'
|
||||||
? <Tag value="f(x)" severity={isFormula}/> : null}
|
? <Tag value="f(x)" severity={isFormula}/> : null}
|
||||||
|
|||||||
@@ -2,19 +2,23 @@ import React from 'react';
|
|||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { is } from 'ramda';
|
import { is } from 'ramda';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import renderHtmlContent from '../../../../../../helpers/renderHtmlContent';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import ElementSettingRepeater from '../ElementSettingRepeater';
|
import ElementSettingRepeater from '../ElementSettingRepeater';
|
||||||
import { InputText } from 'primereact/inputtext';
|
import { InputText } from 'primereact/inputtext';
|
||||||
import { MultiSelect } from 'primereact/multiselect';
|
import { MultiSelect } from 'primereact/multiselect';
|
||||||
import { Editor } from 'primereact/editor';
|
import { Editor } from 'primereact/editor';
|
||||||
|
|
||||||
import { mimeTypes } from '../../../../../../configData';
|
|
||||||
import ElementSettingTableColumns from '../ElementSettingTableColumns';
|
import ElementSettingTableColumns from '../ElementSettingTableColumns';
|
||||||
import { InputSwitch } from 'primereact/inputswitch';
|
import { InputSwitch } from 'primereact/inputswitch';
|
||||||
import ElementSettingChips from '../ElementSettingChips';
|
import ElementSettingChips from '../ElementSettingChips';
|
||||||
|
import ElementSettingCriteriaTableColumns from '../ElementSettingCriteriaTableColumns';
|
||||||
|
|
||||||
|
import { mimeTypes } from '../../../../../../configData';
|
||||||
|
|
||||||
|
|
||||||
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||||
|
|
||||||
const settingLabels = {
|
const settingLabels = {
|
||||||
label: __('Label', 'gepafin'),
|
label: __('Label', 'gepafin'),
|
||||||
placeholder: __('Segnaposto', 'gepafin'),
|
placeholder: __('Segnaposto', 'gepafin'),
|
||||||
@@ -25,10 +29,15 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
mime: __('Tipo di file', 'gepafin'),
|
mime: __('Tipo di file', 'gepafin'),
|
||||||
text: __('Testo formattato', 'gepafin'),
|
text: __('Testo formattato', 'gepafin'),
|
||||||
table_columns: '',
|
table_columns: '',
|
||||||
|
criteria_table_columns: '',
|
||||||
variable: __('Variable (only letters and "_")', 'gepafin'),
|
variable: __('Variable (only letters and "_")', 'gepafin'),
|
||||||
formula: __('Auto calculation formula', '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 = () => {
|
const renderHeader = () => {
|
||||||
return (
|
return (
|
||||||
<span className="ql-formats">
|
<span className="ql-formats">
|
||||||
@@ -84,6 +93,12 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
name={setting.name}
|
name={setting.name}
|
||||||
bandoStatus={bandoStatus}
|
bandoStatus={bandoStatus}
|
||||||
setDataFn={updateDataFn}/>
|
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)) {
|
} else if (['isRequestedAmount', 'isDelegation'].includes(setting.name)) {
|
||||||
return <InputSwitch
|
return <InputSwitch
|
||||||
checked={setting.value}
|
checked={setting.value}
|
||||||
@@ -103,6 +118,10 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
return <div className="formElementSettings__field" key={setting.name}>
|
return <div className="formElementSettings__field" key={setting.name}>
|
||||||
<label htmlFor={setting.name}>{settingLabels[setting.name]}</label>
|
<label htmlFor={setting.name}>{settingLabels[setting.name]}</label>
|
||||||
{getProperField(setting)}
|
{getProperField(setting)}
|
||||||
|
{settingDescription[setting.name]
|
||||||
|
? <div className="formElementSettings__fieldDescription">
|
||||||
|
<p>{renderHtmlContent(settingDescription[setting.name])}</p>
|
||||||
|
</div> : null}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import React, { useState } from 'react';
|
|||||||
|
|
||||||
// components
|
// components
|
||||||
import { Chips } from 'primereact/chips';
|
import { Chips } from 'primereact/chips';
|
||||||
|
import { isEmpty } from 'ramda';
|
||||||
|
|
||||||
const ElementSettingChips = ({ restrictedValues = [], changeFn, value }) => {
|
const ElementSettingChips = ({ restrictedValues = [], changeFn, value = [] }) => {
|
||||||
const [lastTyped, setLastTyped] = useState([])
|
const [lastTyped, setLastTyped] = useState([])
|
||||||
|
|
||||||
const isValidValue = (newVal) => {
|
const isValidValue = (newVal) => {
|
||||||
@@ -12,7 +13,7 @@ const ElementSettingChips = ({ restrictedValues = [], changeFn, value }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleAdd = (e) => {
|
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)) {
|
if (restrictedValues.includes(newValue)) {
|
||||||
changeFn([]);
|
changeFn([]);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -158,7 +158,7 @@ const ElementSettingTableColumns = ({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
disabled={item.enableFormula}
|
disabled={item.enableFormula || bandoStatus === 'PUBLISH'}
|
||||||
value={item.fieldtype ? item.fieldtype : 'text'}
|
value={item.fieldtype ? item.fieldtype : 'text'}
|
||||||
onChange={(e) => onTypeChange(e.value, i)}
|
onChange={(e) => onTypeChange(e.value, i)}
|
||||||
options={[
|
options={[
|
||||||
@@ -168,6 +168,7 @@ const ElementSettingTableColumns = ({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
className="formElementSettings__repeaterItemIconBtn"
|
className="formElementSettings__repeaterItemIconBtn"
|
||||||
onClick={() => setColFormulaChecked(i)}
|
onClick={() => setColFormulaChecked(i)}
|
||||||
data-active={item.enableFormula ? item.enableFormula : false}
|
data-active={item.enableFormula ? item.enableFormula : false}
|
||||||
@@ -193,11 +194,12 @@ const ElementSettingTableColumns = ({
|
|||||||
const properSubField = (item, i, name) => {
|
const properSubField = (item, i, name) => {
|
||||||
return <>
|
return <>
|
||||||
<div>
|
<div>
|
||||||
<InputText value={item[name]} onInput={(e) => onSubInputChange(e, name, i)}/>
|
<InputText
|
||||||
|
value={item[name]}
|
||||||
|
onInput={(e) => onSubInputChange(e, name, i)}/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button icon="pi pi-times"
|
<Button icon="pi pi-times"
|
||||||
disabled={bandoStatus === 'PUBLISH'}
|
|
||||||
className="p-button-danger"
|
className="p-button-danger"
|
||||||
onClick={() => removeRow(i)}/>
|
onClick={() => removeRow(i)}/>
|
||||||
</div>
|
</div>
|
||||||
@@ -212,6 +214,7 @@ const ElementSettingTableColumns = ({
|
|||||||
{item.enableFormula
|
{item.enableFormula
|
||||||
? <div>
|
? <div>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
value={item.lastRowFormula}
|
value={item.lastRowFormula}
|
||||||
onChange={(e) => onLastRowFormulaChange(e.value, i)}
|
onChange={(e) => onLastRowFormulaChange(e.value, i)}
|
||||||
options={[
|
options={[
|
||||||
@@ -232,6 +235,7 @@ const ElementSettingTableColumns = ({
|
|||||||
{__('Definisci ultima righa', 'gepafin')}
|
{__('Definisci ultima righa', 'gepafin')}
|
||||||
</div>
|
</div>
|
||||||
<Button type="button"
|
<Button type="button"
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
outlined
|
outlined
|
||||||
label={__('Pulisci', 'gepafin')}
|
label={__('Pulisci', 'gepafin')}
|
||||||
iconPos="right"
|
iconPos="right"
|
||||||
@@ -271,8 +275,12 @@ const ElementSettingTableColumns = ({
|
|||||||
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
|
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
|
||||||
{properFields(o, i)}
|
{properFields(o, i)}
|
||||||
</div>)}
|
</div>)}
|
||||||
<Button type="button" disabled={bandoStatus === 'PUBLISH'} outlined
|
<Button
|
||||||
label={__('Aggiungi colonna', 'gepafin')} onClick={addNewItem}/>
|
type="button"
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
|
outlined
|
||||||
|
label={__('Aggiungi colonna', 'gepafin')}
|
||||||
|
onClick={addNewItem}/>
|
||||||
</div>
|
</div>
|
||||||
{stateFieldData
|
{stateFieldData
|
||||||
.filter(o => o.predefined).length > 0
|
.filter(o => o.predefined).length > 0
|
||||||
|
|||||||
@@ -110,22 +110,6 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
return dynamicDataOptions[type] ?? [];
|
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(() => {
|
useEffect(() => {
|
||||||
const chosen = head(elements.filter(o => o.id === activeElement));
|
const chosen = head(elements.filter(o => o.id === activeElement));
|
||||||
const elementItems = storeGet.main.elementItems();
|
const elementItems = storeGet.main.elementItems();
|
||||||
@@ -163,11 +147,11 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
? settings
|
? settings
|
||||||
.filter(o => !['variable', 'formula'].includes(o.name))
|
.filter(o => !['variable', 'formula'].includes(o.name))
|
||||||
.map((o) => <ElementSetting
|
.map((o) => <ElementSetting
|
||||||
key={o.name}
|
key={o.name}
|
||||||
setting={o}
|
setting={o}
|
||||||
bandoStatus={bandoStatus}
|
bandoStatus={bandoStatus}
|
||||||
changeFn={onChange}
|
changeFn={onChange}
|
||||||
updateDataFn={onUpdateOptions}/>)
|
updateDataFn={onUpdateOptions}/>)
|
||||||
: null}
|
: null}
|
||||||
{!isNil(dynamicDataOptions[activeElementData.name])
|
{!isNil(dynamicDataOptions[activeElementData.name])
|
||||||
? <div className="formElementSettings__field">
|
? <div className="formElementSettings__field">
|
||||||
@@ -250,18 +234,21 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
placeholder={__('Scegli', 'gepafin')}/>
|
placeholder={__('Scegli', 'gepafin')}/>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel header={__('Calculation', 'gepafin')}>
|
{settings
|
||||||
{settings
|
&& settings
|
||||||
? settings
|
.filter(o => ['variable', 'formula'].includes(o.name)).length > 0
|
||||||
.filter(o => ['variable', 'formula'].includes(o.name))
|
? <TabPanel header={__('Calculation', 'gepafin')}>
|
||||||
.map((o) => <ElementSetting
|
{settings
|
||||||
key={o.name}
|
? settings
|
||||||
setting={o}
|
.filter(o => ['variable', 'formula'].includes(o.name))
|
||||||
bandoStatus={bandoStatus}
|
.map((o) => <ElementSetting
|
||||||
changeFn={onChange}
|
key={o.name}
|
||||||
updateDataFn={onUpdateOptions}/>)
|
setting={o}
|
||||||
: null}
|
bandoStatus={bandoStatus}
|
||||||
</TabPanel>
|
changeFn={onChange}
|
||||||
|
updateDataFn={onUpdateOptions}/>)
|
||||||
|
: null}
|
||||||
|
</TabPanel> : null}
|
||||||
</TabView>
|
</TabView>
|
||||||
|
|
||||||
<Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>
|
<Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { klona } from 'klona';
|
import { klona } from 'klona';
|
||||||
import { head, isNil } from 'ramda';
|
import { head, isNil , isEmpty } from 'ramda';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import 'quill/dist/quill.core.css';
|
import 'quill/dist/quill.core.css';
|
||||||
|
import { evaluate } from 'mathjs';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { storeSet, useStore } from '../../store';
|
import { storeSet, useStore } from '../../store';
|
||||||
@@ -30,12 +32,16 @@ import {
|
|||||||
isUrl, minChecks, maxChecks, nonEmptyTables
|
isUrl, minChecks, maxChecks, nonEmptyTables
|
||||||
} from '../../helpers/validators';
|
} from '../../helpers/validators';
|
||||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||||
|
import renderWithDataVars from '../../helpers/renderWithDataVars';
|
||||||
|
import getTokens from '../../helpers/getTokens';
|
||||||
|
|
||||||
const BandoFormsPreview = () => {
|
const BandoFormsPreview = () => {
|
||||||
const { id, formId } = useParams();
|
const { id, formId } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [formData, setFormData] = useState([]);
|
const [formData, setFormData] = useState([]);
|
||||||
const [formName, setFormName] = useState('');
|
const [formName, setFormName] = useState('');
|
||||||
|
const [fieldsWithVars, setFieldsWithVars] = useState({});
|
||||||
|
const [fieldsWithFormula, setFieldsWithFormula] = useState({});
|
||||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@@ -43,9 +49,12 @@ const BandoFormsPreview = () => {
|
|||||||
formState: { errors },
|
formState: { errors },
|
||||||
getValues,
|
getValues,
|
||||||
register,
|
register,
|
||||||
setValue
|
setValue,
|
||||||
|
watch,
|
||||||
|
reset
|
||||||
} = useForm({ defaultValues: {}, mode: 'onChange' });
|
} = useForm({ defaultValues: {}, mode: 'onChange' });
|
||||||
const values = getValues();
|
const values = getValues();
|
||||||
|
const formValues = watch();
|
||||||
const validationFns = {
|
const validationFns = {
|
||||||
isPIVA,
|
isPIVA,
|
||||||
isCodiceFiscale,
|
isCodiceFiscale,
|
||||||
@@ -75,6 +84,23 @@ const BandoFormsPreview = () => {
|
|||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
setFormName(data.data.label);
|
setFormName(data.data.label);
|
||||||
const elements = klona(data.data.content);
|
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);
|
setFormData(elements);
|
||||||
}
|
}
|
||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
@@ -85,6 +111,41 @@ const BandoFormsPreview = () => {
|
|||||||
storeSet.main.unsetAsyncRequest();
|
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(() => {
|
useEffect(() => {
|
||||||
const parsedFormId = parseInt(formId)
|
const parsedFormId = parseInt(formId)
|
||||||
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
|
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
|
||||||
@@ -126,9 +187,13 @@ const BandoFormsPreview = () => {
|
|||||||
const text = head(o.settings.filter(o => o.name === 'text'));
|
const text = head(o.settings.filter(o => o.name === 'text'));
|
||||||
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
||||||
const options = head(o.settings.filter(o => o.name === 'options'));
|
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 step = head(o.settings.filter(o => o.name === 'step'));
|
||||||
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
||||||
|
const formula = head(o.settings.filter(o => o.name === 'formula'));
|
||||||
let mimeValue = '';
|
let mimeValue = '';
|
||||||
|
|
||||||
if (mime) {
|
if (mime) {
|
||||||
@@ -162,6 +227,7 @@ const BandoFormsPreview = () => {
|
|||||||
</div>
|
</div>
|
||||||
: <FormField
|
: <FormField
|
||||||
key={o.id}
|
key={o.id}
|
||||||
|
readOnly={formula && !isEmpty(formula.value)}
|
||||||
type={o.name}
|
type={o.name}
|
||||||
fieldName={o.id}
|
fieldName={o.id}
|
||||||
label={label ? label.value : ''}
|
label={label ? label.value : ''}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export const elementItems = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "variable",
|
name: "variable",
|
||||||
value: ""
|
value: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "formula",
|
name: "formula",
|
||||||
@@ -435,5 +435,29 @@ export const elementItems = [
|
|||||||
validators: {
|
validators: {
|
||||||
custom: 'nonEmptyTables'
|
custom: 'nonEmptyTables'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 21,
|
||||||
|
sortOrder: 21,
|
||||||
|
name: 'criteria_table',
|
||||||
|
label: 'Tabella di criteri',
|
||||||
|
description: 'Tabella di criteri',
|
||||||
|
settings: [
|
||||||
|
{
|
||||||
|
name: "label",
|
||||||
|
value: "Tabella"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "criteria_table_columns",
|
||||||
|
value: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "variable",
|
||||||
|
value: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
validators: {
|
||||||
|
custom: 'nonEmptyTables'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user