updated form fields and application logic;
This commit is contained in:
8
src/components/BlockingOverlay/index.js
Normal file
8
src/components/BlockingOverlay/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
const BlockingOverlay = ({ shouldDisplay = false }) => {
|
||||
return shouldDisplay
|
||||
? <div className="blockingOverlay"></div> : null;
|
||||
}
|
||||
|
||||
export default BlockingOverlay;
|
||||
@@ -22,13 +22,15 @@ const NodeInitialForm = ({ data: { id, label = '' } }) => {
|
||||
|
||||
useEffect(() => {
|
||||
const forms = storeGet.main.flowForms();
|
||||
const form = head(forms.filter(o => String(o.id) === String(id)))
|
||||
const relevantFields = form
|
||||
? form.content
|
||||
.filter(o => ['radio', 'select'].includes(o.name))
|
||||
.map(o => ({ name: o.id, label: o.label }))
|
||||
: [];
|
||||
setOptions(relevantFields);
|
||||
if (forms.length > 2) {
|
||||
const form = head(forms.filter(o => String(o.id) === String(id)))
|
||||
const relevantFields = form
|
||||
? form.content
|
||||
.filter(o => ['radio', 'select'].includes(o.name))
|
||||
.map(o => ({ name: o.id, label: o.label }))
|
||||
: [];
|
||||
setOptions(relevantFields);
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -55,11 +55,10 @@ const FlowBuilder = ({ initialForm = 0, finalForm = 0 }) => {
|
||||
id: formId,
|
||||
type: 'output',
|
||||
data: { label: o.label, id: formId },
|
||||
position: { x: 0, y: 300 },
|
||||
position: { x: 0, y: forms.length === 2 ? 150 : 300 },
|
||||
}
|
||||
} else {
|
||||
const x = coordinates.splice(0, 1);
|
||||
console.log('x', x)
|
||||
obj = {
|
||||
id: formId,
|
||||
type: 'intermediateForm',
|
||||
@@ -78,11 +77,15 @@ const FlowBuilder = ({ initialForm = 0, finalForm = 0 }) => {
|
||||
if (formId !== String(initialForm) && formId !== String(finalForm)) {
|
||||
edges.push({ id: `${initialForm}->${formId}`, source: String(initialForm), target: formId, type: 'smoothstep' });
|
||||
}
|
||||
if (formId !== String(finalForm) && formId !== String(initialForm) && String(finalForm) !== '0') {
|
||||
if (formId !== String(initialForm) && formId !== String(finalForm) && String(finalForm) !== '0') {
|
||||
edges.push({ id: `${formId}->${finalForm}`, source: formId, target: String(finalForm), type: 'smoothstep' });
|
||||
}
|
||||
});
|
||||
console.log('edges', edges, initialNodes);
|
||||
|
||||
if (forms.length === 2 && initialForm && finalForm) {
|
||||
edges.push({ id: `${initialForm}->${finalForm}`, source: String(initialForm), target: String(finalForm), type: 'smoothstep' });
|
||||
}
|
||||
|
||||
setNodes(initialNodes);
|
||||
setEdges(edges);
|
||||
storeSet.main.flowEdges(edges);
|
||||
|
||||
57
src/components/FormField/components/Checkboxes/index.js
Normal file
57
src/components/FormField/components/Checkboxes/index.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import { Controller } from 'react-hook-form';
|
||||
import { Checkbox } from 'primereact/checkbox';
|
||||
|
||||
const Checkboxes = ({
|
||||
fieldName,
|
||||
label,
|
||||
control,
|
||||
errors,
|
||||
defaultValue = [],
|
||||
config = {},
|
||||
infoText = null,
|
||||
options = []
|
||||
}) => {
|
||||
const [fieldVal, setFieldVal] = useState(defaultValue);
|
||||
|
||||
const onCheckboxesChange = useCallback((e, updateFn) => {
|
||||
let data = [...fieldVal];
|
||||
|
||||
if (e.checked) {
|
||||
data.push(e.value);
|
||||
} else {
|
||||
data.splice(data.indexOf(e.value), 1);
|
||||
}
|
||||
|
||||
setFieldVal(data);
|
||||
updateFn(data);
|
||||
}, [fieldVal]);
|
||||
|
||||
const input = <Controller
|
||||
name={fieldName}
|
||||
control={control}
|
||||
defaultValue={fieldVal}
|
||||
rules={config}
|
||||
render={({ field, fieldState }) =>
|
||||
options.map(o => <div className="appForm__fieldItem" key={o.name}>
|
||||
<Checkbox
|
||||
inputId={`${fieldName}_${o.name}`}
|
||||
name={fieldName}
|
||||
value={o.name}
|
||||
onChange={(e) => onCheckboxesChange(e, field.onChange)}
|
||||
checked={field.value.includes(o.name)}
|
||||
className={classNames({ 'p-invalid': fieldState.invalid })}/>
|
||||
<label htmlFor={`${fieldName}_${o.name}`}>{o.label}</label>
|
||||
</div>)}/>
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
{input}
|
||||
{infoText ? <small>{infoText}</small> : null}
|
||||
</>)
|
||||
}
|
||||
|
||||
export default Checkboxes;
|
||||
@@ -18,7 +18,7 @@ const Datepicker = ({
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required ? '*' : null}
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
<Controller
|
||||
name={fieldName}
|
||||
|
||||
@@ -15,8 +15,8 @@ const NumberInput = ({
|
||||
inputgroup = false,
|
||||
icon = null,
|
||||
locale = 'it-IT',
|
||||
minFractionDigits = 2,
|
||||
step = 1,
|
||||
minFractionDigits = 0,
|
||||
maxFractionDigits = 1,
|
||||
min,
|
||||
max
|
||||
}) => {
|
||||
@@ -31,13 +31,14 @@ const NumberInput = ({
|
||||
onValueChange={(e) => field.onChange(e.value)}
|
||||
min={min}
|
||||
max={max}
|
||||
locale={locale} minFractionDigits={minFractionDigits} step={step}
|
||||
locale={locale}
|
||||
minFractionDigits={minFractionDigits}
|
||||
className={classNames({ 'p-invalid': fieldState.invalid })}/>
|
||||
)}/>
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required ? '*' : null}
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
{inputgroup
|
||||
? <div className="p-inputgroup flex-1">
|
||||
|
||||
@@ -4,34 +4,35 @@ import { Controller } from 'react-hook-form';
|
||||
import { RadioButton } from 'primereact/radiobutton';
|
||||
|
||||
const Radio = ({
|
||||
fieldName,
|
||||
label,
|
||||
control,
|
||||
errors,
|
||||
defaultValue,
|
||||
config = {},
|
||||
infoText = null,
|
||||
options = []
|
||||
}) => {
|
||||
fieldName,
|
||||
label,
|
||||
control,
|
||||
errors,
|
||||
defaultValue,
|
||||
config = {},
|
||||
infoText = null,
|
||||
options = []
|
||||
}) => {
|
||||
const input = <Controller
|
||||
name={fieldName}
|
||||
control={control}
|
||||
defaultValue={defaultValue}
|
||||
rules={config}
|
||||
render={({ field, fieldState }) =>
|
||||
options.map(o => <div className="appForm__fieldItem" key={o.name}>
|
||||
<RadioButton
|
||||
id={`${fieldName}_${o.name}`}
|
||||
name={fieldName}
|
||||
value={o.name}
|
||||
onChange={(e) => field.onChange(e.value)}
|
||||
checked={field.value === o.name}/>
|
||||
<label htmlFor={`${fieldName}_${o.name}`}>{o.label}</label>
|
||||
</div>)}/>
|
||||
options.map(o => <div className="appForm__fieldItem" key={o.name}>
|
||||
<RadioButton
|
||||
inputId={`${fieldName}_${o.name}`}
|
||||
name={fieldName}
|
||||
value={o.name}
|
||||
onChange={(e) => field.onChange(e.value)}
|
||||
checked={field.value === o.name}
|
||||
className={classNames({ 'p-invalid': fieldState.invalid })}/>
|
||||
<label htmlFor={`${fieldName}_${o.name}`}>{o.label}</label>
|
||||
</div>)}/>
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required ? '*' : null}
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
{input}
|
||||
{infoText ? <small>{infoText}</small> : null}
|
||||
|
||||
@@ -27,13 +27,14 @@ const Select = ({
|
||||
onChange={(e) => field.onChange(e.value)}
|
||||
options={options}
|
||||
optionLabel="label"
|
||||
optionValue="name"
|
||||
placeholder={placeholder}
|
||||
className={classNames({ 'p-invalid': fieldState.invalid })}/>
|
||||
)}/>
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required ? '*' : null}
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
{inputgroup
|
||||
? <div className="p-inputgroup flex-1">
|
||||
|
||||
@@ -34,7 +34,7 @@ const Switch = ({
|
||||
<>
|
||||
<div className="appForm__row">
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] }, 'mr-8')}>
|
||||
{label}{config.required ? '*' : null}
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
<div className="appForm__row">
|
||||
{offLabel ? <span>{offLabel}</span> : null}
|
||||
|
||||
@@ -16,7 +16,7 @@ const TextArea = ({
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required ? '*' : null}
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
<Controller
|
||||
name={fieldName}
|
||||
|
||||
@@ -31,7 +31,7 @@ const TextInput = ({
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required ? '*' : null}
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
{inputgroup
|
||||
? <div className="p-inputgroup flex-1">
|
||||
|
||||
54
src/components/FormField/components/Wysiwyg/index.js
Normal file
54
src/components/FormField/components/Wysiwyg/index.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import { Controller } from 'react-hook-form';
|
||||
import { Editor } from 'primereact/editor';
|
||||
|
||||
const Wysiwyg = ({
|
||||
fieldName,
|
||||
label,
|
||||
control,
|
||||
rows = 3,
|
||||
errors,
|
||||
defaultValue,
|
||||
config = {},
|
||||
infoText = null
|
||||
}) => {
|
||||
|
||||
const renderHeader = () => {
|
||||
return (
|
||||
<span className="ql-formats">
|
||||
<button className="ql-bold" aria-label="Bold"></button>
|
||||
<button className="ql-italic" aria-label="Italic"></button>
|
||||
<button className="ql-underline" aria-label="Underline"></button>
|
||||
<button className="ql-link" aria-label="Link"></button>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const header = renderHeader();
|
||||
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||
{label}{config.required || config.isRequired ? '*' : null}
|
||||
</label>
|
||||
<Controller
|
||||
name={fieldName}
|
||||
control={control}
|
||||
defaultValue={defaultValue}
|
||||
rules={config}
|
||||
render={({ field, fieldState }) => (
|
||||
<Editor
|
||||
id={field.name}
|
||||
{...field}
|
||||
headerTemplate={header}
|
||||
onTextChange={(e) => field.onChange(e.htmlValue)}
|
||||
style={{ height: 80 * rows }}
|
||||
className={classNames({ 'p-invalid': fieldState.invalid })}
|
||||
/>
|
||||
)}/>
|
||||
{infoText ? <small>{infoText}</small> : null}
|
||||
</>)
|
||||
}
|
||||
|
||||
export default Wysiwyg;
|
||||
@@ -12,6 +12,8 @@ import NumberInput from './components/NumberInput';
|
||||
import Switch from './components/Switch';
|
||||
import Select from './components/Select';
|
||||
import Radio from './components/Radio';
|
||||
import Wysiwyg from './components/Wysiwyg';
|
||||
import Checkboxes from './components/Checkboxes';
|
||||
|
||||
const FormField = (props) => {
|
||||
const fields = {
|
||||
@@ -23,7 +25,9 @@ const FormField = (props) => {
|
||||
numberinput: NumberInput,
|
||||
switch: Switch,
|
||||
select: Select,
|
||||
radio: Radio
|
||||
radio: Radio,
|
||||
wysiwyg: Wysiwyg,
|
||||
checkboxes: Checkboxes
|
||||
}
|
||||
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { classNames } from 'primereact/utils';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { head, isEmpty, isNil, pluck } from 'ramda';
|
||||
import { diff } from 'deep-object-diff';
|
||||
import { klona } from 'klona';
|
||||
|
||||
// components
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
@@ -97,8 +98,10 @@ const FormFieldRepeater = ({
|
||||
const storeFieldData = data ?? [];
|
||||
setStateFieldData(storeFieldData);
|
||||
setStateOptionsData(prevState => {
|
||||
const ids = pluck('id', storeFieldData)
|
||||
const objectsToAdd = storeFieldData.filter(o => ids.includes(o.id));
|
||||
const ids = pluck('lookUpDataId', prevState)
|
||||
const objectsToAdd = klona(storeFieldData)
|
||||
.filter(o => !ids.includes(o.lookUpDataId))
|
||||
.map(o => ({...o, id: null}));
|
||||
return [...prevState, ...objectsToAdd];
|
||||
});
|
||||
}
|
||||
@@ -120,7 +123,7 @@ const FormFieldRepeater = ({
|
||||
{stateFieldData.map((o, i) => <div key={i} className={classNames('appForm__repeaterItem')}>
|
||||
<div className="p-inputgroup flex-1">
|
||||
{properField(o, i)}
|
||||
<Button icon="pi pi-times" className="p-button-danger" onClick={() => removeItem(i)}/>
|
||||
<Button type="button" icon="pi pi-times" className="p-button-danger" onClick={() => removeItem(i)}/>
|
||||
</div>
|
||||
{isNil(o.lookUpDataId) && infoText ? <small>{infoText}</small> : null}
|
||||
</div>)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { head, isNil, pluck } from 'ramda';
|
||||
import { head, isEmpty, isNil, pluck } from 'ramda';
|
||||
|
||||
// components
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
@@ -9,6 +9,8 @@ import { Button } from 'primereact/button';
|
||||
import { Menu } from 'primereact/menu';
|
||||
import { Dropdown } from 'primereact/dropdown';
|
||||
import { InputNumber } from 'primereact/inputnumber';
|
||||
import { diff } from 'deep-object-diff';
|
||||
import { klona } from 'klona';
|
||||
|
||||
const FormFieldRepeaterCriteria = ({
|
||||
data,
|
||||
@@ -99,6 +101,22 @@ const FormFieldRepeaterCriteria = ({
|
||||
})
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const diffData = diff(data[fieldName], stateFieldData);
|
||||
|
||||
if (!isEmpty(diffData)) {
|
||||
const storeFieldData = data[fieldName] ?? [];
|
||||
setStateFieldData(storeFieldData);
|
||||
setStateOptionsData(prevState => {
|
||||
const ids = pluck('lookUpDataId', prevState)
|
||||
const objectsToAdd = klona(storeFieldData)
|
||||
.filter(o => !ids.includes(o.lookUpDataId))
|
||||
.map(o => ({...o, id: null, score: 0}));
|
||||
return [...prevState, ...objectsToAdd];
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
setStateOptionsData([...options]);
|
||||
}, [options]);
|
||||
@@ -126,7 +144,7 @@ const FormFieldRepeaterCriteria = ({
|
||||
<label>{__('Nome criterio di valutazione', 'gepafin')}</label>
|
||||
<div className="p-inputgroup flex-1">
|
||||
{properField(o, i)}
|
||||
<Button icon="pi pi-times" className="p-button-danger" onClick={() => removeItem(i)}/>
|
||||
<Button type="button" icon="pi pi-times" className="p-button-danger" onClick={() => removeItem(i)}/>
|
||||
</div>
|
||||
{isNil(o.lookUpDataId) && infoText ? <small>{infoText}</small> : null}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user