- added registartion page;

- implemented validation helper-functions;
- fixed form fields datepicker and datepicker range;
- updated routes logic;
- fixed FAQ items editing/submission;
This commit is contained in:
Vitalii Kiiko
2024-09-23 10:05:43 +02:00
parent cf149485e0
commit bbf117eb9b
58 changed files with 1238 additions and 392 deletions

View File

@@ -4,6 +4,9 @@ import { __ } from '@wordpress/i18n';
// components
import ElementSettingRepeater from '../ElementSettingRepeater';
import { InputText } from 'primereact/inputtext';
import { MultiSelect } from 'primereact/multiselect';
import { mimeTypes } from '../../../../../../configData';
const ElementSetting = ({ setting, changeFn, updateDataFn }) => {
@@ -19,7 +22,15 @@ const ElementSetting = ({ setting, changeFn, updateDataFn }) => {
<label htmlFor={setting.name}>{settingLabels[setting.name]}</label>
{setting.name === 'options'
? <ElementSettingRepeater value={setting.value} name={setting.name} setDataFn={updateDataFn}/>
: <InputText id={setting.name} aria-describedby={`${setting.name}-help`}
: setting.name === 'mime'
? <MultiSelect
value={setting.value}
onChange={(e) => updateDataFn(setting.name, e.value)}
options={mimeTypes}
optionLabel="name"
display="chip"
placeholder={__('Scegli', 'gepafin')} />
: <InputText id={setting.name} aria-describedby={`${setting.name}-help`}
value={setting.value}
onChange={(e) => changeFn(e.target.value, setting.name)}/>}
</div>

View File

@@ -56,7 +56,7 @@ const ElementSettingRepeater = ({
<Button icon="pi pi-times" className="p-button-danger" onClick={() => removeItem(i)}/>
</div>
</div>)}
<Button type="button" label={__('Aggiungi', 'gepafin')} onClick={addNewItem}/>
<Button type="button" outlined label={__('Aggiungi', 'gepafin')} onClick={addNewItem}/>
</div>
)
}

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { head, isNil } from 'ramda';
import { head, isEmpty, isNil } from 'ramda';
import { __, sprintf } from '@wordpress/i18n';
import { klona } from 'klona';
@@ -13,6 +13,7 @@ import { Tag } from 'primereact/tag';
import { TabView, TabPanel } from 'primereact/tabview';
import { InputSwitch } from 'primereact/inputswitch';
import ElementSetting from './components/ElementSetting';
import { Dropdown } from 'primereact/dropdown';
const BuilderElementSettings = ({ closeSettings }) => {
const elements = useStore().main.formElements();
@@ -20,7 +21,17 @@ const BuilderElementSettings = ({ closeSettings }) => {
const [activeElementData, setActiveElementData] = useState({});
const [settings, setSettings] = useState([]);
const [validators, setValidators] = useState({});
const textBasedValidatorFields = ['min', 'max', 'minLength', 'maxLength', 'pattern', 'custom'];
const textBasedValidatorFields = ['min', 'max', 'minLength', 'maxLength', 'pattern'];
const customValidationOptions = [
{value: 'isPIVA', label: 'isPIVA'},
{value: 'isCodiceFiscale', label: 'isCodiceFiscale'},
{value: 'isCAP', label: 'isCAP'},
{value: 'isIBAN', label: 'isIBAN'},
{value: 'isEmail', label: 'isEmail'},
{value: 'isEmailPEC', label: 'isEmailPEC'},
{value: 'isUrl', label: 'isUrl'},
{value: 'isMarcaDaBollo', label: 'isMarcaDaBollo'}
]
const onChange = (value, name) => {
const newSettings = settings
@@ -89,7 +100,7 @@ const BuilderElementSettings = ({ closeSettings }) => {
setSettings([]);
setValidators({})
}
}, [activeElement])
}, [activeElement]);
return (activeElementData
? <div className="formElementSettings">
@@ -110,13 +121,13 @@ const BuilderElementSettings = ({ closeSettings }) => {
className="formElementSettings__field" key={k}>
{k === 'isRequired'
? <div className="formElementSettings__field">
<label htmlFor={k}>{__('Required?', 'gepafin')}</label>
<label htmlFor={k}>{__('Obligatorio?', 'gepafin')}</label>
<InputSwitch
checked={validators[k]}
onChange={(e) => toggleRequired(e.value, k)}/>
</div>
: null}
{textBasedValidatorFields.includes(k)
{textBasedValidatorFields.includes(k) || 'custom' === k
? <div className="formElementSettings__field">
<label htmlFor={`enable_${k}`}>{sprintf(__('Set %s', 'gepafin'), k)}</label>
<InputSwitch
@@ -124,6 +135,19 @@ const BuilderElementSettings = ({ closeSettings }) => {
onChange={(e) => showField(e.value, k)}/>
</div>
: null}
{k === 'custom' && !isNil(validators[k])
? <div className="formElementSettings__field">
<label htmlFor={k}>{__('Personalizzato', 'gepafin')}</label>
<Dropdown
id={`enable_${k}`}
value={validators[k]}
onChange={(e) => onChangeValidator(e.value, k)}
options={customValidationOptions}
optionLabel="label"
optionValue="value"
placeholder={__('Scegli', 'gepafin')}/>
</div>
: null}
{textBasedValidatorFields.includes(k) && !isNil(validators[k])
? <div className="formElementSettings__field">
<label htmlFor={k}>{k}</label>

View File

@@ -1,4 +1,4 @@
import React, { useCallback } from 'react'
import React, { useCallback, useEffect } from 'react'
import { __ } from '@wordpress/i18n';
import { isEmpty } from 'ramda';
@@ -47,6 +47,12 @@ const FormBuilder = () => {
storeSet.main.activeElement('');
}
useEffect(() => {
return () => {
storeSet.main.activeElement('');
}
}, []);
return (
<>
<Sidebar visible={!isEmpty(activeElement)} onHide={closeSettings} className="formBuilder__elementSettings">

View File

@@ -1,9 +1,10 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useRef } from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { klona } from 'klona';
import { isEmpty } from 'ramda';
// store
import { storeSet, storeGet, useStore } from '../../store';
@@ -13,17 +14,23 @@ import FormBuilder from './components/FormBuilder';
import { Button } from 'primereact/button';
import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup';
import { InputText } from 'primereact/inputtext';
import { Toast } from 'primereact/toast';
import { ConfirmDialog } from 'primereact/confirmdialog';
// api
import FormsService from '../../service/forms-service';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import { elementItems } from '../../tempData';
import { Messages } from 'primereact/messages';
const BandoFormsEdit = () => {
const { id, formId } = useParams();
const navigate = useNavigate();
const [formName, setFormName] = useState('');
const [visibleConfirmation, setVisibleConfirmation] = useState(false);
const isAsyncRequest = useStore().main.isAsyncRequest();
const formMsgs = useRef(null);
const toast = useRef(null);
const getBandoId = () => {
const parsed = parseInt(id)
@@ -32,13 +39,46 @@ const BandoFormsEdit = () => {
const goBack = () => {
const bandoId = getBandoId();
navigate(`/tenders/${bandoId}/forms`);
navigate(`/bandi/${bandoId}/forms`);
}
const doSave = (shouldRedirect = false) => {
if (formMsgs.current) {
formMsgs.current.clear();
}
const content = storeGet.main.formElements();
if (isEmpty(formName) || isEmpty(content)) {
if (isEmpty(formName)) {
if (formMsgs.current) {
formMsgs.current.show([
{
id: '99',
sticky: true, severity: 'error', summary: '',
detail: __('Nome di form è obligatorio.', 'gepafin'),
closable: true
}
]);
}
}
if (isEmpty(content)) {
if (formMsgs.current) {
formMsgs.current.show([
{
id: '99',
sticky: true, severity: 'error', summary: '',
detail: __('Devi aggiungere almeno uno campo.', 'gepafin'),
closable: true
}
]);
}
}
}
const bandoId = getBandoId();
const parsedFormId = parseInt(formId)
const parsedFormId = parseInt(formId);
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
const formData = {
label: formName,
@@ -47,9 +87,20 @@ const BandoFormsEdit = () => {
storeSet.main.setAsyncRequest();
if (bandoFormId === 0) {
FormsService.createFormForCall(bandoId, formData, (data) => formCreateCallback(data, shouldRedirect), errFormCreateCallback);
FormsService.createFormForCall(
bandoId,
formData,
(data) => formCreateCallback(data, shouldRedirect),
errFormCreateCallback
);
} else {
FormsService.updateForm(bandoFormId, formData, (data) => formCreateCallback(data, shouldRedirect), errFormCreateCallback);
FormsService.updateForm(
bandoFormId,
formData,
(data) => formCreateCallback(data, shouldRedirect),
errFormCreateCallback,
[['forceDeleteFlow', false]]
);
}
}
@@ -58,18 +109,59 @@ const BandoFormsEdit = () => {
storeSet.main.unsetAsyncRequest();
const bandoId = getBandoId();
if (shouldRedirect) {
navigate(`/tenders/${bandoId}/forms/${data.data.id}/preview`);
navigate(`/bandi/${bandoId}/forms/${data.data.id}/preview`);
return;
}
if (data.data.id) {
navigate(`/tenders/${bandoId}/forms/${data.data.id}`);
navigate(`/bandi/${bandoId}/forms/${data.data.id}`);
}
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: __('Il form è stato aggiornato corretamente!', 'gepafin')
});
}
}
}
const errFormCreateCallback = (data) => {
console.log('errFormCreateCallback', data)
storeSet.main.unsetAsyncRequest();
if (data.status === 'BAD_REQUEST') {
setVisibleConfirmation(true);
} else {
if (toast.current) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
}
}
const acceptModification = () => {
const content = storeGet.main.formElements();
const parsedFormId = parseInt(formId);
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
const formData = {
label: formName,
content
}
storeSet.main.setAsyncRequest();
FormsService.updateForm(
bandoFormId,
formData,
(data) => formCreateCallback(data, false),
errFormCreateCallback,
[['forceDeleteFlow', true]]
);
}
const rejectModification = () => {
setVisibleConfirmation(false);
}
const openPreview = () => {
@@ -101,7 +193,7 @@ const BandoFormsEdit = () => {
const formDeleteCallback = (data) => {
if (data.status === 'SUCCESS') {
const bandoId = getBandoId();
navigate(`/tenders/${bandoId}/forms`);
navigate(`/bandi/${bandoId}/forms`);
}
storeSet.main.unsetAsyncRequest();
}
@@ -170,6 +262,19 @@ const BandoFormsEdit = () => {
<div className="appPage__spacer"></div>
<Messages ref={formMsgs}/>
<ConfirmDialog
group="declarative"
visible={visibleConfirmation}
onHide={() => setVisibleConfirmation(false)}
message={__('Le modifiche al modulo influiscono sul flusso precedentemente creato, quindi deve essere ricreato. Confermi le modifiche?', 'gepafin')}
header={__('Conferma le modifiche', 'gepafin')}
icon="pi pi-exclamation-triangle"
accept={acceptModification}
acceptLabel={__('Si', 'gepafin')}
reject={rejectModification}
style={{ maxWidth: '500px' }} />
<div className="appForm__field">
<label htmlFor="label">{__('Assegna un nome a questo form', 'gepafin')}</label>
<InputText
@@ -190,6 +295,7 @@ const BandoFormsEdit = () => {
<div className="appPage__spacer"></div>
<Toast ref={toast} />
<div className="appPageSection">
<div className="appPageSection__actions">
<Button