Merge branch 'develop' of github.com:Kitzanos/GEPAFIN-FE into master-sync/21-03-2025

This commit is contained in:
Vitalii Kiiko
2025-03-21 09:19:10 +01:00
66 changed files with 3274 additions and 268 deletions

View File

@@ -4,7 +4,8 @@ import Routes from './routes';
import { createI18n, setLocaleData } from '@wordpress/i18n';
import { I18nProvider } from '@wordpress/react-i18n';
import './assets/scss/theme.scss';
import { isEmpty, head } from 'ramda'
import { isEmpty, head } from 'ramda';
import { addLocale, PrimeReactProvider } from 'primereact/api';
// store
import { useStore, storeSet, storeGet } from './store';
@@ -18,6 +19,9 @@ function App() {
const role = useStore().main.getRole();
const chosenCompanyId = useStore().main.chosenCompanyId();
const isRedirectedOnceNoCompany = useStore().main.isRedirectedOnceNoCompany();
const value = {
locale: 'it',
};
const callback = (data) => {
if (data.status === 'SUCCESS') {
@@ -33,7 +37,7 @@ function App() {
}
useEffect(() => {
if (role === 'ROLE_BENEFICIARY') {
if (['ROLE_BENEFICIARY', 'ROLE_CONFIDI'].includes(role)) {
const userData = storeGet.main.userData();
if (userData.companies && !isEmpty(userData.companies)) {
storeSet.main.companies(userData.companies);
@@ -59,6 +63,51 @@ function App() {
storeSet.main.setAsyncRequest();
AuthenticationService.me(callback, errCallback);
addLocale('it', {
startsWith: 'Inizia con',
contains: 'Contiene',
notContains: 'Non contiene',
endsWith: 'Finisce con',
equals: 'Uguale a',
notEquals: 'Diverso da',
noFilter: 'Nessun filtro',
lt: 'Minore di',
lte: 'Minore o uguale a',
gt: 'Maggiore di',
gte: 'Maggiore o uguale a',
dateIs: 'Data uguale a',
dateIsNot: 'Data diversa da',
dateBefore: 'Data prima di',
dateAfter: 'Data dopo',
custom: 'Personalizzato',
clear: 'Cancella',
apply: 'Applica',
matchAll: 'Tutte le condizioni',
matchAny: 'Qualsiasi condizione',
addRule: 'Aggiungi regola',
removeRule: 'Rimuovi regola',
accept: 'Sì',
reject: 'No',
choose: 'Scegli',
upload: 'Carica',
cancel: 'Annulla',
dayNames: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
dayNamesMin: ['D', 'L', 'M', 'M', 'G', 'V', 'S'],
monthNames: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
monthNamesShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'],
today: 'Oggi',
weekHeader: 'Sm',
firstDayOfWeek: 1,
dateFormat: 'dd/mm/yy',
weak: 'Debole',
medium: 'Medio',
strong: 'Forte',
passwordPrompt: 'Inserisci una password',
emptyMessage: 'Nessun risultato trovato',
emptyFilterMessage: 'Nessun risultato trovato'
});
fetch('/languages/en_US.json')
.then((res) => res.json())
.then(res => {
@@ -69,7 +118,9 @@ function App() {
return (
<I18nProvider i18n={i18n}>
<BrowserRouter>
<PrimeReactProvider value={value}>
<Routes role={role} chosenCompanyId={chosenCompanyId}/>
</PrimeReactProvider>
</BrowserRouter>
</I18nProvider>
);

View File

@@ -109,6 +109,51 @@
background-color: var(--table-border-color)
}
}
&.fileselect {
.fileselectInner {
flex-direction: row;
display: flex;
gap: 1rem;
> div {
flex: 1 1 50%;
}
}
.fileselectInner__selectionBox {
display: flex;
flex-direction: column;
gap: 10px;
}
.fileselectInner__selectedFiles {
display: flex;
flex-direction: column;
gap: 10px;
p {
margin: 0;
font-weight: bold;
font-size: 14px;
}
ul {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 7px;
li {
display: flex;
gap: 1rem;
justify-content: space-between;
align-items: center;
}
}
}
}
}
.appForm__field--required.appForm__field--required {

View File

@@ -113,6 +113,10 @@
font-weight: 600;
line-height: normal;
margin: 0 0 24px;
display: flex;
gap: 1rem;
flex-wrap: wrap;
align-items: center;
}
h3 {

View File

@@ -167,6 +167,13 @@
}
}
.p-column-filter-overlay .p-column-filter-row-items .p-column-filter-row-item.p-highlight {
color: white;
}
.p-listbox .p-listbox-list .p-listbox-item.p-highlight {
color: white;
}
.p-inputnumber-input[readonly] {
background-color: #e1e1e1;
}

View File

@@ -0,0 +1,105 @@
import React, { useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n';
import translationStrings from '../../translationStringsForComponents';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Button } from 'primereact/button';
import BandoService from '../../service/bando-service';
const DataTableAsync = () => {
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
const [lazyState, setLazyState] = useState({
first: 0,
rows: 5,
page: 1,
sortField: null,
sortOrder: null,
filters: {
name: { value: '', matchMode: 'contains' }
}
});
const getPaginationQuery = () => {
return {
"globalFilters": {
"page": 0,
"limit": lazyState.rows,
"sortBy": {
"columnName": "ID",
"sortDesc": true
}
}
}
}
const onPage = (event) => {
setLazyState(event);
};
const onSort = (event) => {
setLazyState(event);
};
const onFilter = (event) => {
event['first'] = 0;
setLazyState(event);
};
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
const { body, totalRecords, currentPage, totalPages, pageSize } = data.data;
setTotalRecordsNum(totalRecords);
const newItems = body.filter(o => o.status === 'PUBLISH');
setItems(getFormattedBandiData(newItems));
}
setLocalAsyncRequest(false);
}
const errGetCallbacks = (data) => {
setLocalAsyncRequest(false);
}
const getFormattedBandiData = (data) => {
return [...(data || [])].map((d) => {
d.start_date = new Date(d.dates[0]);
d.end_date = new Date(d.dates[1]);
return d;
});
};
useEffect(() => {
console.log(lazyState)
}, [lazyState]);
useEffect(() => {
if (!localAsyncRequest) {
setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery();
BandoService.getBandiPaginated(paginationQuery, getCallback, errGetCallbacks);
}
}, []);
return (
<div className="appPageSection__table">
<DataTable
value={items} stripedRows showGridlines
lazy filterDisplay="row" dataKey="id" paginator
first={lazyState.first} rows={lazyState.rows} totalRecords={totalRecordsNum} onPage={onPage}
onSort={onSort} sortField={lazyState.sortField} sortOrder={lazyState.sortOrder}
onFilter={onFilter} filters={lazyState.filters} loading={localAsyncRequest}
emptyMessage={translationStrings.emptyMessage}>
<Column field="name" filterField="name" filter
header={__('Nome Bando', 'gepafin')}
style={{ minWidth: '8rem' }}/>
</DataTable>
</div>
)
}
export default DataTableAsync;

View File

@@ -0,0 +1,212 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { classNames } from 'primereact/utils';
import { __ } from '@wordpress/i18n';
import { isEmpty, pathOr, pluck } from 'ramda';
// service
import FileUploadService from '../../../../service/file-upload-service';
import CompanyDocumentsService from '../../../../service/company-documents-service';
// components
import { ListBox } from 'primereact/listbox';
import { Button } from 'primereact/button';
import { Link } from 'react-router-dom';
import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup';
const FileSelect = ({
fieldName,
label,
setDataFn,
register,
errors,
defaultValue,
config = {},
infoText = null,
disabled = false,
options = [],
sourceId = 0,
source = 'DOCUMENT',
documentCategories = [],
saveFormCallback
}) => {
//const [stateFieldData, setStateFieldData] = useState([]);
const stateFieldData = useRef([]);
const [selectedUnconfirmed, setSelectedUnconfirmed] = useState([]);
const [optionsTransformed, setOptionsTransformed] = useState([]);
const [loading, setLoading] = useState(false);
const [addNewMode, setAddNewMode] = useState(false);
const attachSelectedFiles = useCallback(() => {
const existingIds = pluck('id', stateFieldData.current);
const selectedToBeAdded = selectedUnconfirmed.filter(o => !existingIds.includes(o.id));
setSelectedUnconfirmed([]);
setLoading(true);
// eslint-disable-next-line array-callback-return
selectedToBeAdded.map(o => {
CompanyDocumentsService.attachCompanyDocumentToAppl(o.id, callback, errCallback, [
['applicationId', sourceId],
['documentType', source]
])
});
setAddNewMode(false);
}, [selectedUnconfirmed]);
const doGoBackToListOfFiles = () => {
setSelectedUnconfirmed([]);
setAddNewMode(false);
}
const callback = (resp) => {
if (resp.status === 'SUCCESS') {
stateFieldData.current = [...stateFieldData.current, resp.data];
setDataFn(fieldName, stateFieldData.current, { shouldValidate: true });
saveFormCallback();
}
setLoading(false);
}
const errCallback = () => {
setLoading(false);
}
const removeAttached = (id) => {
FileUploadService.deleteFile(
{},
(data) => deleteCallback(data, id),
deleteErrorCallback,
[['id', id]]
);
}
const deleteCallback = (data, id) => {
if (data.status === 'SUCCESS') {
stateFieldData.current = stateFieldData.current.filter(o => id !== o.id);
setDataFn(fieldName, stateFieldData.current, { shouldValidate: true });
saveFormCallback();
}
}
const deleteErrorCallback = (err) => {
console.log('err', err);
}
const confirmDelete = (event, id) => {
confirmPopup({
target: event.currentTarget,
message: __('Sei sicuro di cancellare il file?', 'gepafin'),
acceptLabel: __('Si', 'gepafin'),
icon: 'pi pi-info-circle',
defaultFocus: 'reject',
acceptClassName: 'p-button-danger',
accept: () => removeAttached(id),
reject: () => {}
});
};
useEffect(() => {
stateFieldData.current = defaultValue;
register(fieldName, config)
}, []);
useEffect(() => {
if (!isEmpty(options)) {
const optionsDefault = options
.filter(o => isEmpty(documentCategories)
? o
: documentCategories.includes(o.category.id))
.reduce((acc, cur) => {
const catName = pathOr('', ['category', 'categoryName'], cur);
const catLabel = pathOr('', ['category', 'description'], cur);
if (!acc[catName]) {
acc[catName] = {
code: catName,
label: catLabel,
items: []
};
}
acc[catName].items.push(cur)
return acc;
}, {});
setOptionsTransformed(Object.values(optionsDefault));
}
}, [options]);
useEffect(() => {
stateFieldData.current = defaultValue;
}, [defaultValue]);
//console.log([...stateFieldData.current])
return (
<>
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
{label}{config.required || config.isRequired ?
<span className="appForm__field--required">*</span> : null}
</label>
<div className="fileselectInner">
{addNewMode
? <div className="fileselectInner__selectionBox">
<ListBox multiple
value={selectedUnconfirmed}
onChange={(e) => setSelectedUnconfirmed(e.value)}
options={optionsTransformed}
optionLabel="name"
optionGroupLabel="label"
optionGroupChildren="items"
className="w-full md:w-14rem"
listStyle={{ maxHeight: '130px' }}/>
{!isEmpty(selectedUnconfirmed)
? <Button
severity="success"
disabled={loading}
onClick={attachSelectedFiles}
label={__('Conferma i file scelti', 'gepafin')}
icon="pi pi-arrow-right" size="small" iconPos="right"/>
: <Button
severity="success"
outlined
onClick={doGoBackToListOfFiles}
label={__('Torna alla lista dei file selezionati', 'gepafin')}
icon="pi pi-arrow-right" size="small" iconPos="right"/>}
</div> : null}
{!isEmpty(optionsTransformed) && !addNewMode
? <div className="fileselectInner__selectedFiles">
<p>{__('I file selezionati')}</p>
<ul>
{[...stateFieldData.current].map(o => <li key={o.id}>
{o.name}
<div className="appPageSection__iconActions">
<Button icon="pi pi-times" rounded
type="button"
size="small"
onClick={(e) => confirmDelete(e, o.id)}
outlined severity="danger"
aria-label={__('Cancella', 'gepafin')}/>
</div>
</li>)}
</ul>
<Button
severity="success"
disabled={loading}
onClick={() => setAddNewMode(true)}
label={__('Aggiungi i file', 'gepafin')}
icon="pi pi-plus" size="small" iconPos="right"/>
</div> : null}
</div>
{isEmpty(optionsTransformed)
? <div className="appPageSection__message warning">
<span>
{__('I file caricati sulla pagina Documenti saranno disponibili qui. ', 'gepafin')}
<Link to={`/documenti`}>
{__('Vai alla pagina Documenti', 'gepafin')}
</Link>
</span>
</div>
: null}
{infoText ? <small>{infoText}</small> : null}
<ConfirmPopup />
</>)
}
export default FileSelect;

View File

@@ -16,6 +16,7 @@ import { Button } from 'primereact/button';
import { defaultMaxFileSize, mimeTypes } from '../../../../configData';
import getFormatedFileSizeText from '../../../../helpers/getFormatedFileSizeText';
import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup';
const Fileupload = ({
fieldName,
@@ -72,6 +73,20 @@ const Fileupload = ({
console.log('err', err);
}
const confirmDelete = (event, file) => {
console.log('confirmDelete', file)
confirmPopup({
target: event.currentTarget,
message: __('Sei sicuro di cancellare il file?', 'gepafin'),
acceptLabel: __('Si', 'gepafin'),
icon: 'pi pi-info-circle',
defaultFocus: 'reject',
acceptClassName: 'p-button-danger',
accept: () => onTemplateRemove(file),
reject: () => {}
});
};
const itemTemplate = (file) => {
let fileName = file.fileName ? file.fileName : file.name;
return (
@@ -91,7 +106,7 @@ const Fileupload = ({
type="button"
disabled={disabled}
aria-label={__('Anulla', 'gepafin')}
onClick={() => onTemplateRemove(file)}/>
onClick={(e) => confirmDelete(e, file)}/>
</div>
</div>
);
@@ -213,6 +228,7 @@ const Fileupload = ({
onBeforeSelect={onBeforeSelect}
uploadHandler={customBase64Uploader}/>
{infoText ? <small>{infoText}</small> : null}
<ConfirmPopup />
</>
: null
)

View File

@@ -8,6 +8,7 @@ import { __ } from '@wordpress/i18n';
import { Editor } from 'primereact/editor';
import BlockingOverlay from '../../../BlockingOverlay';
import { Button } from 'primereact/button';
import { isNil } from 'ramda';
const Delta = Quill.import('delta');
@@ -53,15 +54,17 @@ const Wysiwyg = ({
<>
<BlockingOverlay shouldDisplay={disabled}/>
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
{label}{config.required || config.isRequired ? <span className="appForm__field--required">*</span> : null}
{label}{config.required || config.isRequired ?
<span className="appForm__field--required">*</span> : null}
</label>
<Button
{!isNil(setDataFn)
? <Button
label={__('Cancella testo', 'gepafin')}
type="button"
severity="warning"
outlined
onClick={handleCleanValue}
/>
/> : null}
<Controller
name={fieldName}
control={control}
@@ -77,9 +80,8 @@ const Wysiwyg = ({
modules={{
clipboard: {
matchers: [
[ Node.ELEMENT_NODE, function(node, delta) {
console.log('here')
const ops = delta.ops.map((op) => ({insert: op.insert}));
[Node.ELEMENT_NODE, function (node, delta) {
const ops = delta.ops.map((op) => ({ insert: op.insert }));
return new Delta(ops)
}]
]

View File

@@ -18,6 +18,7 @@ import Fileupload from './components/Fileupload';
import Table from './components/Table';
import PasswordField from './components/PasswordField';
import CriteriaTable from './components/CriteriaTable';
import FileSelect from './components/FileSelect';
const FormField = (props) => {
const fields = {
@@ -35,7 +36,8 @@ const FormField = (props) => {
checkboxes: Checkboxes,
table: Table,
criteria_table: CriteriaTable,
password: PasswordField
password: PasswordField,
fileselect: FileSelect,
}
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;

View File

@@ -55,7 +55,7 @@ const TopBarProfileMenu = ({ menuLeftRef }) => {
command: () => {
navigate('/profilo-aziendale')
},
enable: intersection(permissions, ['APPLY_CALLS']).length && companies.length > 0
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length && companies.length > 0
},
{
label: __('Seleziona azienda', 'gepafin'),
@@ -67,7 +67,7 @@ const TopBarProfileMenu = ({ menuLeftRef }) => {
command: () => {
navigate('/agguingi-azienda')
},
enable: intersection(permissions, ['APPLY_CALLS']).length
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
},
{
separator: true,

View File

@@ -207,6 +207,21 @@ export const classificationType = [
'name': 'ALTRO',
'idTipoprotocollo': 1
},
{
'idClassificazione': 135,
'name': 'DOMANDA PDF FIRMATO',
'idTipoprotocollo': 1
},
{
'idClassificazione': 136,
'name': 'DELEGA-PROCURA BANDI',
'idTipoprotocollo': 1
},
{
'idClassificazione': 137,
'name': 'DIGITAL ASSESMENT',
'idTipoprotocollo': 1
},
{
'idClassificazione': 202,
'name': 'LETTERA DI GARANZIA',

View File

@@ -14,6 +14,9 @@ const getBandoLabel = (status) => {
case 'APPROVED':
return __('Approvato', 'gepafin');
case 'VALID':
return __('Valido', 'gepafin');
case 'READY_TO_PUBLISH':
return __('Pronto', 'gepafin');
@@ -29,6 +32,12 @@ const getBandoLabel = (status) => {
case 'ADMISSIBLE':
return __('Ammisibile', 'gepafin');
case 'TECHNICAL_EVALUATION':
return __('Valutazione technico-finanziaria', 'gepafin');
case 'DUE':
return __('In scadenza', 'gepafin');
case 'RESPONSE_RECEIVED':
return __('Riposta ricevuta', 'gepafin');

View File

@@ -12,6 +12,9 @@ const getBandoSeverity = (status) => {
case 'APPROVED':
return 'success';
case 'VALID':
return 'success';
case 'READY_TO_PUBLISH':
return 'info';
@@ -27,6 +30,12 @@ const getBandoSeverity = (status) => {
case 'ADMISSIBLE':
return 'info';
case 'TECHNICAL_EVALUATION':
return 'info';
case 'DUE':
return 'warning';
case 'RESPONSE_RECEIVED':
return 'warning';

View File

@@ -0,0 +1,9 @@
const getFormattedDateString = (value) => {
return value.toLocaleDateString('it-IT', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
};
export default getFormattedDateString;

View File

@@ -32,21 +32,21 @@ const AppSidebar = () => {
icon: 'pi pi-file',
href: '/imieibandi',
id: 3,
enable: intersection(permissions, ['APPLY_CALLS']).length
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
},
{
label: __('Bandi disponibili', 'gepafin'),
icon: 'pi pi-bookmark',
href: '/bandi',
id: 4,
enable: intersection(permissions, ['VIEW_CALLS']).length
enable: intersection(permissions, ['VIEW_CALLS', 'VIEW_CONFIDI_CALLS']).length
},
{
label: __('Bandi osservati', 'gepafin'),
icon: 'pi pi-star',
href: '/bandi-osservati',
id: 5,
enable: intersection(permissions, ['VIEW_CALLS']).length
enable: intersection(permissions, ['VIEW_CALLS', 'VIEW_CONFIDI_CALLS']).length
},
{
label: __('Gestione domande', 'gepafin'),
@@ -81,7 +81,7 @@ const AppSidebar = () => {
icon: 'pi pi-briefcase',
href: '/domande',
id: 10,
enable: intersection(permissions, ['APPLY_CALLS']).length
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
},
{
label: __('Archivio domande', 'gepafin'),
@@ -136,7 +136,14 @@ const AppSidebar = () => {
icon: 'pi pi-chart-bar',
href: '/stats',
id: 15,
enable: intersection(permissions, ['APPLY_CALLS']).length
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
},
{
label: __('Documenti', 'gepafin'),
icon: 'pi pi-folder-open',
href: '/documenti',
id: 16,
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
},
{
label: __('Log di Sistema', 'gepafin'),

View File

@@ -3,7 +3,7 @@ import { __ } from '@wordpress/i18n';
import { useLocation } from 'react-router-dom';
// store
import { useStore, storeSet } from '../../store';
import { useStore, storeSet, storeGet } from '../../store';
// components
import AppSidebar from './components/AppSidebar';

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect} from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { is, uniq, isNil, isEmpty } from 'ramda';
import { is, uniq, isNil, isEmpty, head } from 'ramda';
import { wrap } from 'object-path-immutable';
import { useNavigate } from 'react-router-dom';
@@ -37,6 +37,7 @@ const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const AllBandiAccordion = ({ showOnlyPreferred = false }) => {
const chosenCompanyId = useStore().main.chosenCompanyId();
const companies = useStore().main.companies();
const isAsyncRequest = useStore().main.isAsyncRequest();
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
@@ -45,11 +46,15 @@ const AllBandiAccordion = ({ showOnlyPreferred = false }) => {
const navigate = useNavigate();
useEffect(() => {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany && !isAsyncRequest) {
storeSet.main.setAsyncRequest();
BandoService.getBandi(getCallback, errGetCallbacks, [
['companyId', chosenCompanyId],
['onlyPreferredCall', showOnlyPreferred]
]);
}
}, [chosenCompanyId]);
const getCallback = (data) => {

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect} from 'react';
import { __ } from '@wordpress/i18n';
import { is, uniq, isNil, isEmpty } from 'ramda';
import { is, uniq, isNil, isEmpty, head } from 'ramda';
import { wrap } from 'object-path-immutable';
import { useNavigate } from 'react-router-dom';
@@ -30,6 +30,7 @@ import translationStrings from '../../../../translationStringsForComponents';
const AllBandiPreferredAccordion = () => {
const chosenCompanyId = useStore().main.chosenCompanyId();
const companies = useStore().main.companies();
const isAsyncRequest = useStore().main.isAsyncRequest();
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
@@ -38,12 +39,16 @@ const AllBandiPreferredAccordion = () => {
const navigate = useNavigate();
useEffect(() => {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany) {
storeSet.main.setAsyncRequest();
const userData = storeGet.main.userData();
PreferredBandoService.getPreferredCalls(getCallback, errGetCallbacks, [
['companyId', chosenCompanyId],
['userId', userData.id]
]);
}
}, [chosenCompanyId]);
const getCallback = (data) => {

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect, useRef, useMemo } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useParams } from 'react-router-dom';
import { head, is, pluck, isEmpty, pathOr, isNil } from 'ramda';
import { head, is, pluck, isEmpty, pathOr, isNil, uniqBy } from 'ramda';
import { useForm } from 'react-hook-form';
import 'quill/dist/quill.core.css';
import { wrap } from 'object-path-immutable';
@@ -14,6 +14,7 @@ import { storeSet, storeGet, useStore } from '../../store';
// api
import ApplicationService from '../../service/application-service';
import CompanyDocumentsService from '../../service/company-documents-service';
// tools
import {
@@ -64,6 +65,8 @@ const BandoApplication = () => {
const [applicationStatus, setApplicationStatus] = useState('');
const [activeStep, setActiveStep] = useState(1);
const [signedPdfFile, setSignedPdfFile] = useState([]);
const [companyDocs, setCompanyDocs] = useState([]);
const [personalDocs, setPersonalDocs] = useState([]);
const [isRequestForApplData, setIsRequestForApplData] = useState(false);
const isAsyncRequest = useStore().main.isAsyncRequest();
const previousStatus = useRef('');
@@ -219,7 +222,7 @@ const BandoApplication = () => {
}
fieldVal = isEmpty(fieldVal) ? null : fieldVal;
if (formField && formField.name === 'fileupload') {
if (formField && ['fileupload', 'fileselect'].includes(formField.name)) {
fieldVal = is(Array, fieldVal) ? fieldVal.map(o => o.id).join(',') : null;
}
acc.push({
@@ -262,7 +265,7 @@ const BandoApplication = () => {
});
}
if (!isEmpty(saveAndMove) && is(String, saveAndMove)) {
if (['NEXT','PREVIOUS'].includes(saveAndMove)) {
if (['NEXT', 'PREVIOUS'].includes(saveAndMove)) {
storeSet.main.setAsyncRequest();
ApplicationService.getApplicationForm(data.data.id, getApplFormCallback, errGetApplFormCallbacks, [
['formId', formId],
@@ -542,6 +545,26 @@ const BandoApplication = () => {
? ['.p7m', '.pdf']
: ['.p7m'];
const getDocsCallback = (resp, type) => {
if (resp.status === 'SUCCESS') {
const filteredPersonal = getFormattedDocsData(resp.data.filter(o => o.type === 'PERSONAL_DOCUMENT'));
setPersonalDocs(uniqBy((o) => o.id, filteredPersonal));
const filteredCompany = getFormattedDocsData(resp.data.filter(o => o.type === 'COMPANY_DOCUMENT'));
setCompanyDocs(uniqBy((o) => o.id, filteredCompany));
}
}
const errDocsGetCallbacks = () => {
}
const getFormattedDocsData = (data) => {
return data.map((d) => {
d.callEndDate = is(String, d.callEndDate) ? new Date(d.callEndDate) : (d.callEndDate ? d.callEndDate : '');
return d;
});
};
useEffect(() => {
let updatedFormValues = klona(formValues);
let context = {};
@@ -630,6 +653,7 @@ const BandoApplication = () => {
ApplicationService.getApplicationForm(applId, getApplFormCallback, errGetApplFormCallbacks, [
['companyId', chosenCompanyId]
]);
CompanyDocumentsService.getCompanyDocuments(chosenCompanyId, getDocsCallback, errDocsGetCallbacks);
}
}, [id, chosenCompanyId]);
@@ -689,13 +713,16 @@ const BandoApplication = () => {
const label = head(o.settings.filter(o => o.name === 'label'));
const text = head(o.settings.filter(o => o.name === 'text'));
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
const options = head(o.settings.filter(o => o.name === 'options'));
const options = ['fileselect'].includes(o.name)
? { value: [...companyDocs, ...personalDocs] }
: head(o.settings.filter(o => o.name === 'options'));
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 mime = head(o.settings.filter(o => o.name === 'mime'));
const documentCategories = head(o.settings.filter(o => o.name === 'documentCategories'));
const formula = head(o.settings.filter(o => o.name === 'formula'));
let mimeValue = '';
@@ -723,8 +750,8 @@ const BandoApplication = () => {
return acc;
}, {});
/*if (o.name === 'table') {
console.log('value:', values[o.id] ? values[o.id] : '')
/*if (o.name === 'fileselect') {
console.log('options::', options)
}*/
return ['paragraph'].includes(o.name) && text
@@ -747,6 +774,7 @@ const BandoApplication = () => {
defaultValue={values[o.id] ? values[o.id] : ''}
maxFractionDigits={step ? step.value : 0}
accept={mimeValue}
documentCategories={documentCategories ? documentCategories.value : []}
config={validations}
options={options ? options.value : []}
setDataFn={setValue}

View File

@@ -328,7 +328,7 @@ const BandoApplicationPreview = () => {
if (applId) {
storeSet.main.setAsyncRequest();
const queryParams = 'ROLE_BENEFICIARY' === role
const queryParams = ['ROLE_BENEFICIARY', 'ROLE_CONFIDI'].includes(role)
? [
['companyId', chosenCompanyId]
]

View File

@@ -201,7 +201,8 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
![
'descriptionShort', 'descriptionLong', 'documentationRequested', 'threshold',
'aimedTo', 'criteria', 'docs', 'checklist', 'faq', 'amount', 'amountMin', 'amountMax',
'email', 'phoneNumber', 'checkList', 'images', 'numberOfCheck', 'appointmentTemplateId'
'email', 'phoneNumber', 'checkList', 'images', 'numberOfCheck', 'appointmentTemplateId',
'endDate', 'endTime'
].includes(fieldName)
}

View File

@@ -214,7 +214,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
![
'descriptionShort', 'descriptionLong', 'documentationRequested', 'threshold',
'aimedTo', 'criteria', 'docs', 'checklist', 'faq', 'amount', 'amountMin', 'amountMax',
'email', 'phoneNumber', 'checkList', 'images'
'email', 'phoneNumber', 'checkList', 'images', 'endDate', 'endTime'
].includes(fieldName)
}

View File

@@ -78,7 +78,11 @@ const BandoEditFormStep3 = forwardRef(function () {
const getElementItemsCallback = (data) => {
if (data.status === 'SUCCESS') {
//storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder));
storeSet.main.elementItems(
data.data
.filter(o => !['fileselect'].includes(o.name))
.sort((a, b) => a.sortOrder - b.sortOrder)
);
}
storeSet.main.unsetAsyncRequest();
}

View File

@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { ItemTypes } from '../ItemTypes';
import { __ } from '@wordpress/i18n';
import { head, isEmpty } from 'ramda';
import { head, isEmpty, pathOr } from 'ramda';
import { klona } from 'klona';
// store
@@ -22,6 +22,7 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
const ref = useRef(null);
const elements = useStore().main.formElements();
const element = head(elements.filter(o => o.id === id));
const elementSettings = pathOr([], ['settings'], element);
const [isVariable, setIsVariable] = useState('secondary');
const [isFormula, setIsFormula] = useState('secondary');
const [variableName, setVariableName] = useState('secondary');
@@ -134,10 +135,10 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
drag(drop(ref));
useEffect(() => {
const variable = head(element.settings.filter(o => o.name === 'variable'));
const formula = head(element.settings.filter(o => o.name === 'formula'));
const isRequestedAmount = head(element.settings.filter(o => o.name === 'isRequestedAmount'));
const isDelegation = head(element.settings.filter(o => o.name === 'isDelegation'));
const variable = head(elementSettings.filter(o => o.name === 'variable'));
const formula = head(elementSettings.filter(o => o.name === 'formula'));
const isRequestedAmount = head(elementSettings.filter(o => o.name === 'isRequestedAmount'));
const isDelegation = head(elementSettings.filter(o => o.name === 'isDelegation'));
if (variable && !isEmpty(variable.value)) {
setIsVariable('warning');
@@ -151,12 +152,16 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
if (isRequestedAmount && !isEmpty(isRequestedAmount.value) && isRequestedAmount.value) {
setIsRequestedAmount('tertiary');
} else {
setIsRequestedAmount(false);
}
if (isDelegation && !isEmpty(isDelegation.value) && isDelegation.value) {
setIsDelegation('tertiary');
} else {
setIsDelegation(false);
}
}, [elements]);
}, [elementSettings]);
return (
draggingElementId === id

View File

@@ -3,7 +3,7 @@ import { __ } from '@wordpress/i18n';
import { head, is, isEmpty, isNil, uniq } from 'ramda';
// store
import { storeGet } from '../../../../../../store';
import { storeGet, useStore } from '../../../../../../store';
// tools
import renderHtmlContent from '../../../../../../helpers/renderHtmlContent';
@@ -23,6 +23,7 @@ import { mimeTypes } from '../../../../../../configData';
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
const [existingVars, setExistingVars] = useState([]);
const documentCategories = useStore().main.documentCategories();
const settingLabels = {
label: __('Label', 'gepafin'),
@@ -32,6 +33,7 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
isDelegation: __('Delega', 'gepafin'),
options: __('Opzioni', 'gepafin'),
mime: __('Tipo di file', 'gepafin'),
documentCategories: __('Categorie dei documenti', 'gepafin'),
text: __('Testo formattato', 'gepafin'),
table_columns: '',
criteria_table_columns: '',
@@ -79,6 +81,13 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
optionLabel="name"
display="chip"
placeholder={__('Scegli', 'gepafin')}/>
} else if (setting.name === 'documentCategories') {
return <MultiSelect
value={is(Array, setting.value) ? setting.value : []}
onChange={(e) => updateDataFn(setting.name, e.value)}
options={documentCategories}
display="chip"
placeholder={__('Scegli', 'gepafin')}/>
} else if (setting.name === 'text') {
return <Editor
value={setting.value}

View File

@@ -24,7 +24,8 @@ import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import BandoService from '../../service/bando-service';
// TODO temp data
//import { elementItems } from '../../tempData';
import { elementItems } from '../../tempData';
import DocumentCategoryService from '../../service/document-category-service';
const BandoFormsEdit = () => {
const { id, formId } = useParams();
@@ -215,10 +216,10 @@ const BandoFormsEdit = () => {
const getElementItemsCallback = (data) => {
if (data.status === 'SUCCESS') {
//storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
storeSet.main.elementItems(data.data
storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
/*storeSet.main.elementItems(data.data
.filter(o => o.id !== 22)
.sort((a, b) => a.sortOrder - b.sortOrder));
.sort((a, b) => a.sortOrder - b.sortOrder));*/
}
storeSet.main.unsetAsyncRequest();
}
@@ -257,6 +258,15 @@ const BandoFormsEdit = () => {
set404FromErrorResponse(data);
}
const getCategories = (resp) => {
if (resp.status === 'SUCCESS') {
storeSet.main.documentCategories(resp.data.map(o => ({value: o.id, label: o.description})));
}
}
const errGetCategories = () => {
}
useEffect(() => {
const bandoId = getBandoId();
const parsedFormId = parseInt(formId)
@@ -283,6 +293,10 @@ const BandoFormsEdit = () => {
}
}, [id, formId]);
useEffect(() => {
DocumentCategoryService.getCategories(getCategories, errGetCategories)
}, []);
return (
<div className="appPage">
<div className="appPage__pageHeader">

View File

@@ -0,0 +1,169 @@
import React, { useState, useEffect, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { is, pathOr, isEmpty } from 'ramda';
// store
import { useStore } from '../../../../store';
// api
import ApplicationService from '../../../../service/application-service';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { ProgressBar } from 'primereact/progressbar';
import { Button } from 'primereact/button';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Link } from 'react-router-dom';
import translationStrings from '../../../../translationStringsForComponents';
const DraftApplicationsTableAsync = () => {
const chosenCompanyId = useStore().main.chosenCompanyId();
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
const [lazyState, setLazyState] = useState({
first: 0,
rows: 5,
page: 0,
sortField: null,
sortOrder: null,
filters: {
id: { value: null, matchMode: 'contains' },
callTitle: { value: null, matchMode: 'contains' },
companyName: { value: null, matchMode: 'contains' }
}
});
const statuses = ['DRAFT'];
const getPaginationQuery = useCallback(() => {
let sortBy = {
columnName: "ID",
sortDesc: true
};
if (lazyState.sortField) {
sortBy = {
columnName: lazyState.sortField,
sortDesc: lazyState.sortOrder === -1
}
}
return {
globalFilters: {
page: lazyState.page ? lazyState.page + 1 : 1,
limit: lazyState.rows,
sortBy
},
status: statuses,
filters: Object.keys(lazyState.filters).reduce((acc, cur) => {
const value = pathOr('', ['filters', cur, 'value'], lazyState);
if (!isEmpty(value)) {
acc[cur] = lazyState.filters[cur];
}
return acc;
}, {}),
}
}, [lazyState]);
const onPage = (event) => {
setLazyState(event);
};
const onSort = (event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
};
const onFilter = useCallback((event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
}, [lazyState]);
const getApplCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const { body, totalRecords,
//currentPage, totalPages, pageSize
} = resp.data;
setTotalRecordsNum(totalRecords);
setItems(getFormattedData(body));
}
setLocalAsyncRequest(false);
}
const errGetApplCallback = () => {
setLocalAsyncRequest(false);
}
const getFormattedData = (data) => {
return data.map((d) => {
d.callEndDate = is(String, d.callEndDate) ? new Date(d.callEndDate) : (d.callEndDate ? d.callEndDate : '');
d.modifiedDate = is(String, d.modifiedDate) ? new Date(d.modifiedDate) : (d.modifiedDate ? d.modifiedDate : '');
d.submissionDate = is(String, d.submissionDate) ? new Date(d.submissionDate) : (d.submissionDate ? d.submissionDate : '');
return d;
});
};
useEffect(() => {
setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery();
ApplicationService.getApplicationsPaginated(paginationQuery, getApplCallback, errGetApplCallback);
}, [lazyState, chosenCompanyId]);
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const progressBodyTemplate = (options) => {
return <ProgressBar value={options.progress} color={'#64748B'}></ProgressBar>;
};
const actionsBodyTemplate = (rowData) => {
return <Link to={`/domande/${rowData.id}/preview`}>
<Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/>
</Link>
}
return (
<div className="appPageSection__table">
<DataTable
value={items} stripedRows showGridlines
lazy filterDisplay="menu" dataKey="id" paginator
first={lazyState.first} rows={lazyState.rows} totalRecords={totalRecordsNum} onPage={onPage}
onSort={onSort} sortField={lazyState.sortField} sortOrder={lazyState.sortOrder}
onFilter={onFilter} filters={lazyState.filters} loading={localAsyncRequest}
emptyMessage={translationStrings.emptyMessage}>
<Column field="id" header={__('ID domanda', 'gepafin')}
sortable
filterField="id" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="callTitle" header={__('Bando', 'gepafin')}
sortable
filterField="callTitle" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="companyName" header={__('Azienda', 'gepafin')}
sortable
filterField="companyName" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="status" header={__('Stato', 'gepafin')}
style={{ minWidth: '7rem' }} body={statusBodyTemplate}/>
<Column header={__('Progressi', 'gepafin')}
style={{ minWidth: '10rem' }} field="progress" body={progressBodyTemplate}/>
<Column header={__('Azioni', 'gepafin')}
style={{ minWidth: '10rem' }}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default DraftApplicationsTableAsync;

View File

@@ -0,0 +1,208 @@
import React, { useEffect, useState, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty, pathOr } from 'ramda';
import { Link } from 'react-router-dom';
import translationStrings from '../../../../translationStringsForComponents';
// api
import BandoService from '../../../../service/bando-service';
// tools
import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString';
import getTimeFromISOstring from '../../../../helpers/getTimeFromISOstring';
import getFormattedDateString from '../../../../helpers/getFormattedDateString';
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Button } from 'primereact/button';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Dropdown } from 'primereact/dropdown';
import { Tag } from 'primereact/tag';
import { Calendar } from 'primereact/calendar';
const LatestBandiTableAsync = () => {
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
const [lazyState, setLazyState] = useState({
first: 0,
rows: 5,
page: 0,
sortField: null,
sortOrder: null,
filters: {
name: { value: null, matchMode: 'contains' },
startDate: { value: null, matchMode: 'date_is' },
endDate: { value: null, matchMode: 'date_is' },
status: { value: null, matchMode: 'equals' }
}
});
const statuses = ['PUBLISH'];
const getPaginationQuery = useCallback(() => {
let sortBy = {
columnName: "ID",
sortDesc: true
};
if (lazyState.sortField) {
sortBy = {
columnName: lazyState.sortField,
sortDesc: lazyState.sortOrder === -1
}
}
return {
globalFilters: {
page: lazyState.page ? lazyState.page + 1 : 1,
limit: lazyState.rows,
sortBy
},
status: statuses,
filters: Object.keys(lazyState.filters).reduce((acc, cur) => {
const value = pathOr('', ['filters', cur, 'value'], lazyState);
if (!isEmpty(value)) {
acc[cur] = lazyState.filters[cur];
}
return acc;
}, {}),
}
}, [lazyState]);
const onPage = (event) => {
setLazyState(event);
};
const onSort = (event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
};
const onFilter = useCallback((event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
}, [lazyState]);
const getCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const { body, totalRecords,
//currentPage, totalPages, pageSize
} = resp.data;
setTotalRecordsNum(totalRecords);
setItems(getFormattedData(body));
}
setLocalAsyncRequest(false);
}
const errGetCallbacks = () => {
setLocalAsyncRequest(false);
}
const getFormattedData = (data) => {
return [...(data || [])].map((d) => {
d.startDate = new Date(d.dates[0]);
d.endDate = new Date(d.dates[1]);
return d;
});
};
const actionsBodyTemplate = (rowData) => {
return <Link to={`/bandi/${rowData.id}`}>
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small" iconPos="right" />
</Link>
}
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => {
options.filterCallback(e.value, options.index)
const filters = { ...lazyState.filters };
if (e.value) {
filters['status'] = { value: e.value, matchMode: 'equals' };
} else {
delete filters['status'];
}
setLazyState({ ...lazyState, filters, first: 0 });
}}
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter"
showClear/>;
};
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 dateStartBodyTemplate = (rowData) => {
const startTimeObj = getTimeParsedFromString(rowData.startTime);
return getFormattedDateString(rowData.startDate) + ' ' + getTimeFromISOstring(startTimeObj);
};
const dateEndBodyTemplate = (rowData) => {
const endTimeObg = getTimeParsedFromString(rowData.endTime);
return getFormattedDateString(rowData.endDate) + ' ' + getTimeFromISOstring(endTimeObg);
};
useEffect(() => {
setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery();
BandoService.getBandiPaginated(paginationQuery, getCallback, errGetCallbacks);
}, [lazyState]);
return (
<div className="appPageSection__table">
<DataTable
value={items} stripedRows showGridlines
lazy filterDisplay="menu" dataKey="id" paginator
first={lazyState.first} rows={lazyState.rows} totalRecords={totalRecordsNum} onPage={onPage}
onSort={onSort} sortField={lazyState.sortField} sortOrder={lazyState.sortOrder}
onFilter={onFilter} filters={lazyState.filters} loading={localAsyncRequest}
emptyMessage={translationStrings.emptyMessage}>
<Column field="name"
sortable
filterField="name" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
header={__('Nome Bando', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data Pubblicazione', 'gepafin')}
filterElement={dateFilterTemplate} filter
filterField="startDate" dataType="date"
filterMatchModeOptions={translationStrings.dateFilterOptions}
style={{ minWidth: '8rem' }}
body={dateStartBodyTemplate}/>
<Column header={__('Data Scadenza', 'gepafin')}
filterElement={dateFilterTemplate} filter
filterField="endDate" dataType="date"
filterMatchModeOptions={translationStrings.dateFilterOptions}
style={{ minWidth: '8rem' }}
body={dateEndBodyTemplate}/>
<Column field="status"
filterElement={statusFilterTemplate} filter
filterMatchModeOptions={translationStrings.statusFilterOptions}
header={__('Stato', 'gepafin')}
style={{ minWidth: '7rem' }}
body={statusBodyTemplate} />
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default LatestBandiTableAsync;

View File

@@ -8,12 +8,12 @@ import NumberFlow from '@number-flow/react';
import DashboardService from '../../service/dashboard-service';
// components
import LatestBandiTable from './components/LatestBandiTable';
import { Button } from 'primereact/button';
import AllDomandeTable from '../Domande/components/AllDomandeTable';
import DraftApplicationsTable from './components/DraftApplicationsTable';
import ChartDomandePerBando from '../../components/ChartDomandePerBando';
import ChartStatoDomande from '../../components/ChartStatoDomande';
import LatestBandiTableAsync from './components/LatestBandiTableAsync';
import AllDomandeTableAsync from '../Domande/components/AllDomandeTableAsync';
import DraftApplicationsTableAsync from './components/DraftApplicationsTableAsync';
const Dashboard = () => {
const navigate = useNavigate();
@@ -136,30 +136,23 @@ const Dashboard = () => {
<div className="appPageSection">
<h2>{__('Ultimi bandi pubblicati', 'gepafin')}</h2>
<LatestBandiTable/>
<LatestBandiTableAsync/>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<h2>{__('Ultime domande pubblicate', 'gepafin')}</h2>
<AllDomandeTable/>
<AllDomandeTableAsync/>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<h2>{__('Domande in bozza', 'gepafin')}</h2>
<DraftApplicationsTable/>
<DraftApplicationsTableAsync/>
</div>
{/*<div className="appPage__spacer"></div>
<div className="appPageSection">
<h2>{__('Attività Recenti Utenti', 'gepafin')}</h2>
<LatestUsersActivityTable/>
</div>*/}
<div className="appPage__spacer"></div>
{chartStats.applicationPerCall

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { uniq, is, isEmpty } from 'ramda';
import { uniq, is, head } from 'ramda';
// tools
import getBandoLabel from '../../../../helpers/getBandoLabel';
@@ -25,16 +25,20 @@ import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Link } from 'react-router-dom';
import translationStrings from '../../../../translationStringsForComponents';
import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup';
import isDateTimeInPast from '../../../../helpers/isDateTimeInPast';
const MyLatestSubmissionsTable = () => {
const chosenCompanyId = useStore().main.chosenCompanyId();
const companies = useStore().main.companies();
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [statuses, setStatuses] = useState([]);
useEffect(() => {
if (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0) {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany) {
setLocalAsyncRequest(true);
ApplicationService.getApplications(getApplCallback, errGetApplCallback, [
['companyId', chosenCompanyId],
@@ -162,25 +166,28 @@ const MyLatestSubmissionsTable = () => {
};
const actionsBodyTemplate = (rowData) => {
return 'DRAFT' === rowData.status
? <div className="appPageSection__tableActions lessGap">
<Link to={`/imieibandi/${rowData.id}`}>
const isCallExpired = isDateTimeInPast(rowData.callEndDate, rowData.callEndTime);
return <div className="appPageSection__tableActions lessGap">
{'DRAFT' === rowData.status && !isCallExpired
? <Link to={`/imieibandi/${rowData.id}`}>
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small"
iconPos="right"/>
</Link>
: null}
{'DRAFT' !== rowData.status || isCallExpired
? <Link to={`/imieibandi/${rowData.id}`}>
<Button severity="info" label={__('Mostra', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/>
</Link>
: null}
<ConfirmPopup/>
<Button severity="danger"
/*onClick={() => handleDeleteApplication(rowData.id)}*/
onClick={(event) => confirmDelete(event, rowData.id)}
label={__('Cancella', 'gepafin')}
icon="pi pi-trash"
size="small"
iconPos="right"/>
</div>
: <Link to={`/imieibandi/${rowData.id}`}>
<Button severity="info" label={__('Mostra', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/>
</Link>
}

View File

@@ -5,16 +5,16 @@ import { head, isEmpty, pathOr } from 'ramda';
import NumberFlow from '@number-flow/react';
// store
import { useStore } from '../../store';
import { storeSet, useStore } from '../../store';
// api
import DashboardService from '../../service/dashboard-service';
// components
import LatestBandiTable from './components/LatestBandiTable';
import MyLatestSubmissionsTable from './components/MyLatestSubmissionsTable';
import { Button } from 'primereact/button';
import ErrorBoundary from '../../components/ErrorBoundary';
import LatestBandiTableAsync from '../Dashboard/components/LatestBandiTableAsync';
const DashboardBeneficiario = () => {
const navigate = useNavigate();
@@ -108,7 +108,7 @@ const DashboardBeneficiario = () => {
<div className="appPageSection">
<h2>{__('Bandi disponibili', 'gepafin')}</h2>
<ErrorBoundary><LatestBandiTable/></ErrorBoundary>
<ErrorBoundary><LatestBandiTableAsync/></ErrorBoundary>
</div>
<div className="appPage__spacer"></div>

View File

@@ -0,0 +1,198 @@
import React, { useEffect, useState, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty, pathOr } from 'ramda';
import translationStrings from '../../../../translationStringsForComponents';
// api
import BandoService from '../../../../service/bando-service';
// tools
import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString';
import getTimeFromISOstring from '../../../../helpers/getTimeFromISOstring';
import getFormattedDateString from '../../../../helpers/getFormattedDateString';
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Dropdown } from 'primereact/dropdown';
import { Tag } from 'primereact/tag';
import { Calendar } from 'primereact/calendar';
const LatestBandiTableInstructorManagerAsync = () => {
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
const [lazyState, setLazyState] = useState({
first: 0,
rows: 5,
page: 0,
sortField: null,
sortOrder: null,
filters: {
name: { value: null, matchMode: 'contains' },
startDate: { value: null, matchMode: 'date_is' },
endDate: { value: null, matchMode: 'date_is' },
status: { value: null, matchMode: 'equals' }
}
});
const statuses = ['PUBLISH'];
const getPaginationQuery = useCallback(() => {
let sortBy = {
columnName: "ID",
sortDesc: true
};
if (lazyState.sortField) {
sortBy = {
columnName: lazyState.sortField,
sortDesc: lazyState.sortOrder === -1
}
}
return {
globalFilters: {
page: lazyState.page ? lazyState.page + 1 : 1,
limit: lazyState.rows,
sortBy
},
status: statuses,
filters: Object.keys(lazyState.filters).reduce((acc, cur) => {
const value = pathOr('', ['filters', cur, 'value'], lazyState);
if (!isEmpty(value)) {
acc[cur] = lazyState.filters[cur];
}
return acc;
}, {}),
}
}, [lazyState]);
const onPage = (event) => {
setLazyState(event);
};
const onSort = (event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
};
const onFilter = useCallback((event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
}, [lazyState]);
const getCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const { body, totalRecords,
//currentPage, totalPages, pageSize
} = resp.data;
setTotalRecordsNum(totalRecords);
setItems(getFormattedData(body));
}
setLocalAsyncRequest(false);
}
const errGetCallbacks = () => {
setLocalAsyncRequest(false);
}
const getFormattedData = (data) => {
return [...(data || [])].map((d) => {
d.startDate = new Date(d.dates[0]);
d.endDate = new Date(d.dates[1]);
return d;
});
};
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => {
options.filterCallback(e.value, options.index)
const filters = { ...lazyState.filters };
if (e.value) {
filters['status'] = { value: e.value, matchMode: 'equals' };
} else {
delete filters['status'];
}
setLazyState({ ...lazyState, filters, first: 0 });
}}
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter"
showClear/>;
};
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 dateStartBodyTemplate = (rowData) => {
const startTimeObj = getTimeParsedFromString(rowData.startTime);
return getFormattedDateString(rowData.startDate) + ' ' + getTimeFromISOstring(startTimeObj);
};
const dateEndBodyTemplate = (rowData) => {
const endTimeObg = getTimeParsedFromString(rowData.endTime);
return getFormattedDateString(rowData.endDate) + ' ' + getTimeFromISOstring(endTimeObg);
};
useEffect(() => {
setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery();
BandoService.getBandiPaginated(paginationQuery, getCallback, errGetCallbacks);
}, [lazyState]);
return (
<div className="appPageSection__table">
<DataTable
value={items} stripedRows showGridlines
lazy filterDisplay="menu" dataKey="id" paginator
first={lazyState.first} rows={lazyState.rows} totalRecords={totalRecordsNum} onPage={onPage}
onSort={onSort} sortField={lazyState.sortField} sortOrder={lazyState.sortOrder}
onFilter={onFilter} filters={lazyState.filters} loading={localAsyncRequest}
emptyMessage={translationStrings.emptyMessage}>
<Column field="name"
sortable
filterField="name" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
header={__('Nome Bando', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data Pubblicazione', 'gepafin')}
filterElement={dateFilterTemplate} filter
filterField="startDate" dataType="date"
filterMatchModeOptions={translationStrings.dateFilterOptions}
style={{ minWidth: '8rem' }}
body={dateStartBodyTemplate}/>
<Column header={__('Data Scadenza', 'gepafin')}
filterElement={dateFilterTemplate} filter
filterField="endDate" dataType="date"
filterMatchModeOptions={translationStrings.dateFilterOptions}
style={{ minWidth: '8rem' }}
body={dateEndBodyTemplate}/>
<Column field="status"
filterElement={statusFilterTemplate} filter
filterMatchModeOptions={translationStrings.statusFilterOptions}
header={__('Stato', 'gepafin')}
style={{ minWidth: '7rem' }}
body={statusBodyTemplate} />
</DataTable>
</div>
)
}
export default LatestBandiTableInstructorManagerAsync;

View File

@@ -0,0 +1,276 @@
import React, { useEffect, useState, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { head, is, isEmpty, pathOr } from 'ramda';
import { klona } from 'klona';
import translationStrings from '../../../../translationStringsForComponents';
// api
import AssignedApplicationService from '../../../../service/assigned-application-service';
// store
import { useStore } from '../../../../store';
// tools
import getFormattedDateString from '../../../../helpers/getFormattedDateString';
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Dropdown } from 'primereact/dropdown';
import { Tag } from 'primereact/tag';
import { Calendar } from 'primereact/calendar';
import { Button } from 'primereact/button';
import { Link, useNavigate } from 'react-router-dom';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const MieDomandeTableInstructorManagerAsync = ({ userId = null, statuses = [] }) => {
const navigate = useNavigate();
const userData = useStore().main.userData();
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
const [lazyState, setLazyState] = useState({
first: 0,
rows: 5,
page: 0,
sortField: null,
sortOrder: null,
filters: {
applicationId: { value: null, matchMode: 'contains' },
protocolNumber: { value: null, matchMode: 'contains' },
callName: { value: null, matchMode: 'contains' },
companyName: { value: null, matchMode: 'contains' },
submissionDate: { value: null, matchMode: 'date_is' },
evaluationEndDate: { value: null, matchMode: 'date_is' },
status: { value: null, matchMode: 'equals' }
}
});
const getPaginationQuery = useCallback(() => {
let sortBy = {
columnName: "ID",
sortDesc: true
};
if (lazyState.sortField) {
sortBy = {
columnName: lazyState.sortField,
sortDesc: lazyState.sortOrder === -1
}
}
return {
globalFilters: {
page: lazyState.page ? lazyState.page + 1 : 1,
limit: lazyState.rows,
sortBy
},
status: statuses,
filters: Object.keys(lazyState.filters).reduce((acc, cur) => {
const value = pathOr('', ['filters', cur, 'value'], lazyState);
if (!isEmpty(value)) {
acc[cur] = lazyState.filters[cur];
}
return acc;
}, {}),
}
}, [lazyState]);
const onPage = (event) => {
setLazyState(event);
};
const onSort = (event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
};
const onFilter = useCallback((event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
}, [lazyState]);
const getCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const { body, totalRecords,
//currentPage, totalPages, pageSize
} = resp.data;
setTotalRecordsNum(totalRecords);
setItems(getFormattedData(body));
}
setLocalAsyncRequest(false);
}
const errGetCallbacks = () => {
setLocalAsyncRequest(false);
}
const getFormattedData = (data) => {
return data.map((d) => {
d.evaluationEndDate = is(String, d.evaluationEndDate) ? new Date(d.evaluationEndDate) : (d.evaluationEndDate ? d.evaluationEndDate : '');
d.submissionDate = is(String, d.submissionDate) ? new Date(d.submissionDate) : (d.submissionDate ? d.submissionDate : '');
return d;
});
};
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => {
options.filterCallback(e.value, options.index)
const filters = { ...lazyState.filters };
if (e.value) {
filters['status'] = { value: e.value, matchMode: 'equals' };
} else {
delete filters['status'];
}
setLazyState({ ...lazyState, filters, first: 0 });
}}
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter"
showClear/>;
};
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 dateAppliedBodyTemplate = (rowData) => {
return getFormattedDateString(rowData.submissionDate);
};
const dateEndBodyTemplate = (rowData) => {
return getFormattedDateString(rowData.evaluationEndDate);
};
const actionsBodyTemplate = (rowData) => {
if (rowData.status === 'AWAITING') {
return <Button
severity="info"
onClick={() => handleInitiateEvaluation(rowData.id)}
label={__('Valuta', 'gepafin')}
icon="pi pi-eye"
size="small"
iconPos="right"/>
} else {
const label = ['OPEN', 'SOCCORSO'].includes(rowData.status) && userData.id === rowData.userId
? __('Valuta', 'gepafin')
: __('Mostra', 'gepafin');
return <Link to={`/mie-domande/${rowData.applicationId}`}>
<Button severity="info" label={label} icon="pi pi-eye" size="small" iconPos="right"/>
</Link>
}
}
const handleInitiateEvaluation = (id) => {
setLocalAsyncRequest(true);
AssignedApplicationService.updateStatusAssignedApplication(id, getInitEvalCallback, errInitEvalCallbacks, [
['status', 'OPEN']
])
}
const getInitEvalCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const evaluation = klona(head(getFormattedData([resp.data])));
const newItems = items.map(o => o.id === evaluation.id ? evaluation : o);
setItems(newItems);
navigate(`/mie-domande/${evaluation.applicationId}`);
}
setLocalAsyncRequest(false);
}
const errInitEvalCallbacks = (resp) => {
setLocalAsyncRequest(false);
}
useEffect(() => {
setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery();
if (userId) {
AssignedApplicationService.assignApplicationPaginated(paginationQuery, getCallback, errGetCallbacks, [
['userId', userId]
]);
} else {
AssignedApplicationService.assignApplicationPaginated(paginationQuery, getCallback, errGetCallbacks);
}
}, [lazyState]);
return (
<div className="appPageSection__table">
<DataTable
value={items} stripedRows showGridlines
lazy filterDisplay="menu" dataKey="id" paginator
first={lazyState.first} rows={lazyState.rows} totalRecords={totalRecordsNum} onPage={onPage}
onSort={onSort} sortField={lazyState.sortField} sortOrder={lazyState.sortOrder}
onFilter={onFilter} filters={lazyState.filters} loading={localAsyncRequest}
emptyMessage={translationStrings.emptyMessage}>
<Column field="applicationId" header={__('ID domanda', 'gepafin')}
sortable
filterField="applicationId" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
sortable
filterField="protocolNumber" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
? <Column field="ndg" header={__('NDG', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/> : null}
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
? <Column field="appointmentId" header={__('ID appuntamento', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/> : null}
<Column field="callName" header={__('Bando', 'gepafin')}
sortable
filterField="callName" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="companyName" header={__('Azienda', 'gepafin')}
sortable
filterField="companyName" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data ricezione', 'gepafin')}
filterField="submissionDate" dataType="date"
style={{ minWidth: '8rem' }}
filterMatchModeOptions={translationStrings.dateFilterOptions}
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')}
filterField="evaluationEndDate" dataType="date"
style={{ minWidth: '8rem' }}
filterMatchModeOptions={translationStrings.dateFilterOptions}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="applicationStatus" header={__('Stato', 'gepafin')}
style={{ minWidth: '7rem' }} body={statusBodyTemplate}
filter
filterMatchModeOptions={translationStrings.statusFilterOptions}
filterElement={statusFilterTemplate} />
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default MieDomandeTableInstructorManagerAsync;

View File

@@ -9,11 +9,11 @@ import DashboardService from '../../service/dashboard-service';
// components
import { Button } from 'primereact/button';
import LatestBandiTableInstructorManager from './components/LatestBandiTableInstructorManager';
import AllDomandeTable from '../Domande/components/AllDomandeTable';
import DraftApplicationsTable from '../Dashboard/components/DraftApplicationsTable';
import ChartDomandePerBando from '../../components/ChartDomandePerBando';
import ChartStatoDomande from '../../components/ChartStatoDomande';
import LatestBandiTableInstructorManagerAsync from './components/LatestBandiTableInstructorManagerAsync';
import DraftApplicationsTableAsync from '../Dashboard/components/DraftApplicationsTableAsync';
import AllDomandeTableAsync from '../Domande/components/AllDomandeTableAsync';
const DashboardInstructorManager = () => {
const navigate = useNavigate();
@@ -107,27 +107,23 @@ const DashboardInstructorManager = () => {
<div className="appPage__spacer"></div>
{/*<div className="appPageSection">
<h2>{__('Panoramica delle domande da valutare', 'gepafin')}</h2>
<PreInstructorDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={0}/>
</div>*/}
<div className="appPageSection">
<h2>{__('Ultimi bandi pubblicati', 'gepafin')}</h2>
<LatestBandiTableInstructorManager/>
<LatestBandiTableInstructorManagerAsync/>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<h2>{__('Ultime domande pubblicate', 'gepafin')}</h2>
<AllDomandeTable/>
<AllDomandeTableAsync/>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<h2>{__('Domande in bozza', 'gepafin')}</h2>
<DraftApplicationsTable/>
<DraftApplicationsTableAsync/>
</div>
<div className="appPage__spacer"></div>

View File

@@ -0,0 +1,276 @@
import React, { useEffect, useState, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { head, is, isEmpty, pathOr } from 'ramda';
import { klona } from 'klona';
import translationStrings from '../../../../translationStringsForComponents';
// api
import AssignedApplicationService from '../../../../service/assigned-application-service';
// store
import { useStore } from '../../../../store';
// tools
import getFormattedDateString from '../../../../helpers/getFormattedDateString';
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Dropdown } from 'primereact/dropdown';
import { Tag } from 'primereact/tag';
import { Calendar } from 'primereact/calendar';
import { Button } from 'primereact/button';
import { Link, useNavigate } from 'react-router-dom';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const DomandeTablePreInstructorAsync = ({ userId = null, statuses = [] }) => {
const navigate = useNavigate();
const userData = useStore().main.userData();
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
const [lazyState, setLazyState] = useState({
first: 0,
rows: 5,
page: 0,
sortField: null,
sortOrder: null,
filters: {
applicationId: { value: null, matchMode: 'contains' },
protocolNumber: { value: null, matchMode: 'contains' },
callName: { value: null, matchMode: 'contains' },
companyName: { value: null, matchMode: 'contains' },
submissionDate: { value: null, matchMode: 'date_is' },
evaluationEndDate: { value: null, matchMode: 'date_is' },
status: { value: null, matchMode: 'equals' }
}
});
const getPaginationQuery = useCallback(() => {
let sortBy = {
columnName: "ID",
sortDesc: true
};
if (lazyState.sortField) {
sortBy = {
columnName: lazyState.sortField,
sortDesc: lazyState.sortOrder === -1
}
}
return {
globalFilters: {
page: lazyState.page ? lazyState.page + 1 : 1,
limit: lazyState.rows,
sortBy
},
status: statuses,
filters: Object.keys(lazyState.filters).reduce((acc, cur) => {
const value = pathOr('', ['filters', cur, 'value'], lazyState);
if (!isEmpty(value)) {
acc[cur] = lazyState.filters[cur];
}
return acc;
}, {}),
}
}, [lazyState]);
const onPage = (event) => {
setLazyState(event);
};
const onSort = (event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
};
const onFilter = useCallback((event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
}, [lazyState]);
const getCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const { body, totalRecords,
//currentPage, totalPages, pageSize
} = resp.data;
setTotalRecordsNum(totalRecords);
setItems(getFormattedData(body));
}
setLocalAsyncRequest(false);
}
const errGetCallbacks = () => {
setLocalAsyncRequest(false);
}
const getFormattedData = (data) => {
return data.map((d) => {
d.evaluationEndDate = is(String, d.evaluationEndDate) ? new Date(d.evaluationEndDate) : (d.evaluationEndDate ? d.evaluationEndDate : '');
d.submissionDate = is(String, d.submissionDate) ? new Date(d.submissionDate) : (d.submissionDate ? d.submissionDate : '');
return d;
});
};
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => {
options.filterCallback(e.value, options.index)
const filters = { ...lazyState.filters };
if (e.value) {
filters['status'] = { value: e.value, matchMode: 'equals' };
} else {
delete filters['status'];
}
setLazyState({ ...lazyState, filters, first: 0 });
}}
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter"
showClear/>;
};
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 dateAppliedBodyTemplate = (rowData) => {
return getFormattedDateString(rowData.submissionDate);
};
const dateEndBodyTemplate = (rowData) => {
return getFormattedDateString(rowData.evaluationEndDate);
};
const actionsBodyTemplate = (rowData) => {
if (rowData.status === 'AWAITING') {
return <Button
severity="info"
onClick={() => handleInitiateEvaluation(rowData.id)}
label={__('Valuta', 'gepafin')}
icon="pi pi-eye"
size="small"
iconPos="right"/>
} else {
const label = ['OPEN', 'SOCCORSO'].includes(rowData.status) && userData.id === rowData.userId
? __('Valuta', 'gepafin')
: __('Mostra', 'gepafin');
return <Link to={`/domande/${rowData.applicationId}`}>
<Button severity="info" label={label} icon="pi pi-eye" size="small" iconPos="right"/>
</Link>
}
}
const handleInitiateEvaluation = (id) => {
setLocalAsyncRequest(true);
AssignedApplicationService.updateStatusAssignedApplication(id, getInitEvalCallback, errInitEvalCallbacks, [
['status', 'OPEN']
])
}
const getInitEvalCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const evaluation = klona(head(getFormattedData([resp.data])));
const newItems = items.map(o => o.id === evaluation.id ? evaluation : o);
setItems(newItems);
navigate(`/domande/${evaluation.applicationId}`);
}
setLocalAsyncRequest(false);
}
const errInitEvalCallbacks = (resp) => {
setLocalAsyncRequest(false);
}
useEffect(() => {
setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery();
if (userId) {
AssignedApplicationService.assignApplicationPaginated(paginationQuery, getCallback, errGetCallbacks, [
['userId', userId]
]);
} else {
AssignedApplicationService.assignApplicationPaginated(paginationQuery, getCallback, errGetCallbacks);
}
}, [lazyState]);
return (
<div className="appPageSection__table">
<DataTable
value={items} stripedRows showGridlines
lazy filterDisplay="menu" dataKey="id" paginator
first={lazyState.first} rows={lazyState.rows} totalRecords={totalRecordsNum} onPage={onPage}
onSort={onSort} sortField={lazyState.sortField} sortOrder={lazyState.sortOrder}
onFilter={onFilter} filters={lazyState.filters} loading={localAsyncRequest}
emptyMessage={translationStrings.emptyMessage}>
<Column field="applicationId" header={__('ID domanda', 'gepafin')}
sortable
filterField="applicationId" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
sortable
filterField="protocolNumber" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
? <Column field="ndg" header={__('NDG', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/> : null}
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
? <Column field="appointmentId" header={__('ID appuntamento', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/> : null}
<Column field="callName" header={__('Bando', 'gepafin')}
sortable
filterField="callName" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="companyName" header={__('Azienda', 'gepafin')}
sortable
filterField="companyName" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data ricezione', 'gepafin')}
filterField="submissionDate" dataType="date"
style={{ minWidth: '8rem' }}
filterMatchModeOptions={translationStrings.dateFilterOptions}
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')}
filterField="evaluationEndDate" dataType="date"
style={{ minWidth: '8rem' }}
filterMatchModeOptions={translationStrings.dateFilterOptions}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="applicationStatus" header={__('Stato', 'gepafin')}
style={{ minWidth: '7rem' }} body={statusBodyTemplate}
filter
filterMatchModeOptions={translationStrings.statusFilterOptions}
filterElement={statusFilterTemplate} />
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default DomandeTablePreInstructorAsync;

View File

@@ -103,7 +103,7 @@ const PreInstructorDomandeTable = ({ userId = null, statuses = [] }) => {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] }
applicationStatus: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] }
});
};
@@ -128,7 +128,7 @@ const PreInstructorDomandeTable = ({ userId = null, statuses = [] }) => {
};
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
return <ProperBandoLabel status={rowData.applicationStatus}/>;
};
const statusFilterTemplate = (options) => {
@@ -216,7 +216,7 @@ const PreInstructorDomandeTable = ({ userId = null, statuses = [] }) => {
<Column header={__('Scadenza', 'gepafin')} filterField="evaluationEndDate" dataType="date"
style={{ minWidth: '8rem' }}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="status" header={__('Stato', 'gepafin')}
<Column field="applicationStatus" header={__('Stato', 'gepafin')}
style={{ minWidth: '7rem' }} body={statusBodyTemplate} filter
filterElement={statusFilterTemplate} />
<Column header={__('Azioni', 'gepafin')}

View File

@@ -12,7 +12,7 @@ import DashboardService from '../../service/dashboard-service';
// components
import { Button } from 'primereact/button';
import PreInstructorDomandeTable from './components/PreInstructorDomandeTable';
import DomandeTablePreInstructorAsync from './components/DomandeTablePreInstructorAsync';
const DashboardPreInstructor = () => {
const navigate = useNavigate();
@@ -110,7 +110,8 @@ const DashboardPreInstructor = () => {
<div className="appPageSection">
<h2>{__('Coda di lavoro', 'gepafin')}</h2>
<PreInstructorDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={userData.id}/>
{/*<PreInstructorDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={userData.id}/>*/}
<DomandeTablePreInstructorAsync statuses={['OPEN', 'SOCCORSO']} userId={userData.id}/>
</div>
<div className="appPage__spacer"></div>

View File

@@ -0,0 +1,225 @@
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { head, is, uniq } from 'ramda';
// store
import { useStore } from '../../../../store';
// tools
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
// api
import CompanyDocumentsService from '../../../../service/company-documents-service';
// components
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Dropdown } from 'primereact/dropdown';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import { Tag } from 'primereact/tag';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup';
const DocumentsTable = ({ type, reload = 0 }) => {
const chosenCompanyId = useStore().main.chosenCompanyId();
const companies = useStore().main.companies();
const [docs, setDocs] = useState([]);
const [filters, setFilters] = useState(null);
const [loading, setLoading] = useState(false);
const [statuses, setStatuses] = useState([]);
useEffect(() => {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (!loading && existingCompany && reload !== 0) {
setLoading(true);
CompanyDocumentsService.getCompanyDocuments(chosenCompanyId, getCallback, errGetCallbacks, [
['documentType', type]
]);
}
}, [chosenCompanyId, reload]);
useEffect(() => {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany) {
setLoading(true);
CompanyDocumentsService.getCompanyDocuments(chosenCompanyId, getCallback, errGetCallbacks, [
['documentType', type]
]);
}
}, []);
const getCallback = (resp) => {
if (resp.status === 'SUCCESS') {
setDocs(getFormattedData(resp.data));
setStatuses(uniq(resp.data.map(o => o.status)))
initFilters();
}
setLoading(false);
}
const errGetCallbacks = () => {
setLoading(false);
}
const getFormattedData = (data) => {
return data.map((d) => {
d.callEndDate = is(String, d.callEndDate) ? new Date(d.callEndDate) : (d.callEndDate ? d.callEndDate : '');
return d;
});
};
const clearFilter = () => {
initFilters();
};
const initFilters = () => {
setFilters({
name: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
createdDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
expirationDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}
});
};
const renderHeader = () => {
return (
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
</div>
);
};
const dateCreatedBodyTemplate = (rowData) => {
return getDateFromISOstring(rowData.createdDate);
};
const dateExpirationBodyTemplate = (rowData) => {
return getDateFromISOstring(rowData.expirationDate);
};
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 catBodyTemplate = (rowData) => {
return rowData.category.categoryName;
};
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => options.filterCallback(e.value, options.index)}
itemTemplate={statusItemTemplate} placeholder={__('Scegli uno', 'gepafin')}
className="p-column-filter"
showClear/>;
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
const handleDeleteFile = (id) => {
setLoading(true);
CompanyDocumentsService.deleteCompanyDocument(id,(resp) => deleteCallback(resp, id), errDeleteCallback)
}
const deleteCallback = (resp, deletedId) => {
if (resp.status === 'SUCCESS') {
setDocs(docs.filter(o => o.id !== deletedId));
}
setLoading(false);
}
const errDeleteCallback = () => {
setLoading(false);
}
const actionsBodyTemplate = (rowData) => {
return <div className="appPageSection__iconActions">
<Button icon="pi pi-eye" rounded
onClick={() => {
window.open(rowData.filePath, '_blank').focus()
}}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/>
{/*<Button icon="pi pi-sync" rounded
onClick={() => {}}
outlined severity="success"
aria-label={__('Aggiorna', 'gepafin')}/>*/}
<ConfirmPopup/>
<Button icon="pi pi-trash" rounded
onClick={(event) => confirmDelete(event, rowData.id)}
outlined severity="danger"
aria-label={__('Cancella', 'gepafin')}/>
</div>
}
const confirmDelete = (event, id) => {
confirmPopup({
target: event.currentTarget,
message: __('Sei sicuro di voler rimuovere il file?', 'gepafin'),
acceptLabel: __('Si', 'gepafin'),
icon: 'pi pi-info-circle',
defaultFocus: 'reject',
acceptClassName: 'p-button-danger',
accept: () => {
handleDeleteFile(id);
},
reject: () => {
}
});
};
const header = renderHeader();
return (
<div className="appPageSection__table">
<DataTable value={docs} paginator showGridlines rows={5} loading={loading} dataKey="id"
filters={filters} stripedRows removableSort
header={header}
onFilter={(e) => setFilters(e.filters)}>
<Column field="name"
header={__('Nome documento', 'gepafin')}
filter filterField="name"
filterPlaceholder={__('Cerca per nome', 'gepafin')}
style={{ minWidth: '12rem' }}/>
<Column body={catBodyTemplate} header={__('Categoria', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data caricamento', 'gepafin')}
filterField="createdDate" dataType="date"
style={{ minWidth: '7rem' }}
body={dateCreatedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Data scadenza', 'gepafin')}
filterField="expirationDate" dataType="date"
style={{ minWidth: '7rem' }}
body={dateExpirationBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="status" header={__('Stato', 'gepafin')}
filterMenuStyle={{ width: '14rem' }}
style={{ width: '120px' }} body={statusBodyTemplate}
filterElement={statusFilterTemplate}/>
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default DocumentsTable;

View File

@@ -0,0 +1,230 @@
import React, { useCallback, useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { classNames } from 'primereact/utils';
import { wrap } from 'object-path-immutable';
import { isEmpty, isNil } from 'ramda';
// api
import DocumentCategoryService from '../../service/document-category-service';
// components
import DocumentsTable from './components/DocumentsTable';
import { Dialog } from 'primereact/dialog';
import { Button } from 'primereact/button';
import { Dropdown } from 'primereact/dropdown';
import { InputText } from 'primereact/inputtext';
import { storeSet, useStore } from '../../store';
import { Calendar } from 'primereact/calendar';
import { FileUpload } from 'primereact/fileupload';
import formatDateString from '../../helpers/formatDateString';
import CompanyDocumentsService from '../../service/company-documents-service';
const DocumentsBeneficiary = () => {
const [loading, setLoading] = useState(false);
const chosenCompanyId = useStore().main.chosenCompanyId();
const [isVisibleAddNewDialog, setIsVisibleAddNewDialog] = useState(false);
const documentCategories= useStore().main.documentCategories();
const [newFileData, setNewFileData] = useState({});
const [fileAttached, setFileAttached] = useState([]);
const [reloadHash, setReloadHash] = useState(0);
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
const onCreateNew = useCallback((type) => {
const newData = wrap({})
.set(['documentType'], type)
.set(['documentCategoryId'], 0)
.set(['expirationDate'], '')
.set(['name'], '')
.value();
setNewFileData(newData);
setFileAttached([]);
setIsVisibleAddNewDialog(true);
}, [newFileData, chosenCompanyId]);
const hideAddNewDialog = () => {
setIsVisibleAddNewDialog(false);
const newData = wrap({})
.set(['documentType'], '')
.set(['documentCategoryId'], 0)
.set(['expirationDate'], '')
.set(['name'], '')
.value();
setNewFileData(newData);
setFileAttached([]);
}
const headerAddNewDialog = () => {
return <span>{__('Aggiungi file', 'gepafin')}</span>
}
const footerAddNewDialog = () => {
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideAddNewDialog} outlined/>
<Button
type="button"
disabled={loading || !isValidForm()}
label={__('Salva', 'gepafin')} onClick={doAddNew}/>
</div>
}
const isValidForm = useCallback(() => {
return !isEmpty(fileAttached) && !Object.keys(newFileData).filter(k => isInvalidField(newFileData, k)
|| newFileData[k] === 0).length
}, [fileAttached, newFileData]);
const doAddNew = useCallback(() => {
const submitData = {
...newFileData,
expirationDate: formatDateString(newFileData.expirationDate)
}
const queryParams = Object.keys(submitData).map(k => [
k, submitData[k]
]);
if (!isEmpty(fileAttached)) {
const formData = new FormData()
for (const file of fileAttached) {
formData.append('file', file)
}
setLoading(true);
CompanyDocumentsService.uploadCompanyDocument(chosenCompanyId, formData, uploadDoc, errUploadDoc, queryParams);
}
}, [fileAttached, newFileData, chosenCompanyId]);
const uploadDoc = (resp) => {
if (resp.status === 'SUCCESS') {
hideAddNewDialog();
setReloadHash(new Date().getTime())
}
setLoading(false);
}
const errUploadDoc = () => {
setLoading(false);
}
const isInvalidField = (data, key) => isEmpty(data[key]) || isNil(data[key]);
const onUpdateFieldValue = useCallback((value, name) => {
const newData = wrap(newFileData).set([name], value).value();
setNewFileData(newData);
}, [newFileData]);
const onFileSelect = (file) => {
setFileAttached(file.files);
}
const getCategories = (resp) => {
if (resp.status === 'SUCCESS') {
storeSet.main.documentCategories(resp.data.map(o => ({value: o.id, label: o.description})));
}
setLoading(false);
}
const errGetCategories = () => {
setLoading(false);
}
useEffect(() => {
setLoading(true);
DocumentCategoryService.getCategories(getCategories, errGetCategories)
}, []);
return(
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Gestione documenti', 'gepafin')}</h1>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection statsBigBadges">
<h2>
{__('Documenti del rappresentante legale', 'gepafin')}
<Button
onClick={() => onCreateNew('PERSONAL_DOCUMENT')}
size="small"
label={__('Aggiungi nuovo')} icon="pi pi-plus" iconPos="right"/>
</h2>
<DocumentsTable type="PERSONAL_DOCUMENT" reload={reloadHash}/>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection statsBigBadges">
<h2>
{__('Documenti dell\'azienda', 'gepafin')}
<Button
onClick={() => onCreateNew('COMPANY_DOCUMENT')}
size="small"
label={__('Aggiungi nuovo')} icon="pi pi-plus" iconPos="right"/>
</h2>
<DocumentsTable type="COMPANY_DOCUMENT" reload={reloadHash}/>
</div>
<Dialog
visible={isVisibleAddNewDialog}
modal
header={headerAddNewDialog}
footer={footerAddNewDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideAddNewDialog}>
<div className="appForm__cols">
<div className="appForm__field">
<label
className={classNames({ 'p-error': isInvalidField(newFileData, 'name') })}>
{__('Nome', 'gepafin')}*
</label>
<InputText value={newFileData.name}
invalid={isInvalidField(newFileData, 'name')}
onChange={(e) => onUpdateFieldValue(e.target.value, 'name')}/>
</div>
<div className="appForm__field">
<label
className={classNames({ 'p-error': isInvalidField(newFileData, 'documentCategoryId') || newFileData.documentCategoryId === 0 })}>
{__('Categoria', 'gepafin')}*
</label>
<Dropdown
value={newFileData.documentCategoryId}
invalid={isEmpty(newFileData.documentCategoryId) || isNil(newFileData.documentCategoryId) || newFileData.documentCategoryId === 0}
onChange={(e) => onUpdateFieldValue(e.value, 'documentCategoryId')}
options={documentCategories}
optionLabel="label"
optionValue="value"/>
</div>
</div>
<div className="appForm__cols">
<div className="appForm__field">
<label
className={classNames({ 'p-error': isEmpty(newFileData.expirationDate) || isNil(newFileData.expirationDate) })}>
{__('Scadenza', 'gepafin')}*
</label>
<Calendar
value={newFileData.expirationDate}
minDate={tomorrow}
invalid={isEmpty(newFileData.expirationDate) || isNil(newFileData.expirationDate) || newFileData.expirationDate === 0}
onChange={(e) => onUpdateFieldValue(e.value, 'expirationDate')}/>
</div>
</div>
<div className="appForm__cols">
<div className="appForm__field">
<label
className={classNames({ 'p-error': isEmpty(newFileData.file) || isNil(newFileData.expirationDate) })}>
{__('File', 'gepafin')}*
</label>
<FileUpload
mode="basic"
name="file"
onSelect={onFileSelect}/>
</div>
</div>
</Dialog>
</div>
)
}
export default DocumentsBeneficiary;

View File

@@ -71,6 +71,7 @@ const DomandaEditInstructorManager = () => {
const [isVisibleCompleteDialog, setIsVisibleCompleteDialog] = useState(false);
const [operationType, setOperationType] = useState('');
const [motivation, setMotivation] = useState('');
const [amountAccepted, setAmountAccepted] = useState(0);
const [isVisibleAppointmentDialog, setIsVisibleAppointmentDialog] = useState(false);
const [allFilesRated, setAllFilesRated] = useState(false);
const [atLeastOneChecked, setAtLeastOneChecked] = useState(false);
@@ -167,10 +168,14 @@ const DomandaEditInstructorManager = () => {
if (connectedSoccorsoId !== 0) {
navigate(`/mie-domande/${id}/soccorso/${connectedSoccorsoId}`);
} else {
doSaveDraft(`/mie-domande/${id}/aggiungi-soccorso/`)
doSaveDraft(navigateToNewSoccorso)
}
}
const navigateToNewSoccorso = () => {
navigate(`/mie-domande/${id}/aggiungi-soccorso/`);
}
const getVersion = (resp) => {
if (resp.status === 'SUCCESS') {
if (resp.data.evaluationVersion === 'V1') {
@@ -306,7 +311,7 @@ const DomandaEditInstructorManager = () => {
}, []);
}
const doSaveDraft = useCallback((doRedirect = '') => {
const doSaveDraft = useCallback((afterUpdateCallback = null, cfgModifier = {}) => {
if (data.evaluationVersion === 'V1') {
const submitData = {
criteria: klona(data.criteria),
@@ -318,13 +323,14 @@ const DomandaEditInstructorManager = () => {
})
)),
amendmentDetails: klona(data.amendmentDetails),
note: data.note
note: data.note,
...cfgModifier
};
ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId,
submitData,
(data) => updateCallback(data, doRedirect),
(data) => updateCallback(data, afterUpdateCallback),
errUpdateCallback
);
} else if (data.evaluationVersion === 'V2') {
@@ -338,20 +344,26 @@ const DomandaEditInstructorManager = () => {
})
)),
amendmentDetails: klona(data.amendmentDetails),
note: data.note
note: data.note,
...cfgModifier
}
ApplicationEvaluationService.updateEvaluationV2(
data.assignedApplicationId,
formId,
submitData,
(data) => updateCallback(data, doRedirect),
(data) => updateCallback(data, afterUpdateCallback),
errUpdateCallback
);
}
}, [data]);
const updateCallback = (data, doRedirect = '') => {
/**
*
* @param data {object}
* @param afterUpdateCallback {function}
*/
const updateCallback = (data, afterUpdateCallback = null) => {
if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data));
if (toast.current) {
@@ -361,8 +373,8 @@ const DomandaEditInstructorManager = () => {
detail: data.message
});
}
if (!isEmpty(doRedirect)) {
navigate(doRedirect);
if (afterUpdateCallback) {
afterUpdateCallback();
}
}
storeSet.main.unsetAsyncRequest();
@@ -388,7 +400,8 @@ const DomandaEditInstructorManager = () => {
checklist: klona(data.checklist),
files: klona(data.files),
note: data.note,
motivation
motivation,
amountAccepted
}
setLoading(true);
@@ -396,8 +409,8 @@ const DomandaEditInstructorManager = () => {
ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
} else if (data.evaluationVersion === 'V2') {
const newFormValues = getTransformedSubmitData();
@@ -411,7 +424,8 @@ const DomandaEditInstructorManager = () => {
)),
amendmentDetails: klona(data.amendmentDetails),
note: data.note,
motivation
motivation,
amountAccepted
}
setLoading(true);
@@ -420,8 +434,8 @@ const DomandaEditInstructorManager = () => {
data.assignedApplicationId,
formId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
}
}
@@ -442,8 +456,8 @@ const DomandaEditInstructorManager = () => {
ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
} else if (data.evaluationVersion === 'V2') {
const newFormValues = getTransformedSubmitData();
@@ -466,13 +480,13 @@ const DomandaEditInstructorManager = () => {
data.assignedApplicationId,
formId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
}
}
const updateStatusCallback = (data) => {
const approveRejectCallback = (data) => {
if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data));
if (toast.current) {
@@ -486,7 +500,7 @@ const DomandaEditInstructorManager = () => {
setLoading(false);
}
const errUpdateStatusCallback = (data) => {
const errApproveRejectCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
@@ -575,10 +589,10 @@ const DomandaEditInstructorManager = () => {
set404FromErrorResponse(data);
}
const shouldDisableField = (fieldName) => {
return !['EVALUATION'].includes(data.applicationStatus)
const shouldDisableField = useCallback((fieldName) => {
return !['EVALUATION', 'ADMISSIBLE'].includes(data.applicationStatus)
|| (['ADMISSIBLE'].includes(data.applicationStatus) && fieldName !== 'criteria')
}
}, [data.applicationStatus]);
const headerCompleteDialog = () => {
return 'approve' === operationType
@@ -592,15 +606,15 @@ const DomandaEditInstructorManager = () => {
setMotivation('');
}
const footerCompleteDialog = () => {
const footerCompleteDialog = useCallback(() => {
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideCompleteDialog} outlined/>
<Button
type="button"
disabled={loading}
disabled={loading || ('approve' === operationType && (!amountAccepted || isEmpty(amountAccepted) || amountAccepted === 0))}
label={__('Invia', 'gepafin')} onClick={'approve' === operationType ? doApprove : doReject}/>
</div>
}
}, [amountAccepted])
const initiateApproving = () => {
setOperationType('approve');
@@ -614,11 +628,12 @@ const DomandaEditInstructorManager = () => {
}
const doCheckNDG = () => {
doSaveDraft(doGetNDGRequest);
}
const doGetNDGRequest = () => {
storeSet.main.setAsyncRequest();
doSaveDraft();
setTimeout(() => {
AppointmentService.getNdg(id, getNdgCallback, errGetNdgCallback);
}, 100);
}
const getNdgCallback = (data) => {
@@ -733,9 +748,19 @@ const DomandaEditInstructorManager = () => {
}
const doMakeAdmisible = () => {
// TODO
doSaveDraft(null, {
applicationStatus: 'ADMISSIBLE'
});
}
const doPassTechnicalEvaluation = useCallback(() => {
if (isAdmissible) {
doSaveDraft(null, {
applicationStatus: 'TECHNICAL_EVALUATION'
});
}
}, [isAdmissible]);
const evaluationBlockedForUser = (data = {}) => {
const userData = storeGet.main.userData();
return isAsyncRequest || userData.id !== data.assignedUserId;
@@ -807,9 +832,13 @@ const DomandaEditInstructorManager = () => {
/>
<Button
type="button"
disabled={true}
onClick={() => {
}}
disabled={!data.id || !['ADMISSIBLE'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
onClick={doPassTechnicalEvaluation}
icon="pi pi-info-circle" iconPos="right"
tooltip={isAdmissible
? __('Punteggio sufficiente per passaggio alla valutazione tecnica ed economico finanziaria', 'gepafin')
: __('Punteggio non sufficiente per passaggio alla valutazione tecnica ed economico finanziaria', 'gepafin')}
severity={isAdmissible ? 'success' : 'warning'}
label={__('Valutazione tecnico-finanziaria positiva', 'gepafin')}
/>
{data.id
@@ -818,7 +847,7 @@ const DomandaEditInstructorManager = () => {
disabled={!isAdmissible
|| ['APPROVED'].includes(data.applicationStatus)
|| evaluationBlockedForUser(data)
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE'].includes(data.applicationStatus))
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE', 'TECHNICAL_EVALUATION'].includes(data.applicationStatus))
}
onClick={initiateApproving}
label={__('Domanda deliberata', 'gepafin')}
@@ -827,7 +856,7 @@ const DomandaEditInstructorManager = () => {
? <Button
type="button"
disabled={APP_EVALUATION_FLOW_ID === '1'
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT', 'TECHNICAL_EVALUATION'].includes(data.applicationStatus)
|| evaluationBlockedForUser(data))}
onClick={initiateRejecting}
label={__('Respingi domanda', 'gepafin')}
@@ -944,6 +973,15 @@ const DomandaEditInstructorManager = () => {
data,
['evaluationDocument']
)}
updateCallbackFn={(files) => doSaveDraft(
null,
{
evaluationDocument: klona(files.map(o => ({
...o,
fileValue: o.fileValue[0] ? o.fileValue[0].id : ''
})
))
})}
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
sourceId={data.id}
sourceName="evaluation"/>
@@ -1211,6 +1249,18 @@ const DomandaEditInstructorManager = () => {
footer={footerCompleteDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideCompleteDialog}>
{operationType === 'approve'
? <div className="appForm__field">
<label
className={classNames({ 'p-error': !amountAccepted || isEmpty(amountAccepted) || amountAccepted === 0 })}>
{__('Importo approvato', 'gepafin')}
</label>
<InputNumber
value={amountAccepted}
keyfilter="int"
invalid={!amountAccepted || isEmpty(amountAccepted) || amountAccepted === 0}
onChange={(e) => setAmountAccepted(e.value)}/>
</div> : null}
<div className="appForm__field">
<label>{__('Motivazione', 'gepafin')}</label>
<Editor

View File

@@ -6,6 +6,7 @@ import { isNil } from 'ramda';
import getDateTimeFromISOstring from '../../../../helpers/getDateTimeFromISOstring';
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getNumberWithCurrency from '../../../../helpers/getNumberWithCurrency';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
@@ -35,14 +36,6 @@ const ApplicationInfo = ({ data }) => {
<span>{__('Bando', 'gepafin')}</span>
<span>{data.callName}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Referente Aziendale', 'gepafin')}</span>
<span>{data.beneficiary}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
<span>{data.companyName}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Data ricezione', 'gepafin')}</span>
<span>{getDateTimeFromISOstring(data.submissionDate)}</span>
@@ -52,9 +45,29 @@ const ApplicationInfo = ({ data }) => {
<span>{getDateTimeFromISOstring(data.assignedAt)}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Aassegnato a', 'gepafin')}</span>
<span>{__('Assegnato a', 'gepafin')}</span>
<span>{data.assignedUserName}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Referente Aziendale', 'gepafin')}</span>
<span>{data.beneficiary}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
<span>{data.companyName}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Partita IVA', 'gepafin')}</span>
<span>{data.companyVatNumber}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Codice ATECO', 'gepafin')}</span>
<span>{data.companyCodiceAteco}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Importo richiesto', 'gepafin')}</span>
<span>{getNumberWithCurrency(data.amountRequested)}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Scadenza Valutazione', 'gepafin')}</span>
<span>{getDateFromISOstring(data.evaluationEndDate)}</span>

View File

@@ -127,7 +127,7 @@ const RepeaterFields = ({
source={sourceName}
sourceId={sourceId}
multiple={false}
deleteOnBackend={false}
deleteOnBackend={true}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>
</div>

View File

@@ -168,10 +168,14 @@ const DomandaEditPreInstructor = () => {
if (connectedSoccorsoId !== 0) {
navigate(`/domande/${id}/soccorso/${connectedSoccorsoId}`);
} else {
doSaveDraft(`/domande/${id}/aggiungi-soccorso/`)
doSaveDraft(navigateToNewSoccorso)
}
}
const navigateToNewSoccorso = () => {
navigate(`/domande/${id}/aggiungi-soccorso/`);
}
const getVersion = (resp) => {
if (resp.status === 'SUCCESS') {
if (resp.data.evaluationVersion === 'V1') {
@@ -307,7 +311,7 @@ const DomandaEditPreInstructor = () => {
}, []);
}
const doSaveDraft = useCallback((doRedirect = '') => {
const doSaveDraft = useCallback((afterUpdateCallback = null, cfgModifier = {}) => {
if (data.evaluationVersion === 'V1') {
const submitData = {
criteria: klona(data.criteria),
@@ -319,13 +323,14 @@ const DomandaEditPreInstructor = () => {
})
)),
amendmentDetails: klona(data.amendmentDetails),
note: data.note
note: data.note,
...cfgModifier
};
ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId,
submitData,
(data) => updateCallback(data, doRedirect),
(data) => updateCallback(data, afterUpdateCallback),
errUpdateCallback
);
} else if (data.evaluationVersion === 'V2') {
@@ -339,20 +344,26 @@ const DomandaEditPreInstructor = () => {
})
)),
amendmentDetails: klona(data.amendmentDetails),
note: data.note
note: data.note,
...cfgModifier
}
ApplicationEvaluationService.updateEvaluationV2(
data.assignedApplicationId,
formId,
submitData,
(data) => updateCallback(data, doRedirect),
(data) => updateCallback(data, afterUpdateCallback),
errUpdateCallback
);
}
}, [data]);
const updateCallback = (data, doRedirect = '') => {
/**
*
* @param data {object}
* @param afterUpdateCallback {function}
*/
const updateCallback = (data, afterUpdateCallback = null) => {
if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data));
if (toast.current) {
@@ -362,8 +373,8 @@ const DomandaEditPreInstructor = () => {
detail: data.message
});
}
if (!isEmpty(doRedirect)) {
navigate(doRedirect);
if (afterUpdateCallback) {
afterUpdateCallback();
}
}
storeSet.main.unsetAsyncRequest();
@@ -398,8 +409,8 @@ const DomandaEditPreInstructor = () => {
ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
} else if (data.evaluationVersion === 'V2') {
const newFormValues = getTransformedSubmitData();
@@ -413,7 +424,8 @@ const DomandaEditPreInstructor = () => {
)),
amendmentDetails: klona(data.amendmentDetails),
note: data.note,
motivation
motivation,
amountAccepted
}
setLoading(true);
@@ -422,8 +434,8 @@ const DomandaEditPreInstructor = () => {
data.assignedApplicationId,
formId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
}
}
@@ -444,8 +456,8 @@ const DomandaEditPreInstructor = () => {
ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
} else if (data.evaluationVersion === 'V2') {
const newFormValues = getTransformedSubmitData();
@@ -468,13 +480,13 @@ const DomandaEditPreInstructor = () => {
data.assignedApplicationId,
formId,
submitData,
updateStatusCallback,
errUpdateStatusCallback
approveRejectCallback,
errApproveRejectCallback
);
}
}
const updateStatusCallback = (data) => {
const approveRejectCallback = (data) => {
if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data));
if (toast.current) {
@@ -488,7 +500,7 @@ const DomandaEditPreInstructor = () => {
setLoading(false);
}
const errUpdateStatusCallback = (data) => {
const errApproveRejectCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
@@ -577,10 +589,10 @@ const DomandaEditPreInstructor = () => {
set404FromErrorResponse(data);
}
const shouldDisableField = (fieldName) => {
return !['EVALUATION'].includes(data.applicationStatus)
const shouldDisableField = useCallback((fieldName) => {
return !['EVALUATION', 'ADMISSIBLE'].includes(data.applicationStatus)
|| (['ADMISSIBLE'].includes(data.applicationStatus) && fieldName !== 'criteria')
}
}, [data.applicationStatus]);
const headerCompleteDialog = () => {
return 'approve' === operationType
@@ -594,15 +606,15 @@ const DomandaEditPreInstructor = () => {
setMotivation('');
}
const footerCompleteDialog = () => {
const footerCompleteDialog = useCallback(() => {
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideCompleteDialog} outlined/>
<Button
type="button"
disabled={loading}
disabled={loading || ('approve' === operationType && (!amountAccepted || isEmpty(amountAccepted) || amountAccepted === 0))}
label={__('Invia', 'gepafin')} onClick={'approve' === operationType ? doApprove : doReject}/>
</div>
}
}, [amountAccepted])
const initiateApproving = () => {
setOperationType('approve');
@@ -616,11 +628,12 @@ const DomandaEditPreInstructor = () => {
}
const doCheckNDG = () => {
doSaveDraft(doGetNDGRequest);
}
const doGetNDGRequest = () => {
storeSet.main.setAsyncRequest();
doSaveDraft();
setTimeout(() => {
AppointmentService.getNdg(id, getNdgCallback, errGetNdgCallback);
}, 100);
}
const getNdgCallback = (data) => {
@@ -735,9 +748,19 @@ const DomandaEditPreInstructor = () => {
}
const doMakeAdmisible = () => {
// TODO
doSaveDraft(null, {
applicationStatus: 'ADMISSIBLE'
});
}
const doPassTechnicalEvaluation = useCallback(() => {
if (isAdmissible) {
doSaveDraft(null, {
applicationStatus: 'TECHNICAL_EVALUATION'
});
}
}, [isAdmissible]);
const evaluationBlockedForUser = (data = {}) => {
const userData = storeGet.main.userData()
return isAsyncRequest || userData.id !== data.assignedUserId;
@@ -809,18 +832,22 @@ const DomandaEditPreInstructor = () => {
/>
<Button
type="button"
disabled={true}
onClick={() => {
}}
disabled={!data.id || !['ADMISSIBLE'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
onClick={doPassTechnicalEvaluation}
icon="pi pi-info-circle" iconPos="right"
tooltip={isAdmissible
? __('Punteggio sufficiente per passaggio alla valutazione tecnica ed economico finanziaria', 'gepafin')
: __('Punteggio non sufficiente per passaggio alla valutazione tecnica ed economico finanziaria', 'gepafin')}
severity={isAdmissible ? 'success' : 'warning'}
label={__('Valutazione tecnico-finanziaria positiva', 'gepafin')}
/>
{data.id
? <Button
type="button"
disabled={!isAdmissible
|| ['APPROVED','REJECTED'].includes(data.applicationStatus)
|| ['APPROVED', 'REJECTED'].includes(data.applicationStatus)
|| evaluationBlockedForUser(data)
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE'].includes(data.applicationStatus))
|| (APP_EVALUATION_FLOW_ID === '1' && !['TECHNICAL_EVALUATION'].includes(data.applicationStatus))
}
onClick={initiateApproving}
label={__('Domanda deliberata', 'gepafin')}
@@ -828,10 +855,10 @@ const DomandaEditPreInstructor = () => {
{data.id
? <Button
type="button"
disabled={['APPROVED','REJECTED'].includes(data.applicationStatus)
|| APP_EVALUATION_FLOW_ID === '1'
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)
|| evaluationBlockedForUser(data))
disabled={['APPROVED', 'REJECTED'].includes(data.applicationStatus)
|| (APP_EVALUATION_FLOW_ID === '1'
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT', 'TECHNICAL_EVALUATION'].includes(data.applicationStatus)
|| evaluationBlockedForUser(data)))
}
onClick={initiateRejecting}
label={__('Respingi domanda', 'gepafin')}
@@ -949,6 +976,15 @@ const DomandaEditPreInstructor = () => {
data,
['evaluationDocument']
)}
updateCallbackFn={(files) => doSaveDraft(
null,
{
evaluationDocument: klona(files.map(o => ({
...o,
fileValue: o.fileValue[0] ? o.fileValue[0].id : ''
})
))
})}
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
sourceId={data.id}
sourceName="evaluation"/>
@@ -1175,10 +1211,10 @@ const DomandaEditPreInstructor = () => {
<td>
{isAdmissible
? <Tag icon="pi pi-check" severity="success"
value={__('Punteggio sufficiente per passaggio alla valutazione tecnica ed economico finanziaria')}></Tag> : null}
value={__('Punteggio sufficiente per passaggio alla valutazione tecnica ed economico finanziaria', 'gepafin')}></Tag> : null}
{!isAdmissible
? <Tag icon="pi pi-times" severity="warning"
value={__('Punteggio non sufficiente per passaggio alla valutazione tecnica ed economico finanziaria')}></Tag> : null}
value={__('Punteggio non sufficiente per passaggio alla valutazione tecnica ed economico finanziaria', 'gepafin')}></Tag> : null}
</td>
</tr>
</tbody>
@@ -1216,17 +1252,18 @@ const DomandaEditPreInstructor = () => {
footer={footerCompleteDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideCompleteDialog}>
<div className="appForm__field">
{operationType === 'approve'
? <div className="appForm__field">
<label
className={classNames({ 'p-error': isEmpty(amountAccepted) || amountAccepted === 0 })}>
className={classNames({ 'p-error': !amountAccepted || isEmpty(amountAccepted) || amountAccepted === 0 })}>
{__('Importo approvato', 'gepafin')}
</label>
<InputNumber
value={amountAccepted}
keyfilter="int"
invalid={isEmpty(amountAccepted) || amountAccepted === 0}
invalid={!amountAccepted || isEmpty(amountAccepted) || amountAccepted === 0}
onChange={(e) => setAmountAccepted(e.value)}/>
</div>
</div> : null}
<div className="appForm__field">
<label>{__('Motivazione', 'gepafin')}</label>
<Editor

View File

@@ -9,6 +9,7 @@ import ApplicationService from '../../../../service/application-service';
// tools
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
import getFormattedDateString from '../../../../helpers/getFormattedDateString';
// translation
import translationStrings from '../../../../translationStringsForComponents';
@@ -60,14 +61,6 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
});
};
const formatDate = (value) => {
return value.toLocaleDateString('it-IT', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
};
const clearFilter = () => {
initFilters();
};
@@ -105,7 +98,7 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
};
const dateAppliedBodyTemplate = (rowData) => {
return formatDate(rowData.submissionDate);
return getFormattedDateString(rowData.submissionDate);
};
const statusFilterTemplate = (options) => {

View File

@@ -0,0 +1,220 @@
import React, { useEffect, useState, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { is, isEmpty, pathOr } from 'ramda';
import { Link, useLocation } from 'react-router-dom';
import translationStrings from '../../../../translationStringsForComponents';
// api
import ApplicationService from '../../../../service/application-service';
//
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
import getFormattedDateString from '../../../../helpers/getFormattedDateString';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Button } from 'primereact/button';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Dropdown } from 'primereact/dropdown';
import { Tag } from 'primereact/tag';
import { Calendar } from 'primereact/calendar';
const AllDomandeTableAsync = ({ openDialogFn, updaterString = '' }) => {
const location = useLocation();
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [items, setItems] = useState(null);
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
const [lazyState, setLazyState] = useState({
first: 0,
rows: 5,
page: 0,
sortField: null,
sortOrder: null,
filters: {
id: { value: null, matchMode: 'contains' },
callTitle: { value: null, matchMode: 'contains' },
companyName: { value: null, matchMode: 'contains' },
submissionDate: { value: null, matchMode: 'date_is' },
status: { value: null, matchMode: 'equals' }
}
});
const statuses = ['SUBMIT', 'EVALUATION', 'SOCCORSO'];
const getPaginationQuery = useCallback(() => {
let sortBy = {
columnName: "ID",
sortDesc: true
};
if (lazyState.sortField) {
sortBy = {
columnName: lazyState.sortField,
sortDesc: lazyState.sortOrder === -1
}
}
return {
globalFilters: {
page: lazyState.page ? lazyState.page + 1 : 1,
limit: lazyState.rows,
sortBy
},
status: statuses,
filters: Object.keys(lazyState.filters).reduce((acc, cur) => {
const value = pathOr('', ['filters', cur, 'value'], lazyState);
if (!isEmpty(value)) {
acc[cur] = lazyState.filters[cur];
}
return acc;
}, {}),
}
}, [lazyState]);
const onPage = (event) => {
setLazyState(event);
};
const onSort = (event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
};
const onFilter = useCallback((event) => {
event['first'] = 0;
event['page'] = 0;
setLazyState(event);
}, [lazyState]);
const getCallback = (resp) => {
if (resp.status === 'SUCCESS') {
const { body, totalRecords,
//currentPage, totalPages, pageSize
} = resp.data;
setTotalRecordsNum(totalRecords);
setItems(getFormattedData(body));
}
setLocalAsyncRequest(false);
}
const errGetCallbacks = () => {
setLocalAsyncRequest(false);
}
const getFormattedData = (data) => {
return data.map((d) => {
d.callEndDate = is(String, d.callEndDate) ? new Date(d.callEndDate) : (d.callEndDate ? d.callEndDate : '');
d.modifiedDate = is(String, d.modifiedDate) ? new Date(d.modifiedDate) : (d.modifiedDate ? d.modifiedDate : '');
d.submissionDate = is(String, d.submissionDate) ? new Date(d.submissionDate) : (d.submissionDate ? d.submissionDate : '');
return d;
});
};
const actionsBodyTemplate = (rowData) => {
return <div className="appPageSection__tableActions lessGap">
{openDialogFn && ['SUBMIT', 'EVALUATION', 'SOCCORSO'].includes(rowData.status)
? <Button severity="info"
onClick={() => openDialogFn(rowData.id)}
label={__('Assegnare', 'gepafin')}
icon="pi pi-pencil" size="small" iconPos="right"/>
: location.pathname !== '/domande'
? <Link to={'/domande'}>
<Button severity="info" label={__('Gestire', 'gepafin')} size="small"/>
</Link> : null}
<Link to={`/domande/${rowData.id}/preview`}>
<Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/>
</Link>
</div>
}
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => {
options.filterCallback(e.value, options.index)
const filters = { ...lazyState.filters };
if (e.value) {
filters['status'] = { value: e.value, matchMode: 'equals' };
} else {
delete filters['status'];
}
setLazyState({ ...lazyState, filters, first: 0 });
}}
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter"
showClear/>;
};
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 dateAppliedBodyTemplate = (rowData) => {
return getFormattedDateString(rowData.submissionDate);
};
useEffect(() => {
setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery();
ApplicationService.getApplicationsPaginated(paginationQuery, getCallback, errGetCallbacks);
}, [lazyState, updaterString]);
return (
<div className="appPageSection__table">
<DataTable
value={items} stripedRows showGridlines
lazy filterDisplay="menu" dataKey="id" paginator
first={lazyState.first} rows={lazyState.rows} totalRecords={totalRecordsNum} onPage={onPage}
onSort={onSort} sortField={lazyState.sortField} sortOrder={lazyState.sortOrder}
onFilter={onFilter} filters={lazyState.filters} loading={localAsyncRequest}
emptyMessage={translationStrings.emptyMessage}>
<Column field="id" header={__('ID domanda', 'gepafin')}
sortable
filterField="id" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="callTitle" header={__('Bando', 'gepafin')}
filterField="callTitle" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '10rem' }}/>
<Column field="companyName" header={__('Azienda Beneficiaria', 'gepafin')}
filterField="companyName" filter
filterMatchModeOptions={translationStrings.textFilterOptions}
filterPlaceholder={__('Cerca il nome', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column header={__('Data Ricezione', 'gepafin')}
filterElement={dateFilterTemplate} filter
filterField="submissionDate" dataType="date"
filterMatchModeOptions={translationStrings.dateFilterOptions}
style={{ minWidth: '8rem' }}
body={dateAppliedBodyTemplate}/>
<Column field="assignedUserName" header={__('Assegnato', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="status" header={__('Stato', 'gepafin')}
filterElement={statusFilterTemplate} filter
filterMatchModeOptions={translationStrings.statusFilterOptions}
style={{ minWidth: '8rem' }}
body={statusBodyTemplate}/>
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default AllDomandeTableAsync;

View File

@@ -5,6 +5,7 @@ import { isEmpty, pathOr } from 'ramda';
// api
import UserService from '../../service/user-service';
import AssignedApplicationService from '../../service/assigned-application-service';
import DashboardService from '../../service/dashboard-service';
// store
import { storeSet } from '../../store';
@@ -14,14 +15,13 @@ import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import uniqid from '../../helpers/uniqid';
// components
import AllDomandeTable from './components/AllDomandeTable';
import { Dialog } from 'primereact/dialog';
import { Button } from 'primereact/button';
import { classNames } from 'primereact/utils';
import { Dropdown } from 'primereact/dropdown';
import DraftApplicationsTable from '../Dashboard/components/DraftApplicationsTable';
import NumberFlow from '@number-flow/react';
import DashboardService from '../../service/dashboard-service';
import DraftApplicationsTableAsync from '../Dashboard/components/DraftApplicationsTableAsync';
import AllDomandeTableAsync from './components/AllDomandeTableAsync';
const Domande = () => {
const [loading, setLoading] = useState(false);
@@ -166,7 +166,7 @@ const Domande = () => {
<div className="appPageSection">
<h2>{__('Domande pubblicate', 'gepafin')}</h2>
<AllDomandeTable openDialogFn={openAssignDialog} updaterString={updaterString}/>
<AllDomandeTableAsync openDialogFn={openAssignDialog} updaterString={updaterString}/>
</div>
<div className="appPage__spacer"></div>
@@ -224,7 +224,7 @@ const Domande = () => {
<div className="appPageSection">
<h2>{__('Domande in bozza', 'gepafin')}</h2>
<DraftApplicationsTable/>
<DraftApplicationsTableAsync/>
</div>
<Dialog

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { is, isEmpty, uniq } from 'ramda';
import { head, is, uniq } from 'ramda';
import { Link } from 'react-router-dom';
// store
@@ -27,13 +27,16 @@ import translationStrings from '../../../../translationStringsForComponents';
const BeneficiarioDomandeTable = () => {
const chosenCompanyId = useStore().main.chosenCompanyId();
const companies = useStore().main.companies();
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [statuses, setStatuses] = useState([]);
useEffect(() => {
if (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && !localAsyncRequest) {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany && !localAsyncRequest) {
setLocalAsyncRequest(true);
ApplicationService.getApplications(getApplCallback, errGetApplCallback, [
['companyId', chosenCompanyId],

View File

@@ -5,8 +5,8 @@ import { __ } from '@wordpress/i18n';
import { useStore } from '../../store';
// components
import InstructorManagerMieDomandeTable
from '../DashboardInstructorManager/components/InstructorManagerMieDomandeTable';
import MieDomandeTableInstructorManagerAsync
from '../DashboardInstructorManager/components/MieDomandeTableInstructorManagerAsync';
const DomandeMieInstructorManager = () => {
const userData = useStore().main.userData();
@@ -21,14 +21,14 @@ const DomandeMieInstructorManager = () => {
<div className="appPageSection">
<h2>{__('Nuove domande da valutare', 'gepafin')}</h2>
<InstructorManagerMieDomandeTable statuses={['AWAITING']} userId={userData.id}/>
<MieDomandeTableInstructorManagerAsync statuses={['AWAITING']} userId={userData.id}/>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<h2>{__('Coda di lavoro', 'gepafin')}</h2>
<InstructorManagerMieDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={userData.id}/>
<MieDomandeTableInstructorManagerAsync statuses={['OPEN', 'SOCCORSO']} userId={userData.id}/>
</div>
</div>
)

View File

@@ -118,9 +118,12 @@ const Login = () => {
/*if ('t7jh5wfg9QXylNaTZkPoE' === APP_HUB_ID) {
setIsMaintenance(true);
}*/
hotkeys('command+x,ctrl+x', function(event, handler){
hotkeys('command+x,ctrl+x', function(){
window.location.replace('/loginadmin')
});
hotkeys('command+option+x,ctrl+alt+x', function(){
window.location.replace('/confidi')
});
}, []);
return (

View File

@@ -16,6 +16,7 @@ import FormField from '../../components/FormField';
import LogoIcon from '../../icons/LogoIcon';
import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
import hotkeys from 'hotkeys-js';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
@@ -31,7 +32,7 @@ const LoginAdmin = () => {
} = useForm({ mode: 'onChange' });
const gotToResetPassword = () => {
navigate('/reset-password');
navigate('/reset-password-admin');
}
const onSubmit = (formData) => {
@@ -78,12 +79,18 @@ const LoginAdmin = () => {
}
}, [token]);
useEffect(() => {
hotkeys('command+option+x,ctrl+alt+x', function(){
window.location.replace('/confidi')
});
}, []);
return (
<div className={classNames(['appPage', 'appPageLogin'])}>
<div className="appPageLogin__wrapper">
<LogoIcon/>
<h1>{__('Accedi o Registrati', 'gepafin')}</h1>
<h1>{__('Accedi', 'gepafin')}</h1>
<Messages ref={errorMsgs}/>

View File

@@ -0,0 +1,133 @@
import React, { useRef, useState, useEffect } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useForm } from 'react-hook-form';
import { classNames } from 'primereact/utils';
import { isEmpty } from 'ramda';
import { useNavigate } from 'react-router-dom';
// tools
import AuthenticationService from '../../service/authentication-service';
// store
import { storeSet, useStore } from '../../store';
// components
import FormField from '../../components/FormField';
import LogoIcon from '../../icons/LogoIcon';
import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
import hotkeys from 'hotkeys-js';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const LoginConfidi = () => {
const navigate = useNavigate();
const token = useStore().main.token();
const [loading, setLoading] = useState(false);
const errorMsgs = useRef(null);
const {
control,
handleSubmit,
formState: { errors },
} = useForm({ mode: 'onChange' });
const gotToResetPassword = () => {
navigate('/reset-password');
}
const onSubmit = (formData) => {
errorMsgs.current.clear();
setLoading(true);
const request = {
...formData,
hubUuid: APP_HUB_ID,
rememberMe: true
}
AuthenticationService.login(request, loginCallback, loginError);
};
const loginCallback = (data) => {
if (data.status === 'SUCCESS') {
storeSet.main.setAuthData({
token: data.data.token,
userData: data.data.user
});
} else {
errorMsgs.current.show([
{ sticky: true, severity: 'error', summary: '',
detail: data.message,
closable: true }
]);
}
setLoading(false);
}
const loginError = (err) => {
errorMsgs.current.show([
{ sticky: true, severity: 'error', summary: '',
detail: sprintf(__('%s', 'gepafin'), err.message),
closable: true }
]);
setLoading(false);
}
useEffect(() => {
if (!isEmpty(token)) {
setLoading(true);
window.location.replace('/')
}
}, [token]);
useEffect(() => {
hotkeys('command+x,ctrl+x', function(){
window.location.replace('/loginadmin')
});
}, []);
return (
<div className={classNames(['appPage', 'appPageLogin'])}>
<div className="appPageLogin__wrapper">
<LogoIcon/>
<h1>{__('Accesso CONFIDI', 'gepafin')}</h1>
<Messages ref={errorMsgs}/>
<div className="appPage__spacer"></div>
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
<FormField
type="textinput"
fieldName="email"
label={__('Email', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
placeholder="sample@example.com"
/>
<FormField
type="textinput"
inputtype="password"
fieldName="password"
label={__('Password', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>
<Button
label={__('Accedi', 'gepafin')}
disabled={loading}/>
<Button
label={__('Password dimenticata?', 'gepafin')}
link onClick={gotToResetPassword}/>
</form>
</div>
</div>
)
}
export default LoginConfidi;

View File

@@ -36,8 +36,8 @@ const ResetPassword = () => {
setValue
} = useForm({ mode: 'onChange' });
const gotToLoginAdmin = () => {
navigate('/loginadmin');
const gotToLogin = () => {
navigate('/confidi');
}
const onSubmit = (formData) => {
@@ -110,7 +110,6 @@ const ResetPassword = () => {
}, [token]);
useEffect(() => {
console.log(resetPassToken, resetPassEmail);
reset();
setValue('token', resetPassToken);
setValue('email', resetPassEmail);
@@ -191,7 +190,7 @@ const ResetPassword = () => {
<Button
label={__('Accedi', 'gepafin')}
link onClick={gotToLoginAdmin}/>
link onClick={gotToLogin}/>
</form>
</div>
</div>

View File

@@ -0,0 +1,200 @@
import React, { useRef, useState, useEffect } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useForm } from 'react-hook-form';
import { classNames } from 'primereact/utils';
import { isEmpty } from 'ramda';
import { useNavigate, useSearchParams } from 'react-router-dom';
// tools
import AuthenticationService from '../../service/authentication-service';
// store
import { useStore } from '../../store';
// components
import FormField from '../../components/FormField';
import LogoIcon from '../../icons/LogoIcon';
import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const ResetPasswordAdmin = () => {
const navigate = useNavigate();
const token = useStore().main.token();
const [loading, setLoading] = useState(false);
const [resetPassToken, setResetPassToken] = useState('');
const [resetPassEmail, setResetPassEmail] = useState('');
const errorMsgs = useRef(null);
let [searchParams] = useSearchParams();
const {
control,
handleSubmit,
formState: { errors },
reset,
register,
setValue
} = useForm({ mode: 'onChange' });
const gotToLogin = () => {
navigate('/loginadmin');
}
const onSubmit = (formData) => {
errorMsgs.current.clear();
setLoading(true);
const request = {
...formData,
hubUuid: APP_HUB_ID
}
if (request.token && !isEmpty(request.token)) {
AuthenticationService.resetPassword(request, getCallbackReset, errCallback);
} else {
AuthenticationService.forgotPassword(request, getCallback, errCallback);
}
};
const getCallbackReset = (data) => {
if (data.status === 'SUCCESS') {
errorMsgs.current.show([
{
sticky: true, severity: 'success', summary: '',
detail: data.message,
closable: true
}
]);
} else {
errorMsgs.current.show([
{
sticky: true, severity: 'error', summary: '',
detail: data.message,
closable: true
}
]);
}
setLoading(false);
}
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setResetPassToken(data.data)
} else {
errorMsgs.current.show([
{
sticky: true, severity: 'error', summary: '',
detail: data.message,
closable: true
}
]);
}
setLoading(false);
}
const errCallback = (err) => {
errorMsgs.current.show([
{
sticky: true, severity: 'error', summary: '',
detail: sprintf(__('%s', 'gepafin'), err.message),
closable: true
}
]);
setLoading(false);
}
useEffect(() => {
if (!isEmpty(token)) {
setLoading(true);
window.location.replace('/')
}
}, [token]);
useEffect(() => {
reset();
setValue('token', resetPassToken);
setValue('email', resetPassEmail);
}, [resetPassToken, resetPassEmail]);
useEffect(() => {
const token = searchParams.get('token');
const email = searchParams.get('email');
setResetPassToken(token);
setResetPassEmail(email);
}, [searchParams]);
return (
<div className={classNames(['appPage', 'appPageLogin'])}>
<div className="appPageLogin__wrapper">
<LogoIcon/>
<h1>{__('Password dimenticata', 'gepafin')}</h1>
<Messages ref={errorMsgs}/>
<div className="appPage__spacer"></div>
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
<FormField
type="textinput"
fieldName="email"
label={__('Email', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
placeholder="sample@example.com"
/>
{resetPassToken && !isEmpty(resetPassToken)
? <input
type="hidden"
name="token"
{...register('token', {
required: true
})}
/> : null}
{resetPassToken && !isEmpty(resetPassToken)
? <FormField
type="password"
fieldName="newPassword"
label={__('Password', 'gepafin')}
control={control}
errors={errors}
config={{
required: __('È obbligatorio', 'gepafin'),
validate: {
passEqual: (value, values) => values.confirmPassword === value
}
}}
/> : null}
{resetPassToken && !isEmpty(resetPassToken)
? <FormField
type="password"
inputtype="password"
fieldName="confirmPassword"
label={__('Conferma password', 'gepafin')}
control={control}
errors={errors}
config={{
required: __('È obbligatorio', 'gepafin'),
validate: {
passEqual: (value, values) => values.newPassword === value
}
}}
/> : null}
<Button
label={__('Invia', 'gepafin')}
disabled={loading}/>
<Button
label={__('Accedi', 'gepafin')}
link onClick={gotToLogin}/>
</form>
</div>
</div>
)
}
export default ResetPasswordAdmin;

View File

@@ -59,7 +59,7 @@ const PreInstructorSoccorsiTable = ({ userId = null }) => {
const getFormattedData = (data) => {
return data.map((d) => {
d.startDate = is(String, d.startDate) ? new Date(d.startDate) : (d.startDate ? d.startDate : '');
d.evaluationEndDate = is(String, d.evaluationEndDate) ? new Date(d.evaluationEndDate) : (d.evaluationEndDate ? d.evaluationEndDate : '');
d.expirationDate = is(String, d.expirationDate) ? new Date(d.expirationDate) : (d.expirationDate ? d.expirationDate : '');
return d;
});
};
@@ -91,7 +91,7 @@ const PreInstructorSoccorsiTable = ({ userId = null }) => {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
evaluationEndDate: {
expirationDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
@@ -111,7 +111,7 @@ const PreInstructorSoccorsiTable = ({ userId = null }) => {
};
const dateExpirationBodyTemplate = (rowData) => {
return rowData.evaluationEndDate ? formatDate(rowData.evaluationEndDate) : '';
return rowData.expirationDate ? formatDate(rowData.expirationDate) : '';
};
const dateFilterTemplate = (options) => {
@@ -162,7 +162,7 @@ const PreInstructorSoccorsiTable = ({ userId = null }) => {
style={{ minWidth: '8rem' }}
body={dateStartBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')}
filterField="evaluationEndDate" dataType="date"
filterField="expirationDate" dataType="date"
style={{ minWidth: '8rem' }}
body={dateExpirationBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="status"

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { is, isEmpty, uniq } from 'ramda';
import { head, is, uniq } from 'ramda';
// store
import { useStore } from '../../../../store';
@@ -21,6 +21,7 @@ import translationStrings from '../../../../translationStringsForComponents';
const BeneficiarioUltimeDomandeTable = () => {
const chosenCompanyId = useStore().main.chosenCompanyId();
const companies = useStore().main.companies();
const [items, setItems] = useState(null);
// eslint-disable-next-line
const [filters, setFilters] = useState(null);
@@ -43,7 +44,9 @@ const BeneficiarioUltimeDomandeTable = () => {
}
useEffect(() => {
if (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && !localAsyncRequest) {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany && !localAsyncRequest) {
const bodyParams = getPaginationQuery(
['SOCCORSO', 'APPROVED', 'REJECTED', 'EVALUATION', 'SUBMIT'],
1

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useState, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty, pathOr } from 'ramda';
import { head, isEmpty, pathOr } from 'ramda';
import NumberFlow from '@number-flow/react';
// store
@@ -16,6 +16,7 @@ const StatsBeneficiary = () => {
const [mainStats, setMainStats] = useState({});
const [chartStats, setChartStats] = useState({});
const chosenCompanyId = useStore().main.chosenCompanyId();
const companies = useStore().main.companies();
const getStats = (resp) => {
if (resp.status === 'SUCCESS') {
@@ -31,7 +32,11 @@ const StatsBeneficiary = () => {
}, [mainStats]);
useEffect(() => {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany) {
DashboardService.getBeneficiaryStatsPage(chosenCompanyId, getStats, errGetStats);
}
}, [chosenCompanyId]);
return(

View File

@@ -26,23 +26,25 @@ import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import translationStrings from '../../../../translationStringsForComponents';
import { Link } from 'react-router-dom';
const AllUsersTable = () => {
const AllUsersTable = ({ updaterString = '' }) => {
const users = useStore().main.users();
const [filters, setFilters] = useState(null);
const [loading, setLoading] = useState(false);
const [statuses, setStatuses] = useState([]);
const [roles, setRoles] = useState([]);
useEffect(() => {
if (!loading) {
setLoading(true);
UserService.getUsers(getCallback, errGetCallbacks);
}
}, []);
}, [updaterString]);
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
storeSet.main.users(getFormattedData(data.data));
setStatuses(uniq(data.data.map(o => o.status)))
setStatuses(uniq(data.data.map(o => o.status)));
setRoles(uniq(data.data.map(o => o.role.roleName)));
initFilters();
}
setLoading(false);
@@ -54,7 +56,10 @@ const AllUsersTable = () => {
const getFormattedData = (data) => {
return data
.filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(o.role.roleType));
.filter(o => [
'ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER', 'ROLE_CONFIDI'
].includes(o.role.roleType))
.map(o => ({...o, roleName: o.role.roleName}));
};
const clearFilter = () => {
@@ -71,7 +76,8 @@ const AllUsersTable = () => {
lastLogin: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}
},
roleName: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
});
};
@@ -114,6 +120,14 @@ const AllUsersTable = () => {
return <ProperBandoLabel status={rowData.status}/>;
};
const roleFilterTemplate = (options) => {
return <Dropdown value={options.value} options={roles}
onChange={(e) => options.filterCallback(e.value, options.index)}
placeholder={__('Scegli uno', 'gepafin')}
className="p-column-filter"
showClear/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => options.filterCallback(e.value, options.index)}
@@ -155,9 +169,14 @@ const AllUsersTable = () => {
field="email"
filterPlaceholder={__('Cerca per email', 'gepafin')}
style={{ minWidth: '10rem' }}/>
<Column body={roleBodyTemplate} header={__('Ruolo', 'gepafin')}
<Column body={roleBodyTemplate}
filterField="roleName"
filter
filterElement={roleFilterTemplate}
header={__('Ruolo', 'gepafin')}
style={{ minWidth: '8rem' }}/>
<Column field="status" header={__('Stato', 'gepafin')}
<Column field="status"
header={__('Stato', 'gepafin')}
filterMenuStyle={{ width: '14rem' }}
style={{ width: '120px' }} body={statusBodyTemplate}
filterElement={statusFilterTemplate}/>

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty, isNil } from 'ramda';
import { head, isEmpty, isNil } from 'ramda';
import { klona } from 'klona';
// store
@@ -11,7 +11,7 @@ import UserService from '../../service/user-service';
// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import { isEmail } from '../../helpers/validators';
import { isCodiceFiscale, isEmail, isPIVA } from '../../helpers/validators';
// components
import AllUsersTable from './components/AllUsersTable';
@@ -21,12 +21,14 @@ import { Dropdown } from 'primereact/dropdown';
import { Dialog } from 'primereact/dialog';
import { classNames } from 'primereact/utils';
import { Toast } from 'primereact/toast';
import uniqid from '../../helpers/uniqid';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const Users = () => {
const [loading, setLoading] = useState(false);
const [isVisibleEditDialog, setIsVisibleEditDialog] = useState(false);
const [updaterString, setUpdaterString] = useState('');
const [newUserData, setNewUserData] = useState({
firstName: '',
lastName: '',
@@ -34,7 +36,8 @@ const Users = () => {
phoneNumber: '',
password: '',
confPassword: '',
roleId: 0
roleId: 0,
codiceFiscale: ''
});
const [roles, setRoles] = useState([]);
const toast = useRef(null);
@@ -56,18 +59,27 @@ const Users = () => {
phoneNumber: '',
password: '',
confPassword: '',
roleId: 0
roleId: 0,
codiceFiscale: ''
});
}
const saveEditDialog = () => {
const emptyValues = Object.values(newUserData).filter(v => isEmpty(v));
const isConfidi = isConfidiRoleChosen();
const emptyValues = Object.keys(newUserData)
.filter(v => v !== 'phoneNumber')
.filter(v => isConfidi ? v : v !== 'codiceFiscale')
.filter(v => isInvalidField(newUserData, v));
if (isEmpty(emptyValues) && newUserData.password === newUserData.confPassword && !loading) {
setLoading(true);
const body = {
let body = klona({
...newUserData,
hubUuid: APP_HUB_ID
});
if (!isConfidi) {
delete body.codiceFiscale;
}
UserService.createUser(body, createUserCallback, errCreateUserCallback);
@@ -86,6 +98,7 @@ const Users = () => {
});
}
}
setUpdaterString(uniqid());
setLoading(false);
hideEditDialog();
}
@@ -108,23 +121,33 @@ const Users = () => {
setNewUserData(userData);
}
const footerEditDialog = () => {
const footerEditDialog = useCallback(() => {
const isConfidi = isConfidiRoleChosen();
const errorValues = Object.keys(newUserData)
.filter(v => v !== 'phoneNumber')
.filter(v => isConfidi ? v : v !== 'codiceFiscale')
.filter(v => isInvalidField(newUserData, v));
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideEditDialog} outlined/>
<Button
type="button"
disabled={isEmpty(newUserData) || loading}
disabled={!isEmpty(errorValues) || loading}
label={__('Salva', 'gepafin')} onClick={saveEditDialog}/>
</div>
}
}, [newUserData]);
const getRolesCallback = (data) => {
if (data.status === 'SUCCESS') {
const roles = data.data
.filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(o.roleType))
.filter(o => [
'ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER', 'ROLE_CONFIDI'
].includes(o.roleType))
.map(o => ({
name: o.roleName,
value: o.id
value: o.id,
id: o.id,
roleType: o.roleType
}));
setRoles(roles);
}
@@ -136,7 +159,14 @@ const Users = () => {
storeSet.main.unsetAsyncRequest();
}
const isInvalidField = (data, key) => isEmpty(data[key]) || isNil(data[key])
const isInvalidField = (data, key) => key === 'codiceFiscale'
? !isCodiceFiscale(data[key]) && !isPIVA(data[key])
: isEmpty(data[key]) || isNil(data[key]);
const isConfidiRoleChosen = useCallback(() => {
const chosen = head(roles.filter(o => o.id === newUserData.roleId));
return chosen ? chosen.roleType === 'ROLE_CONFIDI' : false;
}, [roles, newUserData])
useEffect(() => {
if (isVisibleEditDialog) {
@@ -151,7 +181,7 @@ const Users = () => {
</div>
<div className="appPage__spacer"></div>
<Toast ref={toast} />
<Toast ref={toast}/>
<div className="appPageSection">
<div className="appPageSection__actions">
@@ -160,7 +190,7 @@ const Users = () => {
label={__('Crea nuovo')} icon="pi pi-plus" iconPos="right"/>
</div>
<AllUsersTable/>
<AllUsersTable updaterString={updaterString}/>
<Dialog
visible={isVisibleEditDialog}
@@ -201,13 +231,11 @@ const Users = () => {
onChange={(e) => onChangeEditItem(e.target.value, 'email')}/>
</div>
<div className="appForm__field">
<label
className={classNames({ 'p-error': isInvalidField(newUserData, 'phoneNumber') })}>
<label>
{__('Telefono', 'gepafin')}
</label>
<InputText value={newUserData.phoneNumber}
keyfilter="int"
invalid={isInvalidField(newUserData, 'phoneNumber')}
onChange={(e) => onChangeEditItem(e.target.value, 'phoneNumber')}/>
</div>
</div>
@@ -244,6 +272,16 @@ const Users = () => {
optionLabel="name"
optionValue="value"/>
</div>
{isConfidiRoleChosen()
? <div className="appForm__field">
<label
className={classNames({ 'p-error': isInvalidField(newUserData, 'codiceFiscale') })}>
{__('Codice Fiscale', 'gepafin')}*
</label>
<InputText value={newUserData.codiceFiscale}
invalid={isInvalidField(newUserData, 'codiceFiscale')}
onChange={(e) => onChangeEditItem(e.target.value, 'codiceFiscale')}/>
</div> : null}
<div className="appPage__spacer"></div>
</Dialog>
</div>

View File

@@ -51,6 +51,9 @@ import SoccorsoEditInstructorManager from './pages/SoccorsoEditInstructorManager
import SoccorsoIstruttorioInstructorManager from './pages/SoccorsoIstruttorioInstructorManager';
import SoccorsoIstruttorioMioInstructorManager from './pages/SoccorsoIstruttorioMioInstructorManager';
import StatsBeneficiary from './pages/StatsBeneficiary';
import DocumentsBeneficiary from './pages/DocumentsBeneficiary';
import LoginConfidi from './pages/LoginConfidi';
import ResetPasswordAdmin from './pages/ResetPasswordAdmin';
const routes = ({ role, chosenCompanyId }) => {
@@ -60,193 +63,233 @@ const routes = ({ role, chosenCompanyId }) => {
<Route path="/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <Dashboard/> : null}
{'ROLE_BENEFICIARY' === role ? <DashboardBeneficiario/> : null}
{'ROLE_CONFIDI' === role ? <DashboardBeneficiario/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <DashboardPreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DashboardInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/bandi" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <Bandi/> : null}
{'ROLE_BENEFICIARY' === role ? <BandiBeneficiario/> : null}
{'ROLE_CONFIDI' === role ? <BandiBeneficiario/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <BandiPreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <BandiPreInstructor/> : null}
</DefaultLayout>}/>
<Route path="/bandi/:id" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoEdit/> : null}
{'ROLE_BENEFICIARY' === role ? <BandoViewBeneficiario/> : null}
{'ROLE_CONFIDI' === role ? <BandoViewBeneficiario/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <BandoViewPreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <BandoViewPreInstructor/> : null}
</DefaultLayout>}/>
<Route path="/bandi/:id/preview" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoView/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/bandi/:id/preview-evaluation" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoView/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/bandi/:id/forms" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoForms/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/bandi/:id/forms/:formId" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoFormsEdit/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/bandi/:id/forms/:formId/preview" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoFormsPreview/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/bandi/:id/flow" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoFlowEdit/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/bandi-osservati" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <BandiPreferredBeneficiario/> : null}
{'ROLE_CONFIDI' === role ? <BandiPreferredBeneficiario/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/domande" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <Domande/> : null}
{'ROLE_BENEFICIARY' === role ? <DomandeBeneficiario/> : null}
{'ROLE_CONFIDI' === role ? <DomandeBeneficiario/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandePreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandeInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/domande/:id/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
{'ROLE_BENEFICIARY' === role ? <SoccorsoEditBeneficiario/> : null}
{'ROLE_CONFIDI' === role ? <SoccorsoEditBeneficiario/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandaEditPreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandaEditPreInstructor/> : null}
</DefaultLayout>}/>
<Route path="/domande/:id/preview" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
{'ROLE_BENEFICIARY' === role ? <BandoApplicationPreview/> : null}
{'ROLE_CONFIDI' === role ? <BandoApplicationPreview/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <BandoApplicationPreview/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <BandoApplicationPreview/> : null}
</DefaultLayout>}/>
<Route path="/domande-archivio" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <DomandeArchive/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandeArchivePreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandeArchive/> : null}
</DefaultLayout>}/>
<Route path="/domande-archivio/:id/preview" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <BandoApplicationPreview/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <BandoApplicationPreview/> : null}
</DefaultLayout>}/>
<Route path="/domande/:id/aggiungi-soccorso" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoAddPreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/domande/:id/soccorso/:amendmentId" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoEditPreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoEditPreInstructor/> : null}
</DefaultLayout>}/>
<Route path="/soccorso-istruttorio/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoIstruttorioPreInstructor/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoIstruttorioInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/mie-domande" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandeMieInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/mie-domande/:id/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandaEditInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/mie-domande/:id/aggiungi-soccorso" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoAddInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/mie-domande/:id/soccorso/:amendmentId" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoEditInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/mio-soccorso-istruttorio/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoIstruttorioMioInstructorManager/> : null}
</DefaultLayout>}/>
<Route path="/imieibandi" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <Applications/> : null}
{'ROLE_CONFIDI' === role ? <Applications/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/imieibandi/:id/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <BandoApplication/> : null}
{'ROLE_CONFIDI' === role ? <BandoApplication/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/profilo" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <Profile/> : null}
{'ROLE_BENEFICIARY' === role ? <ProfileBeneficiario/> : null}
{'ROLE_CONFIDI' === role ? <ProfileBeneficiario/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <Profile/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <Profile/> : null}
</DefaultLayout>}/>
<Route path="/profilo-aziendale" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role && chosenCompanyId > 0 ? <ProfileCompany/> : <PageNotFound/>}
{'ROLE_CONFIDI' === role && chosenCompanyId > 0 ? <ProfileCompany/> : <PageNotFound/>}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/agguingi-azienda" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <AddCompany/> : null}
{'ROLE_CONFIDI' === role ? <AddCompany/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/utenti" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <Users/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/utenti/:id" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <UserActivity/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_CONFIDI' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/stats" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <StatsBeneficiary/> : null}
{'ROLE_CONFIDI' === role ? <StatsBeneficiary/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
<Route path="/documenti" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <DocumentsBeneficiary/> : null}
{'ROLE_CONFIDI' === role ? <DocumentsBeneficiary/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
</DefaultLayout>}/>
</Route>
<Route exact path="/reset-password" element={<ResetPassword/>}/>
<Route exact path="/reset-password-admin" element={<ResetPasswordAdmin/>}/>
<Route exact path="/login" element={<Login/>}/>
<Route exact path="/loginAdmin" element={<LoginAdmin/>}/>
<Route exact path="/loginadmin" element={<LoginAdmin/>}/>
<Route exact path="/confidi" element={<LoginConfidi/>}/>
<Route exact path="/registration" element={<Registration/>}/>
<Route path="*" element={<PageNotFound/>}/>
</Routes>)

View File

@@ -15,4 +15,8 @@ export default class AssignedApplicationService {
static updateStatusAssignedApplication = (id, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/assignedApplication/${id}/status`, {}, callback, errCallback, queryParams);
};
static assignApplicationPaginated = (body, callback, errCallback, queryParams) => {
NetworkService.post(`${API_BASE_URL}/assignedApplication/pagination`, body, callback, errCallback, queryParams);
};
}

View File

@@ -0,0 +1,24 @@
import { NetworkService } from './network-service';
const API_BASE_URL = process.env.REACT_APP_API_EXECUTION_ADDRESS;
export default class CompanyDocumentsService {
static getCompanyDocuments = (companyId, callback, errCallback, queryParams) => {
NetworkService.get(`${API_BASE_URL}/companyDocument/company/${companyId}`, callback, errCallback, queryParams);
};
static uploadCompanyDocument = (id, body, callback, errCallback, queryParams) => {
NetworkService.postMultiPart(`${API_BASE_URL}/companyDocument/company/${id}/upload`, body, callback, errCallback, queryParams);
};
static attachCompanyDocumentToAppl = (id, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/companyDocument/${id}/document/upload`, {}, callback, errCallback, queryParams);
};
static deleteCompanyDocument = (id, callback, errCallback) => {
NetworkService.delete(`${API_BASE_URL}/companyDocument`, {}, callback, errCallback, [
['id', id]
]);
};
}

View File

@@ -0,0 +1,10 @@
import { NetworkService } from './network-service';
const API_BASE_URL = process.env.REACT_APP_API_EXECUTION_ADDRESS;
export default class DocumentCategoryService {
static getCategories = (callback, errCallback) => {
NetworkService.get(`${API_BASE_URL}/documentCategory`, callback, errCallback);
};
}

View File

@@ -9,7 +9,7 @@ export class NetworkService {
} else if (status === 403) {
storeSet.main.token('');
const { pathname } = window.location;
if (!['/login', '/loginadmin', '/reset-password', '/registration'].includes(pathname)) {
if (!['/login', '/registration', '/loginadmin', '/reset-password-admin', '/confidi', '/reset-password'].includes(pathname)) {
window.location.replace('/login');
}
}

View File

@@ -11,6 +11,7 @@ const initialStore = {
users: [],
// bando form
formInitialData: {},
documentCategories: [],
// form builder
formId: 0,
formLabel: '',

View File

@@ -483,5 +483,29 @@ export const elementItems = [
validators: {
isRequired: false
}
},
{
id: 23,
sortOrder: 23,
name: 'fileselect',
label: 'Seleziona File',
description: "Per selezionare di documenti o immagini",
settings: [
{
name: "label",
value: "Seleziona File"
},
{
name: "documentCategories",
value: []
},
{
name: "isDelegation",
value: false
}
],
validators: {
isRequired: false
}
}
]

View File

@@ -1,5 +1,6 @@
/* data table related */
import { __ } from '@wordpress/i18n';
import { FilterMatchMode } from 'primereact/api';
const currentPageReportTemplate = '';
@@ -7,10 +8,43 @@ const emptyMessage = __('Nessun dato disponibile', 'gepafin');
const selectOneLabel = __('Seleziona', 'gepafin');
const textFilterOptions = [
//{ label: 'Inizia con', value: FilterMatchMode.STARTS_WITH },
{ label: 'Contiene', value: FilterMatchMode.CONTAINS },
//{ label: 'Non contiene', value: FilterMatchMode.NOT_CONTAINS },
//{ label: 'Finisce con', value: FilterMatchMode.ENDS_WITH },
{ label: 'Uguale a', value: FilterMatchMode.EQUALS },
//{ label: 'Diverso da', value: FilterMatchMode.NOT_EQUALS }
];
const statusFilterOptions = [
{ label: 'Uguale a', value: FilterMatchMode.EQUALS }
];
const numericFilterOptions = [
{ label: 'Uguale a', value: FilterMatchMode.EQUALS },
{ label: 'Diverso da', value: FilterMatchMode.NOT_EQUALS },
{ label: 'Maggiore di', value: FilterMatchMode.GREATER_THAN },
{ label: 'Maggiore o uguale a', value: FilterMatchMode.GREATER_THAN_OR_EQUAL_TO },
{ label: 'Minore di', value: FilterMatchMode.LESS_THAN },
{ label: 'Minore o uguale a', value: FilterMatchMode.LESS_THAN_OR_EQUAL_TO }
];
const dateFilterOptions = [
{ label: 'Data uguale a', value: FilterMatchMode.DATE_IS },
{ label: 'Data diversa da', value: FilterMatchMode.DATE_IS_NOT },
{ label: 'Data prima di', value: FilterMatchMode.DATE_BEFORE },
{ label: 'Data dopo', value: FilterMatchMode.DATE_AFTER }
];
const translationStrings = {
currentPageReportTemplate,
emptyMessage,
selectOneLabel
selectOneLabel,
textFilterOptions,
statusFilterOptions,
numericFilterOptions,
dateFilterOptions
}
export default translationStrings;