Merge branch 'develop' into feature/46-forms-flow-preview

This commit is contained in:
Vitalii Kiiko
2024-11-29 13:40:53 +01:00
28 changed files with 520 additions and 348 deletions

5
.distignore Normal file
View File

@@ -0,0 +1,5 @@
.git
node_modules
build
environments
public

View File

@@ -14,9 +14,11 @@
"@wordpress/react-i18n": "4.8.0",
"@xyflow/react": "12.3.1",
"codice-fiscale-js": "2.3.22",
"copy-to-clipboard": "^3.3.3",
"deep-object-diff": "^1.1.9",
"dompurify": "3.1.7",
"fast-deep-equal": "3.1.3",
"hotkeys-js": "^3.13.7",
"html-react-parser": "5.1.16",
"jwt-decode": "4.0.0",
"klona": "2.0.6",
@@ -44,6 +46,7 @@
"@babel/plugin-syntax-jsx": "7.24.7",
"@wordpress/babel-plugin-makepot": "6.8.0",
"babel-plugin-macros": "3.1.0",
"node-wp-i18n": "^1.2.7",
"sass": "1.79.3",
"sass-loader": "16.0.2"
},
@@ -55,7 +58,8 @@
"build:dev": "cp environments/dev/* public/loaded-files && rm public/loaded-files/dev.env && cp environments/dev/dev.env .env && react-scripts build --mode development",
"build:prod": "cp environments/prod/* public/loaded-files && rm public/loaded-files/prod.env && cp environments/prod/prod.env .env && react-scripts build --mode production",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"make-pot": "wpi18n makepot --domain-path=languages --domain=gepafin"
},
"eslintConfig": {
"extends": [

View File

@@ -167,6 +167,7 @@
display: flex;
gap: 1rem;
align-items: center;
justify-content: space-between;
padding: 5px 0;
&.rowContent {
@@ -178,7 +179,7 @@
p {
margin: 0;
flex: 1 1 100%;
/*flex: 1 1 100%;*/
}
ul, ol {
@@ -251,6 +252,7 @@
flex-direction: row;
justify-content: space-between;
gap: 16px;
width: 100%;
}
.appPageSection__checklist {

View File

@@ -153,6 +153,16 @@ button[disabled] {
filter: grayscale(1);
}
.iconBtn {
background: transparent;
border: none;
&:hover {
cursor: pointer;
color: var(--primary-text);
}
}
@media (max-width: 800px) {
.inner {
flex-direction: column;

View File

@@ -8,10 +8,15 @@
.p-badge {
color: var(--menuitem-active-color);
}
.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link),
.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link) span {
.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link, .p-column-filter-add-button, .p-column-filter-remove-button),
.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link, .p-column-filter-add-button, .p-column-filter-remove-button) span {
color: var(--menuitem-active-color);
}
.p-column-filter-remove-button {
span {
margin: 0 5px;
}
}
.p-fileupload-row {
.p-button-danger {
background-color: #f44336;

View File

@@ -9,6 +9,7 @@ import { is, isNil } from 'ramda';
// store
import { storeGet } from '../../store';
import formatDateString from '../../helpers/formatDateString';
const UnsavedChangesDetector = ({ getValuesFn }) => {
const warnIfUnsavedChanges = (event) => {
@@ -16,16 +17,15 @@ const UnsavedChangesDetector = ({ getValuesFn }) => {
formData.dates = [];
if (formData.startDate) {
let starDate;
let startDate;
if (is(String, formData.startDate)) {
starDate = formData.startDate;
startDate = formData.startDate;
} else {
const tzAwareDate = new TZDate(formData.startDate, 'Europe/Berlin');
starDate = tzAwareDate.toISOString().substring(0, 19);
startDate = formatDateString(formData.startDate);
}
formData = wrap(formData).insert(['dates'], starDate, 0).value();
formData = wrap(formData).insert(['dates'], startDate, 0).value();
delete formData.startDate;
}
if (formData.endDate) {
@@ -34,8 +34,7 @@ const UnsavedChangesDetector = ({ getValuesFn }) => {
if (is(String, formData.endDate)) {
endDate = formData.endDate;
} else {
const tzAwareDate = new TZDate(formData.endDate, 'Europe/Berlin');
endDate = tzAwareDate.toISOString().substring(0, 19);
endDate = formatDateString(formData.endDate);
}
formData = wrap(formData).insert(['dates'], endDate, 1).value();

View File

@@ -0,0 +1,18 @@
/**
*
* @param dateObj {Date}
* @return {Date}
*/
const createUTCDate = (dateObj) => {
const comps = {
year: dateObj.getFullYear(),
month: dateObj.getMonth(),
day: dateObj.getDate(),
hours: dateObj.getHours(),
minutes: dateObj.getMinutes(),
seconds: dateObj.getSeconds()
};
return new Date(Date.UTC(comps.year, comps.month, comps.day, 0, 0, 0));
}
export default createUTCDate;

View File

@@ -0,0 +1,13 @@
/**
*
* @param date {Date}
* @return {string}
*/
const formatDateString = (date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}T00:00:00`;
}
export default formatDateString;

View File

@@ -14,9 +14,6 @@ import BandoService from '../../../../service/bando-service';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Dropdown } from 'primereact/dropdown';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
@@ -30,7 +27,6 @@ const AllBandiTable = () => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
@@ -62,16 +58,6 @@ const AllBandiTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -80,17 +66,12 @@ const AllBandiTable = () => {
end_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
});
setGlobalFilterValue('');
};
const renderHeader = () => {
return (
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
<IconField iconPosition="left">
<InputIcon className="pi pi-search" />
<InputText value={globalFilterValue} onChange={onGlobalFilterChange} placeholder={__('Cerca', 'gepafin')} />
</IconField>
</div>
);
};
@@ -134,13 +115,13 @@ const AllBandiTable = () => {
return(
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>
<Column field="name" header={__('Nome Bando', 'gepafin')}
filter filterPlaceholder={__('Cerca', 'gepafin')}
filter sortable
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data Pubblicazione', 'gepafin')} filterField="start_date" dataType="date"
style={{ minWidth: '8rem' }}

View File

@@ -3,7 +3,6 @@ import { __, sprintf } from '@wordpress/i18n';
import { useParams } from 'react-router-dom';
import { head, is, pluck, isEmpty, pathOr } from 'ramda';
import { useForm } from 'react-hook-form';
import { TZDate } from '@date-fns/tz';
import 'quill/dist/quill.core.css';
import { wrap } from 'object-path-immutable';
@@ -40,6 +39,7 @@ import { Dialog } from 'primereact/dialog';
import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
import { defaultMaxFileSize } from '../../configData';
import formatDateString from '../../helpers/formatDateString';
const BandoApplication = () => {
const chosenCompanyId = useStore().main.chosenCompanyId();
@@ -192,8 +192,7 @@ const BandoApplication = () => {
let fieldVal = formValues[cur];
if (formValues[cur] && formValues[cur].toISOString) {
const tzAwareDate = new TZDate(formValues[cur], 'Europe/Berlin');
fieldVal = tzAwareDate.toISOString().substring(0, 19);
fieldVal = formatDateString(formValues[cur]);
}
fieldVal = isEmpty(fieldVal) ? null : fieldVal;

View File

@@ -26,6 +26,7 @@ import { isEmail } from '../../../../helpers/validators';
import { storeSet } from '../../../../store';
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString';
import formatDateString from '../../../../helpers/formatDateString';
const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, getFormErrors, status }, ref) {
const navigate = useNavigate();
@@ -62,8 +63,7 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
if (is(String, formData.startDate)) {
starDate = formData.startDate;
} else {
const tzAwareDate = new TZDate(formData.startDate, 'Europe/Berlin');
starDate = tzAwareDate.toISOString().substring(0, 19);
starDate = formatDateString(formData.startDate);
}
formData = wrap(formData).insert(['dates'], starDate, 0).value();
@@ -74,8 +74,7 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
if (is(String, formData.endDate)) {
endDate = formData.endDate;
} else {
const tzAwareDate = new TZDate(formData.endDate, 'Europe/Berlin');
endDate = tzAwareDate.toISOString().substring(0, 19);
endDate = formatDateString(formData.endDate);
}
formData = wrap(formData).insert(['dates'], endDate, 1).value();

View File

@@ -23,6 +23,7 @@ import { storeSet } from '../../../../store';
import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString';
import { mimeTypes } from '../../../../configData';
import { wrap } from 'object-path-immutable';
import formatDateString from '../../../../helpers/formatDateString';
const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, getFormErrors, status }, ref) {
const navigate = useNavigate();
@@ -60,8 +61,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
if (is(String, formData.startDate)) {
starDate = formData.startDate;
} else {
const tzAwareDate = new TZDate(formData.startDate, 'Europe/Berlin');
starDate = tzAwareDate.toISOString().substring(0, 19);
starDate = formatDateString(formData.starDate);
}
formData = wrap(formData).insert(['dates'], starDate, 0).value();
@@ -72,8 +72,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
if (is(String, formData.endDate)) {
endDate = formData.endDate;
} else {
const tzAwareDate = new TZDate(formData.endDate, 'Europe/Berlin');
endDate = tzAwareDate.toISOString().substring(0, 19);
endDate = formatDateString(formData.endDate);
}
formData = wrap(formData).insert(['dates'], endDate, 1).value();

View File

@@ -3,31 +3,36 @@ import { __ } from '@wordpress/i18n';
import { useParams, useNavigate } from 'react-router-dom';
import { isEmpty } from 'ramda';
import { classNames } from 'primereact/utils';
import { klona } from 'klona';
// components
import { Button } from 'primereact/button';
import { Dropdown } from 'primereact/dropdown';
// store
import { storeSet } from '../../store';
// service
import FormsService from '../../service/forms-service';
// store
import { storeSet } from '../../store';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import BandoService from '../../service/bando-service';
// tools
import uniqid from '../../helpers/uniqid';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
// components
import { Button } from 'primereact/button';
import { Dropdown } from 'primereact/dropdown';
import BandoService from '../../service/bando-service';
import { Toast } from 'primereact/toast';
const BandoForms = () => {
const { id } = useParams();
const navigate = useNavigate()
const [templates, setTemplates] = useState(null);
const [selectedTemplate, setSelectedTemplate] = useState(null);
const [selectedForm, setSelectedForm] = useState(null);
const [selectedForDuplicateForm, setSelectedForDuplicateForm] = useState(null);
const [selectedForDuplicateForm, setSelectedForDuplicateForm] = useState(0);
const [forms, setForms] = useState([]);
const [bandoStatus, setBandoStatus] = useState('');
const [allBandiOptions, setAllBandiOptions] = useState([]);
const [allBandiIsLoading, setAllBandiIsLoading] = useState(false);
const [selectedBandoIdForDuplicate, setSelectedBandoIdForDuplicate] = useState(0);
const [allFormsOptions, setAllFormsOptions] = useState([]);
const [allFormsIsLoading, setAllFormsIsLoading] = useState(false);
const [selectedFormIdForDuplicate, setSelectedFormIdForDuplicate] = useState(0);
const toast = useRef(null);
const doCreateNewForm = () => {
@@ -53,11 +58,11 @@ const BandoForms = () => {
if (!isEmpty(selectedFormArr)) {
storeSet.main.setAsyncRequest();
FormsService.getFormById(selectedForDuplicateForm, getFormCallback, errGetFormCallbacks);
FormsService.getFormById(selectedForDuplicateForm, getFormDuplicateCallback, errGetFormDuplicateCallbacks);
}
}
const getFormCallback = (data) => {
const getFormDuplicateCallback = (data) => {
if (data.status === 'SUCCESS') {
const newLabel = `${data.data.label} (copy)`;
@@ -76,9 +81,10 @@ const BandoForms = () => {
errFormCreateCallback
);
}
storeSet.main.unsetAsyncRequest();
}
const errGetFormCallbacks = (data) => {
const errGetFormDuplicateCallbacks = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
@@ -141,17 +147,52 @@ const BandoForms = () => {
storeSet.main.unsetAsyncRequest();
}
const getAllBandiCallback = (data) => {
if (data.status === 'SUCCESS') {
setAllBandiOptions(data.data.filter(o => o.id !== parseInt(id)).map(o => ({ label: o.name, value: o.id })))
}
setAllBandiIsLoading(false);
}
const errGetAllBandiCallback = () => {
setAllBandiIsLoading(false);
}
const getAllFormsCallback = (data) => {
if (data.status === 'SUCCESS') {
setAllFormsOptions(data.data.map(o => ({ label: o.label, value: o.id })));
}
setAllFormsIsLoading(false);
}
const errGetAllFormsCallback = () => {
setAllFormsIsLoading(false);
}
const doDuplicateFormOfAnotherBando = () => {
if (selectedBandoIdForDuplicate !== 0 && selectedFormIdForDuplicate !== 0) {
storeSet.main.setAsyncRequest();
FormsService.getFormById(selectedFormIdForDuplicate, getFormDuplicateCallback, errGetFormDuplicateCallbacks);
}
}
useEffect(() => {
if (selectedBandoIdForDuplicate !== 0) {
setAllFormsIsLoading(true);
FormsService.getFormsForCall(selectedBandoIdForDuplicate, getAllFormsCallback, errGetAllFormsCallback);
}
}, [selectedBandoIdForDuplicate]);
useEffect(() => {
const parsed = parseInt(id)
const bandoId = !isNaN(parsed) ? parsed : 0;
setTemplates([
{ label: 'Form template', value: 11 }
])
storeSet.main.setAsyncRequest();
BandoService.getBando(id, getCallback, errGetCallback);
FormsService.getFormsForCall(bandoId, getFormsCallback, errGetFormsCallback);
setAllBandiIsLoading(true);
BandoService.getBandi(getAllBandiCallback, errGetAllBandiCallback);
}, [id]);
return (
@@ -164,7 +205,7 @@ const BandoForms = () => {
</div>
<div className="appPage__spacer"></div>
<Toast ref={toast} />
<Toast ref={toast}/>
<div className="appPage__content">
@@ -191,7 +232,7 @@ const BandoForms = () => {
</div>*/}
<div className="appPageSection__withBorder">
<h2>{__('Crea un nuovo Form da Zero', 'gepafin')}</h2>
<h2>{__('Crea un nuovo Form o duplica', 'gepafin')}</h2>
<div className="row">
<p>{__('Inizia con un form completamente vuoto e personalizzabile', 'gepafin')}</p>
<Button
@@ -202,19 +243,46 @@ const BandoForms = () => {
</div>
<div className="row">
<p>{__('Duplica il form creato in precedenza', 'gepafin')}</p>
<Dropdown
id="form"
disabled={isEmpty(forms)}
value={selectedForDuplicateForm}
onChange={(e) => setSelectedForDuplicateForm(e.value)}
options={forms}
optionLabel="label"
placeholder={__('Seleziona form', 'gepafin')}/>
<Button
type="button"
disabled={'PUBLISH' === bandoStatus || isEmpty(forms)}
onClick={doDuplicateForm}
label={__('Duplicare', 'gepafin')}/>
<div className="row">
<Dropdown
id="form"
disabled={isEmpty(forms)}
value={selectedForDuplicateForm}
onChange={(e) => setSelectedForDuplicateForm(e.value)}
options={forms}
optionLabel="label"
placeholder={__('Seleziona form', 'gepafin')}/>
<Button
type="button"
disabled={'PUBLISH' === bandoStatus || isEmpty(forms) || selectedForDuplicateForm === 0}
onClick={doDuplicateForm}
label={__('Duplicare', 'gepafin')}/>
</div>
</div>
<div className="row">
<p>{__('Duplica il form dal altro bando', 'gepafin')}</p>
<div className="row">
<Dropdown
id="form"
disabled={allBandiIsLoading}
value={selectedBandoIdForDuplicate}
onChange={(e) => setSelectedBandoIdForDuplicate(e.value)}
options={allBandiOptions}
placeholder={__('Seleziona bando', 'gepafin')}/>
<Dropdown
id="form"
disabled={allFormsIsLoading}
value={selectedFormIdForDuplicate}
onChange={(e) => setSelectedFormIdForDuplicate(e.value)}
options={allFormsOptions}
placeholder={__('Seleziona form', 'gepafin')}/>
<Button
type="button"
disabled={selectedBandoIdForDuplicate === 0 || selectedFormIdForDuplicate === 0}
onClick={doDuplicateFormOfAnotherBando}
label={__('Duplicare', 'gepafin')}/>
</div>
</div>
</div>

View File

@@ -127,7 +127,7 @@ const ElementSettingTableColumns = ({
</div>
})}
<Button type="button" outlined
label={__('Aggiungi una righa', 'gepafin')}
label={__('Aggiungi una riga', 'gepafin')}
onClick={() => addNewRow(findIndex(propEq(o.name, 'name'))(stateFieldData))}/>
</div>
</div>

View File

@@ -147,7 +147,7 @@ const ElementSettingTableColumns = ({
<Button type="button"
outlined
disabled={bandoStatus === 'PUBLISH'}
label={__('Aggiungi una righa', 'gepafin')}
label={__('Aggiungi una riga', 'gepafin')}
onClick={addNewRow}/>
</div>
</div>

View File

@@ -33,7 +33,6 @@ const DraftApplicationsTable = () => {
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
@@ -79,16 +78,6 @@ const DraftApplicationsTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -96,6 +85,10 @@ const DraftApplicationsTable = () => {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
companyName: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
modifiedDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
@@ -106,7 +99,6 @@ const DraftApplicationsTable = () => {
},
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
});
setGlobalFilterValue('');
};
const renderHeader = () => {
@@ -114,28 +106,10 @@ const DraftApplicationsTable = () => {
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
<IconField iconPosition="left">
<InputIcon className="pi pi-search"/>
<InputText value={globalFilterValue} onChange={onGlobalFilterChange}
placeholder={__('Cerca', 'gepafin')}/>
</IconField>
</div>
);
};
/*const dateModifyBodyTemplate = (rowData) => {
return formatDate(rowData.modifiedDate);
};
const dateEndBodyTemplate = (rowData) => {
return formatDate(rowData.callEndDate);
};
const dateFilterTemplate = (options) => {
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)}
dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999"/>;
};*/
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
@@ -167,8 +141,7 @@ const DraftApplicationsTable = () => {
return (
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>

View File

@@ -9,9 +9,6 @@ import BandoService from '../../../../service/bando-service';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
@@ -23,7 +20,6 @@ const LatestBandiTable = () => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [, setStatuses] = useState([]);
useEffect(() => {
@@ -66,16 +62,6 @@ const LatestBandiTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -84,17 +70,12 @@ const LatestBandiTable = () => {
end_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] }
});
setGlobalFilterValue('');
};
const renderHeader = () => {
return (
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
<IconField iconPosition="left">
<InputIcon className="pi pi-search" />
<InputText value={globalFilterValue} onChange={onGlobalFilterChange} placeholder={__('Cerca', 'gepafin')} />
</IconField>
</div>
);
};
@@ -126,12 +107,13 @@ const LatestBandiTable = () => {
return(
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>
<Column field="name" header={__('Nome Bando', 'gepafin')} filter filterPlaceholder={__('Cerca il nome', 'gepafin')}
<Column field="name" header={__('Nome Bando', 'gepafin')}
filter sortable
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data Pubblicazione', 'gepafin')} filterField="start_date" dataType="date"
style={{ minWidth: '8rem' }}

View File

@@ -17,9 +17,6 @@ import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
@@ -32,7 +29,6 @@ const LatestBandiTable = () => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [loading, setLoading] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [, setStatuses] = useState([]);
useEffect(() => {
@@ -130,16 +126,6 @@ const LatestBandiTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -157,7 +143,6 @@ const LatestBandiTable = () => {
},
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] }
});
setGlobalFilterValue('');
};
const renderHeader = () => {
@@ -165,11 +150,6 @@ const LatestBandiTable = () => {
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
<IconField iconPosition="left">
<InputIcon className="pi pi-search"/>
<InputText value={globalFilterValue} onChange={onGlobalFilterChange}
placeholder={__('Cerca', 'gepafin')}/>
</IconField>
</div>
);
};
@@ -210,12 +190,12 @@ const LatestBandiTable = () => {
return (
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={loading} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>
<Column field="name" header={__('Nome Bando', 'gepafin')} filter
<Column field="name" header={__('Nome Bando', 'gepafin')}
filter sortable
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data Pubblicazione', 'gepafin')} filterField="start_date" dataType="date"

View File

@@ -16,9 +16,6 @@ import ApplicationService from '../../../../service/application-service';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Dropdown } from 'primereact/dropdown';
import { ProgressBar } from 'primereact/progressbar';
import { Button } from 'primereact/button';
@@ -33,7 +30,6 @@ const MyLatestSubmissionsTable = () => {
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
@@ -82,16 +78,6 @@ const MyLatestSubmissionsTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -99,6 +85,10 @@ const MyLatestSubmissionsTable = () => {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
companyName: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
modifiedDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
@@ -109,7 +99,6 @@ const MyLatestSubmissionsTable = () => {
},
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
});
setGlobalFilterValue('');
};
const renderHeader = () => {
@@ -117,11 +106,6 @@ const MyLatestSubmissionsTable = () => {
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
<IconField iconPosition="left">
<InputIcon className="pi pi-search"/>
<InputText value={globalFilterValue} onChange={onGlobalFilterChange}
placeholder={__('Cerca', 'gepafin')}/>
</IconField>
</div>
);
};
@@ -173,13 +157,12 @@ const MyLatestSubmissionsTable = () => {
return (
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>
<Column field="callTitle" header={__('Bando', 'gepafin')}
sortable
filter sortable
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="companyName" header={__('Azienda', 'gepafin')}

View File

@@ -17,9 +17,6 @@ import getBandoSeverity from '../../../../helpers/getBandoSeverity';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
@@ -33,7 +30,6 @@ const PreInstructorDomandeTable = () => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
@@ -76,16 +72,6 @@ const PreInstructorDomandeTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -93,6 +79,10 @@ const PreInstructorDomandeTable = () => {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
companyName: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
submissionDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
@@ -102,17 +92,12 @@ const PreInstructorDomandeTable = () => {
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}
});
setGlobalFilterValue('');
};
const renderHeader = () => {
return (
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
<IconField iconPosition="left">
<InputIcon className="pi pi-search" />
<InputText value={globalFilterValue} onChange={onGlobalFilterChange} placeholder={__('Cerca', 'gepafin')} />
</IconField>
</div>
);
};
@@ -152,8 +137,7 @@ const PreInstructorDomandeTable = () => {
return(
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>

View File

@@ -0,0 +1,106 @@
import React, { useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty } from 'ramda';
import { wrap } from 'object-path-immutable';
// components
import { Button } from 'primereact/button';
import { Dialog } from 'primereact/dialog';
import { InputTextarea } from 'primereact/inputtextarea';
import { Dropdown } from 'primereact/dropdown';
import { classNames } from 'primereact/utils';
const ArchiveDocument = ({ ndg = '', fileId = 0 }) => {
const [loading, setLoading] = useState(false);
const [isVisibleDialog, setIsVisibleDialog] = useState(false);
const [modalData, setModalData] = useState({});
const [categories, setCategories] = useState([]);
const openArchivationModal = () => {
setIsVisibleDialog(true);
setModalData({
description: '',
categoryId: 0,
fileId
});
}
const headerDialog = () => {
return <span>{__('Archive document', 'gepafin')}</span>;
}
const hideDialog = () => {
setIsVisibleDialog(false);
setModalData({});
}
const setValue = (name, value) => {
const newData = wrap(modalData).set(name, value).value();
setModalData(newData);
}
const footerDialog = () => {
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideDialog} outlined/>
<Button
type="button"
disabled={loading}
label={__('Invia', 'gepafin')} onClick={submitData}/>
</div>
}
const submitData = () => {
console.log('submitData', modalData)
}
useEffect(() => {
setCategories([
{value: 1, label: 'Type 1'},
{value: 2, label: 'Type 2'},
])
}, []);
return (
<>
{!isEmpty(ndg)
? <Button icon="pi pi-file-export"
rounded
onClick={openArchivationModal}
outlined
severity="info"
aria-label={__('Mostra', 'gepafin')}/>
: null}
<Dialog
visible={isVisibleDialog}
modal
header={headerDialog}
footer={footerDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideDialog}>
<div className="appForm__field">
<label className={classNames({ 'p-error': !modalData.categoryId || modalData.categoryId === 0 })}>
{__('Classificazione', 'gepafin')}*
</label>
<Dropdown
value={modalData.categoryId}
invalid={!modalData.categoryId || modalData.categoryId === 0}
onChange={(e) => setValue('categoryId', e.value)}
options={categories}/>
</div>
<div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(modalData.description) })}>
{__('Descrizione', 'gepafin')}
</label>
<InputTextarea
value={modalData.description}
invalid={isEmpty(modalData.description)}
onChange={(e) => setValue('description', e.target.value)}
rows={3}
cols={30}/>
</div>
</Dialog>
</>
)
}
export default ArchiveDocument;

View File

@@ -28,6 +28,10 @@ import BlockingOverlay from '../../components/BlockingOverlay';
import { Toast } from 'primereact/toast';
import HelpIcon from '../../icons/HelpIcon';
import { Dialog } from 'primereact/dialog';
import ArchiveDocument from './components/ArchiveDocument';
import { classNames } from 'primereact/utils';
import { InputTextarea } from 'primereact/inputtextarea';
import { InputText } from 'primereact/inputtext';
const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
@@ -46,6 +50,13 @@ const DomandaEditPreInstructor = () => {
const [isVisibleCompleteDialog, setIsVisibleCompleteDialog] = useState(false);
const [operationType, setOperationType] = useState('');
const [motivation, setMotivation] = useState('');
const [isVisibleAppointmentDialog, setIsVisibleAppointmentDialog] = useState(false);
const [appointmentData, setAppointmentData] = useState({
title: '',
text: '',
duration: 0,
amount: 0
});
const goToEvaluationsPage = () => {
navigate('/domande');
@@ -53,10 +64,9 @@ const DomandaEditPreInstructor = () => {
const doNewSoccorso = () => {
if (connectedSoccorsoId !== 0) {
navigate(`/domande/${id}/soccorso/${connectedSoccorsoId}`);
doSaveDraft(`/domande/${id}/soccorso/${connectedSoccorsoId}`)
} else {
navigate(`/domande/${id}/aggiungi-soccorso/`);
doSaveDraft(`/domande/${id}/aggiungi-soccorso/`)
}
}
@@ -117,17 +127,22 @@ const DomandaEditPreInstructor = () => {
setData(newData);
}
const doSaveDraft = () => {
const doSaveDraft = (doRedirect = '') => {
const formData = {
criteria: klona(data.criteria),
checklist: klona(data.checklist),
files: klona(data.files),
note: data.note
}
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateCallback, errUpdateCallback);
ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId,
formData,
(data) => updateCallback(data, doRedirect),
errUpdateCallback
);
}
const updateCallback = (data) => {
const updateCallback = (data, doRedirect = '') => {
if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data));
if (toast.current) {
@@ -137,6 +152,9 @@ const DomandaEditPreInstructor = () => {
detail: data.message
});
}
if (!isEmpty(doRedirect)) {
navigate(doRedirect);
}
}
storeSet.main.unsetAsyncRequest();
}
@@ -315,10 +333,53 @@ const DomandaEditPreInstructor = () => {
setIsVisibleCompleteDialog(true);
}
const doCreateAppointment = () => {
const doCheckNDG = () => {
// TODO
}
const doCreateAppointment = () => {
setAppointmentData({
title: '',
text: '',
duration: 0,
amount: 0
});
setIsVisibleAppointmentDialog(true);
}
const setValue = (name, value) => {
const newData = wrap(appointmentData).set(name, value).value();
setAppointmentData(newData);
}
const headerAppointmentDialog = () => {
return <span>{__('Crea appuntamento', 'gepafin')}</span>;
}
const hideAppointmentDialog = () => {
setIsVisibleAppointmentDialog(false);
setAppointmentData({});
}
const footerAppointmentDialog = () => {
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideAppointmentDialog} outlined/>
<Button
type="button"
disabled={loading}
label={__('Invia', 'gepafin')} onClick={doCreateAppointmentRequest}/>
</div>
}
const doCreateAppointmentRequest = () => {
if (
!isEmpty(appointmentData.title) && !isEmpty(appointmentData.text) && !isEmpty(appointmentData.amount)
&& !isEmpty(appointmentData.duration) && appointmentData.duration !== 0 && appointmentData.amount !== 0
) {
console.log(appointmentData);
}
}
const doMakeAdmisible = () => {
// TODO
}
@@ -558,6 +619,7 @@ const DomandaEditPreInstructor = () => {
}}>
<span>{k.name}</span>
<div className="appPageSection__iconActions">
<ArchiveDocument ndg={data.ndg} fileId={k.id}/>
<Button icon="pi pi-eye" rounded
onClick={() => window.open(k.filePath, '_blank').focus()}
outlined severity="info"
@@ -609,6 +671,13 @@ const DomandaEditPreInstructor = () => {
label={__('Crea valutazione', 'gepafin')}
icon="pi pi-save" iconPos="right"/>}
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
? <Button
type="button"
disabled={!data.id}
onClick={doCheckNDG}
label={__('Controlla NDG', 'gepafin')}
/> : null}
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus) && data.ndg
? <Button
type="button"
disabled={!data.id}
@@ -668,6 +737,55 @@ const DomandaEditPreInstructor = () => {
</div>
</Dialog>
<Dialog
visible={isVisibleAppointmentDialog}
modal
header={headerAppointmentDialog}
footer={footerAppointmentDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideAppointmentDialog}>
<div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(appointmentData.amount) || appointmentData.amount === 0})}>
{__('Importo', 'gepafin')}
</label>
<InputNumber
value={appointmentData.amount}
keyfilter="int"
invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0}
onChange={(e) => setValue('amount', e.value)}/>
</div>
<div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(appointmentData.duration) || appointmentData.duration === 0 })}>
{__('Durata', 'gepafin')}
</label>
<InputNumber
value={appointmentData.duration}
keyfilter="int"
invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0}
onChange={(e) => setValue('duration', e.value)}/>
</div>
<div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(appointmentData.title) })}>
{__('Titolo', 'gepafin')}
</label>
<InputText
value={appointmentData.title}
invalid={isEmpty(appointmentData.title)}
onChange={(e) => setValue('title', e.target.value)}/>
</div>
<div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(appointmentData.text) })}>
{__('Messaggio', 'gepafin')}
</label>
<InputTextarea
value={appointmentData.text}
invalid={isEmpty(appointmentData.text)}
onChange={(e) => setValue('text', e.target.value)}
rows={3}
cols={30}/>
</div>
</Dialog>
</div>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>

View File

@@ -3,9 +3,6 @@ import { __ } from '@wordpress/i18n';
import { is, uniq } from 'ramda';
import { Link } from 'react-router-dom';
// store
//import { storeSet, storeGet } from '../../../../store';
// api
import ApplicationService from '../../../../service/application-service';
@@ -13,9 +10,6 @@ import ApplicationService from '../../../../service/application-service';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
@@ -26,7 +20,6 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [, setStatuses] = useState([]);
useEffect(() => {
@@ -70,16 +63,6 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -87,6 +70,10 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
companyName: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
submissionDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
@@ -96,7 +83,6 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}
});
setGlobalFilterValue('');
};
const renderHeader = () => {
@@ -104,11 +90,6 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
<IconField iconPosition="left">
<InputIcon className="pi pi-search"/>
<InputText value={globalFilterValue} onChange={onGlobalFilterChange}
placeholder={__('Cerca', 'gepafin')}/>
</IconField>
</div>
);
};
@@ -152,8 +133,7 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
return (
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>

View File

@@ -17,9 +17,6 @@ import getBandoSeverity from '../../../../helpers/getBandoSeverity';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
@@ -33,7 +30,6 @@ const BeneficiarioDomandeTable = () => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
@@ -83,16 +79,6 @@ const BeneficiarioDomandeTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -100,6 +86,10 @@ const BeneficiarioDomandeTable = () => {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
companyName: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
modifiedDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
@@ -109,7 +99,6 @@ const BeneficiarioDomandeTable = () => {
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}
});
setGlobalFilterValue('');
};
const renderHeader = () => {
@@ -117,11 +106,6 @@ const BeneficiarioDomandeTable = () => {
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
<IconField iconPosition="left">
<InputIcon className="pi pi-search"/>
<InputText value={globalFilterValue} onChange={onGlobalFilterChange}
placeholder={__('Cerca', 'gepafin')}/>
</IconField>
</div>
);
};
@@ -167,8 +151,7 @@ const BeneficiarioDomandeTable = () => {
return (
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>

View File

@@ -2,6 +2,7 @@ import React, { useRef, useEffect, useState } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { classNames } from 'primereact/utils';
import { isEmpty, isNil } from 'ramda';
import hotkeys from 'hotkeys-js';
// store
import { storeSet, useStore } from '../../store';
@@ -111,11 +112,14 @@ const Login = () => {
}
}, [searchParams]);
/*useEffect(() => {
if ('t7jh5wfg9QXylNaTZkPoE' === APP_HUB_ID) {
useEffect(() => {
/*if ('t7jh5wfg9QXylNaTZkPoE' === APP_HUB_ID) {
setIsMaintenance(true);
}
}, [])*/
}*/
hotkeys('command+x', function(event, handler){
window.location.replace('/loginadmin')
});
}, []);
return (
<div className={classNames(['appPage', 'appPageLogin'])}>

View File

@@ -137,7 +137,7 @@ const SoccorsoEditPreInstructor = () => {
}, []);
const submitData = {
applicationFormFields: newFormValues,
applicationFormFields: newFormValues
}
storeSet.main.setAsyncRequest();
AmendmentsService.updateSoccorso(amendmentId, submitData, updateAmendmentCallback, errUpdateAmendmentCallback);
@@ -366,9 +366,10 @@ const SoccorsoEditPreInstructor = () => {
<h3>{__('Documenti Richiesti', 'gepafin')}</h3>
<ol className="appPageSection__list">
{data.formFields
? data.formFields.map((o, i) => <li key={o.fieldId} style={{ flexDirection: 'row' }}>
<span>{o.label}</span>
</li>) : null}
? data.formFields.map((o, i) => <li key={o.fieldId}
style={{ flexDirection: 'row' }}>
<span>{o.label}</span>
</li>) : null}
</ol>
</div>
<div>
@@ -393,26 +394,44 @@ const SoccorsoEditPreInstructor = () => {
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
{data.formFields
? data.formFields.map((o, i) => {
return <FormField
key={o.fieldId}
disabled={data.status === 'CLOSE'}
type="fileupload"
setDataFn={setValue}
saveFormCallback={doUpdateAmendment}
fieldName={o.fieldId}
label={o.label}
control={control}
register={register}
errors={errors}
defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []}
accept={[]}
sourceId={data.applicationId}
multiple={true}
/>
}) : null}
return <FormField
key={o.fieldId}
disabled={data.status === 'CLOSE'}
type="fileupload"
setDataFn={setValue}
saveFormCallback={doUpdateAmendment}
fieldName={o.fieldId}
label={o.label}
control={control}
register={register}
errors={errors}
defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []}
accept={[]}
sourceId={data.applicationId}
multiple={true}
/>
}) : null}
</form>
</div>
<div className="appForm__field">
<label>{__('Motivazioni / Note Interne', 'gepafin')}</label>
<div style={{ position: 'relative' }}>
<BlockingOverlay shouldDisplay={data.status === 'CLOSE'}/>
<Editor
value={data.internalNote}
readOnly={data.status === 'CLOSE'}
placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header}
onTextChange={(e) => updateNewAmendmentData(
e.htmlValue,
'internalNote'
)}
style={{ height: 80 * 3, width: '100%' }}
/>
</div>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection__hr">
@@ -437,6 +456,12 @@ const SoccorsoEditPreInstructor = () => {
label={__('Estendi Scadenza', 'gepafin')}
icon="pi pi-stopwatch"
/>
{/*<Button
type="button"
onClick={doUpdateAmendment}
disabled={isAsyncRequest || data.status === 'CLOSE'}
label={__('Salva bozza', 'gepafin')}
icon="pi pi-save" iconPos="right"/>*/}
<Button
type="button"
onClick={doCloseAmendment}
@@ -446,24 +471,6 @@ const SoccorsoEditPreInstructor = () => {
</div>
</div>
<div className="appForm__field" style={{ marginTop: '-40px' }}>
<label>{__('Note Interne', 'gepafin')}</label>
<div style={{position: 'relative'}}>
<BlockingOverlay shouldDisplay={data.status === 'CLOSE'}/>
<Editor
value={data.internalNote}
readOnly={data.status === 'CLOSE'}
placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header}
onTextChange={(e) => updateNewAmendmentData(
e.htmlValue,
'internalNote'
)}
style={{ height: 80 * 3, width: '100%' }}
/>
</div>
</div>
</div>
<Dialog

View File

@@ -17,9 +17,6 @@ import getBandoSeverity from '../../../../helpers/getBandoSeverity';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
@@ -33,7 +30,6 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
@@ -75,16 +71,6 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
@@ -105,17 +91,12 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}
});
setGlobalFilterValue('');
};
const renderHeader = () => {
return (
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
<IconField iconPosition="left">
<InputIcon className="pi pi-search" />
<InputText value={globalFilterValue} onChange={onGlobalFilterChange} placeholder={__('Cerca', 'gepafin')} />
</IconField>
</div>
);
};
@@ -125,7 +106,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
};
const dateExpirationBodyTemplate = (rowData) => {
return formatDate(rowData.expirationDate);
return rowData.expirationDate ? formatDate(rowData.expirationDate) : '';
};
const dateFilterTemplate = (options) => {
@@ -155,8 +136,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
return(
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { uniq } from 'ramda';
import copy from 'copy-to-clipboard';
// store
import { useStore, storeSet } from '../../../../store';
@@ -17,9 +18,6 @@ import UserService from '../../../../service/user-service';
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Dropdown } from 'primereact/dropdown';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
@@ -31,7 +29,6 @@ const AllUsersTable = () => {
const users = useStore().main.users();
const [filters, setFilters] = useState(null);
const [loading, setLoading] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
@@ -63,30 +60,18 @@ const AllUsersTable = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
name: {
email: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
lastLogin: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
}
});
setGlobalFilterValue('');
};
const renderHeader = () => {
@@ -94,11 +79,6 @@ const AllUsersTable = () => {
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
<IconField iconPosition="left">
<InputIcon className="pi pi-search"/>
<InputText value={globalFilterValue} onChange={onGlobalFilterChange}
placeholder={__('Cerca', 'gepafin')}/>
</IconField>
</div>
);
};
@@ -116,6 +96,15 @@ const AllUsersTable = () => {
return `${rowData.firstName} ${rowData.lastName}`;
};
const roleEmailTemplate = (rowData) => {
return <div className="appPageSection__tableActions lessGap">
<span className="truncatedText">{rowData.email}</span>
<button className="iconBtn" onClick={() => copy(rowData.email)}>
<i className="pi pi-copy"></i>
</button>
</div>;
};
const roleBodyTemplate = (rowData) => {
return rowData.role.roleName;
};
@@ -148,24 +137,25 @@ const AllUsersTable = () => {
return (
<div className="appPageSection__table">
<DataTable value={users} paginator showGridlines rows={10} loading={loading} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
filters={filters} stripedRows removableSort
header={header}
emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}>
<Column body={nameBodyTemplate}
header={__('Nome utente', 'gepafin')}
filter filterPlaceholder={__('Cerca per nome', 'gepafin')}
filterPlaceholder={__('Cerca per nome', 'gepafin')}
style={{ minWidth: '12rem' }}/>
<Column field="email" header={__('Email', 'gepafin')}
filter filterPlaceholder={__('Cerca per email', 'gepafin')}
<Column body={roleEmailTemplate} header={__('Email', 'gepafin')}
filter sortable
field="email"
filterPlaceholder={__('Cerca per email', 'gepafin')}
style={{ minWidth: '12rem' }}/>
<Column body={roleBodyTemplate} header={__('Ruolo', 'gepafin')}
style={{ minWidth: '12rem' }}/>
<Column field="status" header={__('Stato', 'gepafin')}
filterMenuStyle={{ width: '14rem' }}
style={{ width: '120px' }} body={statusBodyTemplate}
filter filterElement={statusFilterTemplate}/>
filterElement={statusFilterTemplate}/>
<Column header={__('Ultimo accesso', 'gepafin')}
filterField="lastLogin" dataType="date"
style={{ minWidth: '10rem' }}