- merged develop;

This commit is contained in:
Vitalii Kiiko
2024-12-11 11:37:36 +01:00
34 changed files with 917 additions and 456 deletions

3
.env
View File

@@ -4,4 +4,5 @@ REACT_APP_API_ADDRESS=https://api-dev-gepafin.memento.credit
REACT_APP_LOGO_FILENAME=gepafin-logo.svg REACT_APP_LOGO_FILENAME=gepafin-logo.svg
REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico
REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs
REACT_APP_EVALUATION_FLOW_ID=1 REACT_APP_EVALUATION_FLOW_ID=1
REACT_APP_LOCAL_DEVELOPMENT=1

View File

@@ -8,7 +8,7 @@
"@date-fns/tz": "1.2.0", "@date-fns/tz": "1.2.0",
"@emailjs/browser": "4.4.1", "@emailjs/browser": "4.4.1",
"@emotion/styled": "11.13.5", "@emotion/styled": "11.13.5",
"@number-flow/react": "0.4.1", "@number-flow/react": "0.4.2",
"@sentry/browser": "^8.41.0", "@sentry/browser": "^8.41.0",
"@tanstack/react-table": "^8.20.5", "@tanstack/react-table": "^8.20.5",
"@wordpress/i18n": "5.13.0", "@wordpress/i18n": "5.13.0",

View File

@@ -342,6 +342,10 @@
.appPageSection__row { .appPageSection__row {
display: flex; display: flex;
gap: 1rem; gap: 1rem;
&.autoFlow {
flex-wrap: wrap;
}
} }
.appPageSection__pMeta { .appPageSection__pMeta {

View File

@@ -12,6 +12,10 @@
.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link, .p-column-filter-add-button, .p-column-filter-remove-button) span { .p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link, .p-column-filter-add-button, .p-column-filter-remove-button) span {
color: var(--menuitem-active-color); color: var(--menuitem-active-color);
} }
.p-button.p-button-success.p-button-icon-only[disabled],
.p-button.p-button-danger.p-button-icon-only[disabled] {
filter: unset;
}
.p-column-filter-remove-button { .p-column-filter-remove-button {
span { span {
margin: 0 5px; margin: 0 5px;

View File

@@ -0,0 +1,31 @@
import React, { Component } from 'react';
import logMsgWithSentry from '../../helpers/logMsgWithSentry';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {
builderError: false
};
}
static getDerivedStateFromError(error) {
try {
logMsgWithSentry('', 0, {}, error);
} catch (err) {
console.log(err);
}
return { builderError: true };
}
render() {
if (this.state.builderError) {
return <div>Error</div>;
}
return this.props.children;
}
}
export default ErrorBoundary;

View File

@@ -3,6 +3,7 @@ import { Navigate, Outlet } from 'react-router-dom';
// tools // tools
import AuthenticationService from '../../service/authentication-service'; import AuthenticationService from '../../service/authentication-service';
import ErrorBoundary from '../ErrorBoundary';
const ProtectedRoute = () => { const ProtectedRoute = () => {
@@ -22,7 +23,7 @@ const ProtectedRoute = () => {
return (<Navigate to={'/'} replace/>); return (<Navigate to={'/'} replace/>);
}*/ }*/
return <Outlet/>; return <ErrorBoundary><Outlet/></ErrorBoundary>;
} }
export default ProtectedRoute; export default ProtectedRoute;

View File

@@ -44,4 +44,111 @@ export const dynamicDataOptions = {
], ],
textinput: dynamicDataForTextinput, textinput: dynamicDataForTextinput,
textarea: dynamicDataForTextinput textarea: dynamicDataForTextinput
} }
export const protocolType = [
{
'id': 1,
'name': 'PROTOCOLLO IN ENTRATA'
},
{
'id': 2,
'name': 'PROTOCOLLO IN USCITA'
},
{
'id': 3,
'name': 'DOCUMENTO INTERNO'
},
{
'id': 1003,
'name': 'PROTOCOLLO INTERNO '
}
];
export const classificationType = [
{
'idClassificazione': 101,
'name': 'BILANCIO',
'idTipoprotocollo': 1
},
{
'idClassificazione': 102,
'name': 'DICHHIARAZIONE DEI REDDITI',
'idTipoprotocollo': 1
},
{
'idClassificazione': 103,
'name': 'SITUAZIONE CONTABILE',
'idTipoprotocollo': 1
},
{
'idClassificazione': 104,
'name': 'PROSPETTO CONTO ECONOMICO',
'idTipoprotocollo': 1
},
{
'idClassificazione': 105,
'name': 'CENTRALE DEI RISCHI',
'idTipoprotocollo': 1
},
{
'idClassificazione': 106,
'name': 'RELAZIONE AZIENDALE ILLUSTRATIVA (MOD R1C, R1I, R1R, R1R A SECONDO DEI ',
'idTipoprotocollo': 1
},
{
'idClassificazione': 107,
'name': 'DOCUMENTO IDENTITA\'',
'idTipoprotocollo': 1
},
{
'idClassificazione': 108,
'name': 'MODELLO SP1',
'idTipoprotocollo': 1
},
{
'idClassificazione': 109,
'name': 'PRIVACY',
'idTipoprotocollo': 1
},
{
'idClassificazione': 110,
'name': 'DOCUMENTAZIONE CHE ATTESTA POSSIBILITA\' DI RILASCIARE GAA FAVORE',
'idTipoprotocollo': 1
},
{
'idClassificazione': 111,
'name': 'MODELLO AR1 D.LG 231/2007',
'idTipoprotocollo': 1
},
{
'idClassificazione': 112,
'name': 'DOCUMENTO IDENTITA\' FIRMATORIO DICHHIARAZIONE SOSTITUTIVA',
'idTipoprotocollo': 1
},
{
'idClassificazione': 113,
'name': 'PRIVACY FIRMATARIO DICHHIARAZIONE SOSTITUTIVA',
'idTipoprotocollo': 1
},
{
'idClassificazione': 114,
'name': 'NULLAOSTA ANTIMAFIA',
'idTipoprotocollo': 1
},
{
'idClassificazione': 201,
'name': 'LETTERA ESITO DELIBERA',
'idTipoprotocollo': 2
},
{
'idClassificazione': 202,
'name': 'LETTERA DI GARANZIA',
'idTipoprotocollo': 1
},
{
'idClassificazione': 203,
'name': 'GENERICO',
'idTipoprotocollo': 3
}
];

View File

@@ -4,7 +4,6 @@
* @return {string} * @return {string}
*/ */
const formatDateString = (date) => { const formatDateString = (date) => {
console.log('date', date);
const year = date.getFullYear(); const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0');

View File

@@ -20,6 +20,15 @@ const getBandoLabel = (status) => {
case 'READY': case 'READY':
return __('Pronto', 'gepafin'); return __('Pronto', 'gepafin');
case 'NDG':
return __('NDG', 'gepafin');
case 'APPOINTMENT':
return __('Appuntamento', 'gepafin');
case 'ADMISSIBLE':
return __('Ammisibile', 'gepafin');
case 'SOCCORSO': case 'SOCCORSO':
return __('Soccorso', 'gepafin'); return __('Soccorso', 'gepafin');

View File

@@ -18,6 +18,15 @@ const getBandoSeverity = (status) => {
case 'READY': case 'READY':
return 'info'; return 'info';
case 'NDG':
return 'info';
case 'APPOINTMENT':
return 'info';
case 'ADMISSIBLE':
return 'info';
case 'SOCCORSO': case 'SOCCORSO':
return 'warning'; return 'warning';

View File

@@ -0,0 +1,31 @@
import * as Sentry from '@sentry/browser';
const LOCAL_DEVELOPMENT = process.env.REACT_APP_LOCAL_DEVELOPMENT;
const logMsgWithSentry = (endpoint = '', status = 0, resp = {}, error = null) => {
try {
if (LOCAL_DEVELOPMENT !== '1') {
Sentry.init({
dsn: 'https://e7b2134f7d816f663bb83e51b106a694@o4508381921738752.ingest.de.sentry.io/4508381935501392',
environment: process.env.NODE_ENV || 'development'
});
if (!error) {
const newError = new Error(`Status ${status}`);
Sentry.captureException(`Error in endpoint: ${endpoint}`, {
level: 'error',
extra: {
originalError: newError,
details: resp
}
});
} else {
Sentry.captureException(error);
}
}
} catch (err) {
console.log(err);
}
}
export default logMsgWithSentry;

View File

@@ -4,6 +4,7 @@ import CodiceFiscale from 'codice-fiscale-js';
export const isPIVA = (v) => { export const isPIVA = (v) => {
const regexp = new RegExp(/^[0-9]{11}$/); const regexp = new RegExp(/^[0-9]{11}$/);
//console.log('isPIVA', !isEmpty(match(regexp, String(v))))
return !isEmpty(match(regexp, String(v))); return !isEmpty(match(regexp, String(v)));
} }
@@ -11,6 +12,7 @@ export const isPIVA = (v) => {
export const isCodiceFiscale = (v) => { export const isCodiceFiscale = (v) => {
//const regexp = new RegExp(/^(?:[A-Z][AEIOU][AEIOUX]|[AEIOU]X{2}|[B-DF-HJ-NP-TV-Z]{2}[A-Z]){2}(?:[\dLMNP-V]{2}(?:[A-EHLMPR-T](?:[04LQ][1-9MNP-V]|[15MR][\dLMNP-V]|[26NS][0-8LMNP-U])|[DHPS][37PT][0L]|[ACELMRT][37PT][01LM]|[AC-EHLMPR-T][26NS][9V])|(?:[02468LNQSU][048LQU]|[13579MPRTV][26NS])B[26NS][9V])(?:[A-MZ][1-9MNP-V][\dLMNP-V]{2}|[A-M][0L](?:[1-9MNP-V][\dLMNP-V]|[0L][1-9MNP-V]))[A-Z]$/, 'i') //const regexp = new RegExp(/^(?:[A-Z][AEIOU][AEIOUX]|[AEIOU]X{2}|[B-DF-HJ-NP-TV-Z]{2}[A-Z]){2}(?:[\dLMNP-V]{2}(?:[A-EHLMPR-T](?:[04LQ][1-9MNP-V]|[15MR][\dLMNP-V]|[26NS][0-8LMNP-U])|[DHPS][37PT][0L]|[ACELMRT][37PT][01LM]|[AC-EHLMPR-T][26NS][9V])|(?:[02468LNQSU][048LQU]|[13579MPRTV][26NS])B[26NS][9V])(?:[A-MZ][1-9MNP-V][\dLMNP-V]{2}|[A-M][0L](?:[1-9MNP-V][\dLMNP-V]|[0L][1-9MNP-V]))[A-Z]$/, 'i')
//return !isEmpty(match(regexp, v)); //return !isEmpty(match(regexp, v));
//console.log('isCodiceFiscale', CodiceFiscale.check(v))
return CodiceFiscale.check(v); return CodiceFiscale.check(v);
} }

View File

@@ -19,9 +19,11 @@ import BlockingOverlay from '../../components/BlockingOverlay';
import CompanyService from '../../service/company-service'; import CompanyService from '../../service/company-service';
// tools // tools
import { isPIVA, isEmail, isEmailPEC } from '../../helpers/validators'; import { isPIVA, isEmail, isEmailPEC, isCodiceFiscale } from '../../helpers/validators';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
//const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
const AddCompany = () => { const AddCompany = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const isAsyncRequest = useStore().main.isAsyncRequest(); const isAsyncRequest = useStore().main.isAsyncRequest();
@@ -33,12 +35,14 @@ const AddCompany = () => {
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
setValue, setValue,
watch watch,
trigger
} = useForm({ } = useForm({
defaultValues: {}, defaultValues: {},
mode: 'onChange' mode: 'onChange'
}); });
const isPiva = watch('vatNumber'); const isPiva = watch('vatNumber');
//const isPiva = watch('vatNumber');
const setEmptyValues = () => { const setEmptyValues = () => {
const formData = { const formData = {
@@ -116,7 +120,7 @@ const AddCompany = () => {
pec, pec,
email: pec, email: pec,
city: comune, city: comune,
codiceFiscale: cf, codiceFiscale: cf ? cf : piva,
address: indirizzo, address: indirizzo,
vatNumber: piva, vatNumber: piva,
companyName: denominazione companyName: denominazione
@@ -127,6 +131,7 @@ const AddCompany = () => {
} else { } else {
setEmptyValues(); setEmptyValues();
} }
trigger();
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
} }
@@ -136,6 +141,11 @@ const AddCompany = () => {
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
} }
/*const shouldDisableFiscalCode = () => {
const formData = getValues();
return !formData.type || formData.type && formData.type === 'giuridica';
}*/
useEffect(() => { useEffect(() => {
setInputPiva(isPiva); setInputPiva(isPiva);
}, [isPiva]); }, [isPiva]);
@@ -174,6 +184,23 @@ const AddCompany = () => {
/> />
</div> </div>
{/*{APP_EVALUATION_FLOW_ID === '2'
? <div className="appForm__cols">
<FormField
type="radio"
fieldName="type"
label={__('Type', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
defaultValue="giuridica"
options={[
{ name: 'giuridica', label: 'Giuridica' },
{ name: 'fisica', label: 'Fisica' },
]}
/>
</div> : null}*/}
<div className="appForm__cols"> <div className="appForm__cols">
<FormField <FormField
type="textinput" type="textinput"
@@ -181,18 +208,46 @@ const AddCompany = () => {
label={__('P.IVA', 'gepafin')} label={__('P.IVA', 'gepafin')}
control={control} control={control}
errors={errors} errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }} config={{
required: __('È obbligatorio', 'gepafin'),
validate: {
isPIVA
}
}}
/> />
<FormField <FormField
type="textinput" type="textinput"
disabled={true}
fieldName="codiceFiscale" fieldName="codiceFiscale"
label={__('Codice fiscale', 'gepafin')} label={__('Codice fiscale', 'gepafin')}
control={control} control={control}
errors={errors} errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }} config={{
required: __('È obbligatorio', 'gepafin'),
validate: {
validCF: (value) => isCodiceFiscale(value) || isPIVA(value)
}
}}
/> />
{/*{APP_EVALUATION_FLOW_ID === '1'
? <FormField
type="textinput"
disabled
fieldName="codiceFiscale"
label={__('Codice fiscale', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>
: <FormField
type="textinput"
disabled={shouldDisableFiscalCode()}
fieldName="codiceFiscale"
label={__('Codice fiscale', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>}*/}
</div> </div>
<div className="appForm__cols"> <div className="appForm__cols">

View File

@@ -5,6 +5,7 @@ import { useNavigate } from 'react-router-dom';
// components // components
import MyLatestSubmissionsTable from '../DashboardBeneficiario/components/MyLatestSubmissionsTable'; import MyLatestSubmissionsTable from '../DashboardBeneficiario/components/MyLatestSubmissionsTable';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import ErrorBoundary from '../../components/ErrorBoundary';
const Applications = () => { const Applications = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -22,7 +23,7 @@ const Applications = () => {
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>
<div className="appPageSection"> <div className="appPageSection">
<MyLatestSubmissionsTable/> <ErrorBoundary><MyLatestSubmissionsTable/></ErrorBoundary>
</div> </div>
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>

View File

@@ -8,6 +8,7 @@ import { useStore } from '../../store';
// components // components
import AllBandiAccordion from './components/AllBandiAccordion'; import AllBandiAccordion from './components/AllBandiAccordion';
import ErrorBoundary from '../../components/ErrorBoundary';
const BandiBeneficiario = () => { const BandiBeneficiario = () => {
const chosenCompanyId = useStore().main.chosenCompanyId(); const chosenCompanyId = useStore().main.chosenCompanyId();
@@ -34,7 +35,7 @@ const BandiBeneficiario = () => {
</> : null} </> : null}
<div className="appPageSection"> <div className="appPageSection">
<AllBandiAccordion/> <ErrorBoundary><AllBandiAccordion/></ErrorBoundary>
</div> </div>
</div> </div>
) )

View File

@@ -14,6 +14,7 @@ import DashboardService from '../../service/dashboard-service';
import LatestBandiTable from './components/LatestBandiTable'; import LatestBandiTable from './components/LatestBandiTable';
import MyLatestSubmissionsTable from './components/MyLatestSubmissionsTable'; import MyLatestSubmissionsTable from './components/MyLatestSubmissionsTable';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import ErrorBoundary from '../../components/ErrorBoundary';
const DashboardBeneficiario = () => { const DashboardBeneficiario = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -85,7 +86,7 @@ const DashboardBeneficiario = () => {
<div className="appPageSection"> <div className="appPageSection">
<h2>{__('Domande in lavorazione', 'gepafin')}</h2> <h2>{__('Domande in lavorazione', 'gepafin')}</h2>
<MyLatestSubmissionsTable/> <ErrorBoundary><MyLatestSubmissionsTable/></ErrorBoundary>
</div> </div>
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>
@@ -105,7 +106,7 @@ const DashboardBeneficiario = () => {
<div className="appPageSection"> <div className="appPageSection">
<h2>{__('Bandi disponibili', 'gepafin')}</h2> <h2>{__('Bandi disponibili', 'gepafin')}</h2>
<LatestBandiTable/> <ErrorBoundary><LatestBandiTable/></ErrorBoundary>
</div> </div>
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>

View File

@@ -54,7 +54,7 @@ const PreInstructorDomandeTable = () => {
const getFormattedData = (data) => { const getFormattedData = (data) => {
return data.map((d) => { return data.map((d) => {
d.callEndDate = is(String, d.callEndDate) ? new Date(d.callEndDate) : (d.callEndDate ? d.callEndDate : ''); 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 : ''); d.submissionDate = is(String, d.submissionDate) ? new Date(d.submissionDate) : (d.submissionDate ? d.submissionDate : '');
return d; return d;
}); });
@@ -87,7 +87,7 @@ const PreInstructorDomandeTable = () => {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}, },
callEndDate : { evaluationEndDate: {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
} }
@@ -107,7 +107,7 @@ const PreInstructorDomandeTable = () => {
}; };
const dateEndBodyTemplate = (rowData) => { const dateEndBodyTemplate = (rowData) => {
return formatDate(rowData.callEndDate); return formatDate(rowData.evaluationEndDate);
}; };
const dateFilterTemplate = (options) => { const dateFilterTemplate = (options) => {
@@ -144,6 +144,15 @@ const PreInstructorDomandeTable = () => {
<Column field="applicationId" header={__('ID domanda', 'gepafin')} <Column field="applicationId" header={__('ID domanda', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')} sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/> style={{ minWidth: '6rem' }}/>
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="ndg" header={__('NDG', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="appointmentId" header={__('ID appuntamento', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="callName" header={__('Bando', 'gepafin')} <Column field="callName" header={__('Bando', 'gepafin')}
filter sortable filter sortable
filterPlaceholder={__('Cerca', 'gepafin')} filterPlaceholder={__('Cerca', 'gepafin')}
@@ -155,7 +164,7 @@ const PreInstructorDomandeTable = () => {
<Column header={__('Data ricezione', 'gepafin')} filterField="submissionDate" dataType="date" <Column header={__('Data ricezione', 'gepafin')} filterField="submissionDate" dataType="date"
style={{ minWidth: '8rem' }} style={{ minWidth: '8rem' }}
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')} filterField="callEndDate" dataType="date" <Column header={__('Scadenza', 'gepafin')} filterField="evaluationEndDate" dataType="date"
style={{ minWidth: '8rem' }} style={{ minWidth: '8rem' }}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="status" header={__('Stato', 'gepafin')} <Column field="status" header={__('Stato', 'gepafin')}

View File

@@ -207,35 +207,39 @@ const DomandaBeneficiario = () => {
<div className="appPage__content"> <div className="appPage__content">
{data.id {data.id
? <div className="appPageSection__withBorder columns"> ? <div className="appPageSection__withBorder columns">
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('ID domanda', 'gepafin')}</span> <span>{__('ID domanda', 'gepafin')}</span>
<span>{data.applicationId}</span> <span>{data.applicationId}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Bando', 'gepafin')}</span> <span>{__('Bando', 'gepafin')}</span>
<span>{data.callName}</span> <span>{data.callName}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Beneficiario', 'gepafin')}</span> <span>{__('Beneficiario', 'gepafin')}</span>
<span>{data.beneficiaryName}</span> <span>{data.beneficiaryName}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Inizio', 'gepafin')}</span> <span>{__('Azienda', 'gepafin')}</span>
<span>{getDateFromISOstring(data.startDate)}</span> <span></span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Scadenza', 'gepafin')}</span> <span>{__('Inizio', 'gepafin')}</span>
<span>{getDateFromISOstring(data.expirationDate)}</span> <span>{getDateFromISOstring(data.startDate)}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Stato', 'gepafin')}</span> <span>{__('Scadenza', 'gepafin')}</span>
<span>{getBandoLabel(data.status)}</span> <span>{getDateFromISOstring(data.expirationDate)}</span>
</p> </p>
</div> : null} <p className="appPageSection__pMeta">
<span>{__('Stato', 'gepafin')}</span>
<span>{getBandoLabel(data.status)}</span>
</p>
</div> : null}
{dataAppl.id {dataAppl.id
? <div className="appPageSection__withBorder columns"> ? <div className="appPageSection__withBorder columns">
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('ID domanda', 'gepafin')}</span> <span>{__('ID domanda', 'gepafin')}</span>
<span>{dataAppl.id}</span> <span>{dataAppl.id}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
@@ -289,6 +293,7 @@ const DomandaBeneficiario = () => {
errors={errors} errors={errors}
defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []} defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []}
accept={[]} accept={[]}
source="AMENDMENT"
sourceId={data.applicationId} sourceId={data.applicationId}
multiple={true} multiple={true}
/> />

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { isEmpty } from 'ramda'; import { isEmpty } from 'ramda';
import { wrap } from 'object-path-immutable'; import { wrap } from 'object-path-immutable';
@@ -9,24 +9,37 @@ import { Dialog } from 'primereact/dialog';
import { InputTextarea } from 'primereact/inputtextarea'; import { InputTextarea } from 'primereact/inputtextarea';
import { Dropdown } from 'primereact/dropdown'; import { Dropdown } from 'primereact/dropdown';
import { classNames } from 'primereact/utils'; import { classNames } from 'primereact/utils';
import { InputSwitch } from 'primereact/inputswitch';
import { InputText } from 'primereact/inputtext';
const ArchiveDocument = ({ ndg = '', fileId = 0 }) => { import { classificationType, protocolType } from '../../../../configData';
import AppointmentService from '../../../../service/appointment-service';
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
import { storeSet } from '../../../../store';
import { Toast } from 'primereact/toast';
const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0 }) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [isVisibleDialog, setIsVisibleDialog] = useState(false); const [isVisibleDialog, setIsVisibleDialog] = useState(false);
const [modalData, setModalData] = useState({}); const [modalData, setModalData] = useState({});
const [types, setTypes] = useState([]);
const [categories, setCategories] = useState([]); const [categories, setCategories] = useState([]);
const toast = useRef(null);
const openArchivationModal = () => { const openArchivationModal = () => {
setIsVisibleDialog(true); setIsVisibleDialog(true);
setModalData({ setModalData({
description: '', descrizione: '',
categoryId: 0, idTipoProtocollo: 0,
idClassificazione: 0,
flagDaFirmare: false,
email: '',
fileId fileId
}); });
} }
const headerDialog = () => { const headerDialog = () => {
return <span>{__('Archive document', 'gepafin')}</span>; return <span>{__('Archiviazione del documento', 'gepafin')}</span>;
} }
const hideDialog = () => { const hideDialog = () => {
@@ -50,57 +63,141 @@ const ArchiveDocument = ({ ndg = '', fileId = 0 }) => {
} }
const submitData = () => { const submitData = () => {
console.log('submitData', modalData); if (
//setLoading(true); modalData.idTipoProtocollo !== 0 && modalData.idClassificazione !== 0
&& !isEmpty(modalData.descrizione) && !isEmpty(modalData.email)
) {
setLoading(true);
const submitData = {
'input': {
'idTipoProtocollo': modalData.idTipoProtocollo,
'idClassificazione': modalData.idClassificazione,
'flagDaFirmare': modalData.flagDaFirmare,
'descrizione': modalData.descrizione,
'attributes': {
'ndg': ndg,
'email': modalData.email
}
}
}
AppointmentService.archiveDocument(applicationId, fileId, submitData, submitCallback, errSubmitCallback)
}
}
const submitCallback = (data) => {
if (data.status === 'SUCCESS') {
console.log(data.data);
}
setLoading(false);
}
const errSubmitCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
setLoading(false);
} }
useEffect(() => { useEffect(() => {
setCategories([ const newModalData = {
{value: 1, label: 'Type 1'}, ...modalData,
{value: 2, label: 'Type 2'}, idClassificazione: 0
]) };
setModalData(newModalData);
setCategories(classificationType
.filter(o => o.idTipoprotocollo === modalData.idTipoProtocollo)
.map(o => ({ value: o.idClassificazione, label: o.name })));
}, [modalData.idTipoProtocollo])
useEffect(() => {
setTypes(protocolType.map(o => ({ value: o.id, label: o.name })));
}, []); }, []);
return ( return (!isEmpty(ndg)
<> ? <>
{!isEmpty(ndg) <Toast ref={toast}/>
? <Button icon="pi pi-file-export" <Button icon="pi pi-file-export"
rounded rounded
onClick={openArchivationModal} onClick={openArchivationModal}
outlined outlined
severity="info" severity="info"
aria-label={__('Mostra', 'gepafin')}/> aria-label={__('Mostra', 'gepafin')}/>
: null} <Dialog
<Dialog visible={isVisibleDialog}
visible={isVisibleDialog} modal
modal header={headerDialog}
header={headerDialog} footer={footerDialog}
footer={footerDialog} style={{ maxWidth: '600px', width: '100%' }}
style={{ maxWidth: '600px', width: '100%' }} onHide={hideDialog}>
onHide={hideDialog}> <div className="appForm__field">
<div className="appForm__field"> <label
<label className={classNames({ 'p-error': !modalData.categoryId || modalData.categoryId === 0 })}> className={classNames({ 'p-error': !modalData.idTipoProtocollo || modalData.idTipoProtocollo === 0 })}>
{__('Classificazione', 'gepafin')}* {__('Tipo di protocollo', 'gepafin')}*
</label> </label>
<Dropdown <Dropdown
value={modalData.categoryId} value={modalData.idTipoProtocollo}
invalid={!modalData.categoryId || modalData.categoryId === 0} invalid={!modalData.idTipoProtocollo || modalData.idTipoProtocollo === 0}
onChange={(e) => setValue('categoryId', e.value)} onChange={(e) => setValue('idTipoProtocollo', e.value)}
options={categories}/> options={types}/>
</div> </div>
<div className="appForm__field"> <div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(modalData.description) })}> <label
{__('Descrizione', 'gepafin')} className={classNames({ 'p-error': !modalData.idClassificazione || modalData.idClassificazione === 0 })}>
</label> {__('Classificazione', 'gepafin')}*
<InputTextarea </label>
value={modalData.description} <Dropdown
invalid={isEmpty(modalData.description)} value={modalData.idClassificazione}
onChange={(e) => setValue('description', e.target.value)} invalid={!modalData.idClassificazione || modalData.idClassificazione === 0}
rows={3} onChange={(e) => setValue('idClassificazione', e.value)}
cols={30}/> options={categories}/>
</div> </div>
</Dialog> <div className="appForm__field">
</> <label>
{__('Da firmare?', 'gepafin')}
</label>
<InputSwitch
checked={modalData.flagDaFirmare}
onChange={(e) => setValue('flagDaFirmare', e.value)}/>
</div>
<div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(modalData.descrizione) })}>
{__('Descrizione', 'gepafin')}*
</label>
<InputTextarea
value={modalData.descrizione}
invalid={isEmpty(modalData.descrizione)}
onChange={(e) => setValue('descrizione', e.target.value)}
rows={3}
cols={30}/>
</div>
<div className="appForm__field">
<label>
{__('NDG', 'gepafin')}*
</label>
<InputText
value={ndg}
disabled
onChange={() => {
}}/>
</div>
<div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(modalData.email) })}>
{__('Email', 'gepafin')}*
</label>
<InputText
value={modalData.email}
keyfilter="email"
invalid={isEmpty(modalData.email)}
onChange={(e) => setValue('email', e.target.value)}/>
</div>
</Dialog>
</> : null
) )
} }

View File

@@ -0,0 +1,49 @@
import React, { useState } from 'react';
import { __ } from '@wordpress/i18n';
// tools
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
// api
import ApplicationService from '../../../../service/application-service';
// components
import { Button } from 'primereact/button';
const DownloadApplicationArchive = ({ applicationId = 0 }) => {
const [loading, setLoading] = useState(false);
const onClickDownload = () => {
setLoading(true);
ApplicationService.downloadCompleteZip(applicationId, getCompleteZipCallback, errCompleteZipCallback);
}
const getCompleteZipCallback = (data) => {
const file = new Blob([data], { type: 'application/zip' });
const url = window.URL.createObjectURL(file);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `application-${applicationId}.zip`);
document.body.appendChild(link);
link.click();
link.remove();
setLoading(false);
}
const errCompleteZipCallback = (data) => {
set404FromErrorResponse(data);
setLoading(false);
}
return (applicationId && applicationId !== 0
? <Button
type="button"
disabled={loading}
onClick={onClickDownload}
label={__('Scarica ZIP', 'gepafin')}
icon="pi pi-download"
iconPos="right"/> : null
)
}
export default DownloadApplicationArchive;

View File

@@ -0,0 +1,51 @@
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty } from 'ramda';
// api
import CompanyService from '../../../../service/company-service';
// components
import { Button } from 'primereact/button';
const DownloadCompanyDelegation = ({ applicationId = 0 }) => {
const [loading, setLoading] = useState(false);
const [delega, setDelega] = useState({});
const onClickDownload = () => {
if (delega.filePath) {
window.open(encodeURI(delega.filePath), '_blank').focus()
}
}
const getDellegaCallback = (data) => {
if (data.data) {
setDelega(data.data);
}
setLoading(false);
}
const errDellegaCallback = () => {
setDelega([]);
setLoading(false);
}
useEffect(() => {
setLoading(true);
CompanyService.getCompanyDelega(getDellegaCallback, errDellegaCallback, [
['applicationId', applicationId]
]);
}, [])
return (applicationId && applicationId !== 0
? <Button
type="button"
disabled={loading || isEmpty(delega)}
onClick={onClickDownload}
label={__('Scarica la delega', 'gepafin')}
icon="pi pi-download"
iconPos="right"/> : null
)
}
export default DownloadCompanyDelegation;

View File

@@ -0,0 +1,45 @@
import React, { useState } from 'react';
import { __ } from '@wordpress/i18n';
// api
import ApplicationService from '../../../../service/application-service';
// components
import { Button } from 'primereact/button';
const DownloadSignedApplication = ({ applicationId = 0 }) => {
const [loading, setLoading] = useState(false);
const [, setDocument] = useState({});
const onClickDownload = () => {
setLoading(true);
ApplicationService.getApplicationSignedPdf(applicationId, getSignedPdfCallback, errSignedPdfCallbacks);
}
const getSignedPdfCallback = (data) => {
if (data.data) {
setDocument([data.data]);
if (data.data.filePath) {
window.open(encodeURI(data.data.filePath), '_blank').focus()
}
}
setLoading(false);
}
const errSignedPdfCallbacks = () => {
setDocument([]);
setLoading(false);
}
return (applicationId && applicationId !== 0
? <Button
type="button"
disabled={loading}
onClick={onClickDownload}
label={__('Scarica PDF firmato', 'gepafin')}
icon="pi pi-download"
iconPos="right"/> : null
)
}
export default DownloadSignedApplication;

View File

@@ -0,0 +1,72 @@
import React from 'react';
import { Button } from 'primereact/button';
import { __ } from '@wordpress/i18n';
import { isNil } from 'ramda';
import ArchiveDocument from '../ArchiveDocument';
const ListOfFiles = ({ files, updateFn, shouldDisableFieldFn, name, ndg, applicationId }) => {
return (
<ol className="appPageSection__list">
{files.map((o, i) => <li key={o.id} className="appPageSection__listItem">
<div className="appPageSection__listItemRow">
<span>{o.label}</span>
<div className="appPageSection__iconActions">
{o.fileDetail && o.fileDetail.length === 1
? <Button icon="pi pi-eye" rounded
onClick={() => {
window.open(o.fileDetail[0].filePath, '_blank').focus()
}}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/> : null}
<Button icon="pi pi-thumbs-up" rounded outlined
disabled={shouldDisableFieldFn(name)}
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
onClick={() => updateFn(
true,
[name, i, 'valid']
)}
aria-label={__('Su', 'gepafin')}/>
<Button icon="pi pi-thumbs-down" rounded outlined
disabled={shouldDisableFieldFn(name)}
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
onClick={() => updateFn(
false,
[name, i, 'valid']
)}
aria-label={__('Giu', 'gepafin')}/>
</div>
</div>
{o.fileDetail && o.fileDetail.length > 1
? <ul style={{
width: '100%',
paddingLeft: '15px',
display: 'flex',
flexDirection: 'column',
gap: '10px'
}}>
{o.fileDetail.map((k) => <li key={k.id} style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<span>{k.name}</span>
<div className="appPageSection__iconActions">
<ArchiveDocument ndg={ndg} applicationId={applicationId} fileId={k.id}/>
<Button icon="pi pi-eye" rounded
onClick={() => {
window.open(k.filePath, '_blank').focus()
}}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/>
</div>
</li>)}
</ul>
: null}
</li>)}
</ol>
)
}
export default ListOfFiles;

View File

@@ -32,6 +32,11 @@ import ArchiveDocument from './components/ArchiveDocument';
import { classNames } from 'primereact/utils'; import { classNames } from 'primereact/utils';
import { InputTextarea } from 'primereact/inputtextarea'; import { InputTextarea } from 'primereact/inputtextarea';
import { InputText } from 'primereact/inputtext'; import { InputText } from 'primereact/inputtext';
import DownloadApplicationArchive from './components/DownloadApplicationArchive';
import DownloadCompanyDelegation from './components/DownloadCompanyDelegation';
import DownloadSignedApplication from './components/DownloadSignedApplication';
import AppointmentService from '../../service/appointment-service';
import ListOfFiles from './components/ListOfFiles';
const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID; const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
@@ -51,6 +56,9 @@ const DomandaEditPreInstructor = () => {
const [operationType, setOperationType] = useState(''); const [operationType, setOperationType] = useState('');
const [motivation, setMotivation] = useState(''); const [motivation, setMotivation] = useState('');
const [isVisibleAppointmentDialog, setIsVisibleAppointmentDialog] = useState(false); const [isVisibleAppointmentDialog, setIsVisibleAppointmentDialog] = useState(false);
const [allFilesRated, setAllFilesRated] = useState(false);
const [atLeastOneChecked, setAtLeastOneChecked] = useState(false);
const [allChecksChecked, setAllChecksChecked] = useState(false);
const [appointmentData, setAppointmentData] = useState({ const [appointmentData, setAppointmentData] = useState({
title: '', title: '',
text: '', text: '',
@@ -62,6 +70,22 @@ const DomandaEditPreInstructor = () => {
navigate('/domande'); navigate('/domande');
} }
const updateFlagsForSoccorso = (data) => {
if (data.files) {
const nonRatedFiles = data.files
.map(el => el.valid)
.filter(v => isNil(v));
setAllFilesRated(nonRatedFiles.length === 0);
}
if (data.checklist) {
const checkedChecklistItems = data.checklist
.map(el => el.valid)
.filter(v => v);
setAtLeastOneChecked(checkedChecklistItems.length > 0);
setAllChecksChecked(checkedChecklistItems.length === data.checklist.length)
}
}
const doNewSoccorso = () => { const doNewSoccorso = () => {
if (connectedSoccorsoId !== 0) { if (connectedSoccorsoId !== 0) {
doSaveDraft(`/domande/${id}/soccorso/${connectedSoccorsoId}`) doSaveDraft(`/domande/${id}/soccorso/${connectedSoccorsoId}`)
@@ -74,6 +98,7 @@ const DomandaEditPreInstructor = () => {
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data)); setData(getFormattedData(data.data));
setMotivation(data.data.motivation); setMotivation(data.data.motivation);
updateFlagsForSoccorso(data.data);
} }
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
} }
@@ -116,15 +141,16 @@ const DomandaEditPreInstructor = () => {
const header = renderHeader(); const header = renderHeader();
const updateEvaluationValue = (value, path, maxValue) => { const updateEvaluationValue = (value, path, maxValue = null) => {
let finalValue = value; let finalValue = value;
if (maxValue || maxValue === 0) { if (maxValue || maxValue === 0) {
finalValue = value > maxValue ? maxValue : value; finalValue = value > maxValue ? maxValue : value;
} }
const newData = wrap(data).set(path.split('.'), finalValue).value(); const newData = wrap(data).set(path, finalValue).value();
setData(newData); setData(newData);
updateFlagsForSoccorso(newData);
} }
const doSaveDraft = (doRedirect = '') => { const doSaveDraft = (doRedirect = '') => {
@@ -134,6 +160,7 @@ const DomandaEditPreInstructor = () => {
files: klona(data.files), files: klona(data.files),
note: data.note note: data.note
} }
ApplicationEvaluationService.updateEvaluation( ApplicationEvaluationService.updateEvaluation(
data.assignedApplicationId, data.assignedApplicationId,
formData, formData,
@@ -241,9 +268,11 @@ const DomandaEditPreInstructor = () => {
switch (item.fieldName) { switch (item.fieldName) {
case 'fileupload' : case 'fileupload' :
content = <ul> content = <ul>
{item.fieldValue.map(o => <li key={o.id}> {item.fieldValue
{o.filePath ? <a href={o.filePath}>{o.name}</a> : null} ? item.fieldValue.map(o => <li key={o.id}>
</li>)} {o.filePath ? <a href={o.filePath}>{o.name}</a> : null}
</li>)
: null}
</ul>; </ul>;
break; break;
case 'table' : case 'table' :
@@ -255,9 +284,11 @@ const DomandaEditPreInstructor = () => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{item.fieldValue.map((o, i) => <tr key={i}> {item.fieldValue
{Object.values(o).map(v => <td key={v}>{v}</td>)} ? item.fieldValue.map((o, i) => <tr key={i}>
</tr>)} {Object.values(o).map(v => <td key={v}>{v}</td>)}
</tr>)
: null}
</tbody> </tbody>
</table>; </table>;
break; break;
@@ -336,7 +367,30 @@ const DomandaEditPreInstructor = () => {
} }
const doCheckNDG = () => { const doCheckNDG = () => {
// TODO storeSet.main.setAsyncRequest();
doSaveDraft();
setTimeout(() => {
AppointmentService.getNdg(id, getNdgCallback, errGetNdgCallback);
}, 100);
}
const getNdgCallback = (data) => {
if (data.status === 'SUCCESS') {
console.log('data', data.data);
}
storeSet.main.unsetAsyncRequest();
}
const errGetNdgCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
} }
const doCreateAppointment = () => { const doCreateAppointment = () => {
@@ -376,7 +430,7 @@ const DomandaEditPreInstructor = () => {
const doCreateAppointmentRequest = () => { const doCreateAppointmentRequest = () => {
if ( if (
!isEmpty(appointmentData.title) && !isEmpty(appointmentData.text) && !isEmpty(appointmentData.amount) !isEmpty(appointmentData.title) && !isEmpty(appointmentData.text) && !isEmpty(appointmentData.amount)
&& !isEmpty(appointmentData.duration) && appointmentData.duration !== 0 && appointmentData.amount !== 0 && !isEmpty(appointmentData.duration) && appointmentData.duration !== 0 && appointmentData.amount !== 0
) { ) {
console.log(appointmentData); console.log(appointmentData);
//setLoading(true); //setLoading(true);
@@ -436,6 +490,18 @@ const DomandaEditPreInstructor = () => {
<span>{__('ID domanda', 'gepafin')}</span> <span>{__('ID domanda', 'gepafin')}</span>
<span>{data.applicationId}</span> <span>{data.applicationId}</span>
</p> </p>
<p className="appPageSection__pMeta">
<span>{__('Protocollo', 'gepafin')}</span>
<span>{data.protocolNumber}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('NDG', 'gepafin')}</span>
<span>{data.ndg}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Appuntamento', 'gepafin')}</span>
<span>{data.appointmentId}</span>
</p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Bando', 'gepafin')}</span> <span>{__('Bando', 'gepafin')}</span>
<span>{data.callName}</span> <span>{data.callName}</span>
@@ -444,13 +510,21 @@ const DomandaEditPreInstructor = () => {
<span>{__('Beneficiario', 'gepafin')}</span> <span>{__('Beneficiario', 'gepafin')}</span>
<span>{data.beneficiary}</span> <span>{data.beneficiary}</span>
</p> </p>
<p className="appPageSection__pMeta">
<span>{__('Azienda', 'gepafin')}</span>
<span>{data.companyName}</span>
</p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Data ricezione', 'gepafin')}</span> <span>{__('Data ricezione', 'gepafin')}</span>
<span>{getDateFromISOstring(data.submissionDate)}</span> <span>{getDateFromISOstring(data.submissionDate)}</span>
</p> </p>
<p className="appPageSection__pMeta">
<span>{__('Data assegnazione', 'gepafin')}</span>
<span>{getDateFromISOstring(data.assignedAt)}</span>
</p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Scadenza Valutazione', 'gepafin')}</span> <span>{__('Scadenza Valutazione', 'gepafin')}</span>
<span>{getDateFromISOstring(data.callEndDate)}</span> <span>{getDateFromISOstring(data.evaluationEndDate)}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Stato', 'gepafin')}</span> <span>{__('Stato', 'gepafin')}</span>
@@ -458,7 +532,64 @@ const DomandaEditPreInstructor = () => {
</p> </p>
</div> </div>
<div className="appPageSection"></div> <div className="appPageSection">
<h2>{__('Scarica documenti della domanda', 'gepafin')}</h2>
<div className="appPageSection__row autoFlow">
<DownloadApplicationArchive applicationId={id}/>
<DownloadSignedApplication applicationId={id}/>
<DownloadCompanyDelegation applicationId={id}/>
</div>
</div>
<div className="appPageSection">
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
<div className="appPageSection columns">
<div>
<h3>{__('Lista', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey" style={{ marginBottom: '20px' }}>
<div className="appPageSection__checklist">
{data.checklist.map((o, i) => <div key={o.id}>
<Checkbox
disabled={shouldDisableField('checklist')}
inputId={`checklist_${o.id}`}
onChange={(e) => updateEvaluationValue(
e.checked,
['checklist', i, 'valid']
)}
checked={o.valid}></Checkbox>
<label htmlFor={`checklist_${o.id}`}>{o.label}</label>
</div>)}
</div>
</div>
<h3>{__('Note', 'gepafin')}</h3>
<div>
<Editor
value={data.note}
readOnly={shouldDisableField('note')}
placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header}
onTextChange={(e) => updateEvaluationValue(
e.htmlValue,
['note']
)}
style={{ height: 80 * 3, width: '100%' }}
/>
</div>
</div>
<div>
<h3>{__('Documenti allegati', 'gepafin')}</h3>
<ListOfFiles
files={data.files}
updateFn={updateEvaluationValue}
shouldDisableFieldFn={shouldDisableField}
name="files"
ndg={data.ndg}
applicationId={id}/>
</div>
</div>
</div>
<div className="appPageSection"> <div className="appPageSection">
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2> <h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
@@ -484,8 +615,8 @@ const DomandaEditPreInstructor = () => {
max={o.maxScore} max={o.maxScore}
onChange={(e) => updateEvaluationValue( onChange={(e) => updateEvaluationValue(
e.value, e.value,
`criteria.${i}.score`, ['criteria', i, 'score'],
o.maxScore o.criteria
)}/> )}/>
<span className="p-inputgroup-addon"> <span className="p-inputgroup-addon">
/ {o.maxScore} / {o.maxScore}
@@ -504,7 +635,7 @@ const DomandaEditPreInstructor = () => {
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'} severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
onClick={() => updateEvaluationValue( onClick={() => updateEvaluationValue(
true, true,
`criteria.${i}.valid` ['criteria', i, 'valid']
)} )}
aria-label={__('Su', 'gepafin')}/> aria-label={__('Su', 'gepafin')}/>
<Button icon="pi pi-thumbs-down" rounded outlined <Button icon="pi pi-thumbs-down" rounded outlined
@@ -512,7 +643,7 @@ const DomandaEditPreInstructor = () => {
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'} severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
onClick={() => updateEvaluationValue( onClick={() => updateEvaluationValue(
false, false,
`criteria.${i}.valid` ['criteria', i, 'valid']
)} )}
aria-label={__('Giu', 'gepafin')}/> aria-label={__('Giu', 'gepafin')}/>
</div> </div>
@@ -539,104 +670,6 @@ const DomandaEditPreInstructor = () => {
</table> : null} </table> : null}
</div> </div>
<div className="appPageSection">
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
<div className="appPageSection columns">
<div>
<h3>{__('Lista', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey" style={{ marginBottom: '20px' }}>
<div className="appPageSection__checklist">
{data.checklist.map((o, i) => <div key={o.id}>
<Checkbox
disabled={shouldDisableField('checklist')}
inputId={`checklist_${o.id}`}
onChange={(e) => updateEvaluationValue(
e.checked,
`checklist.${i}.valid`
)}
checked={o.valid}></Checkbox>
<label htmlFor={`checklist_${o.id}`}>{o.label}</label>
</div>)}
</div>
</div>
<h3>{__('Note', 'gepafin')}</h3>
<div>
<Editor
value={data.note}
readOnly={shouldDisableField('note')}
placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header}
onTextChange={(e) => updateEvaluationValue(
e.htmlValue,
'note'
)}
style={{ height: 80 * 3, width: '100%' }}
/>
</div>
</div>
<div>
<h3>{__('Documenti allegati', 'gepafin')}</h3>
<ol className="appPageSection__list">
{data.files.map((o, i) => <li key={o.id} className="appPageSection__listItem">
<div className="appPageSection__listItemRow">
<span>{o.label}</span>
<div className="appPageSection__iconActions">
{o.fileDetail && o.fileDetail.length === 1
? <Button icon="pi pi-eye" rounded
onClick={() => window.open(o.fileDetail[0].filePath, '_blank').focus()}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/> : null}
<Button icon="pi pi-thumbs-up" rounded outlined
disabled={shouldDisableField('files')}
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
onClick={() => updateEvaluationValue(
true,
`files.${i}.valid`
)}
aria-label={__('Su', 'gepafin')}/>
<Button icon="pi pi-thumbs-down" rounded outlined
disabled={shouldDisableField('files')}
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
onClick={() => updateEvaluationValue(
false,
`files.${i}.valid`
)}
aria-label={__('Giu', 'gepafin')}/>
</div>
</div>
{o.fileDetail && o.fileDetail.length > 1
? <ul style={{
width: '100%',
paddingLeft: '15px',
display: 'flex',
flexDirection: 'column',
gap: '10px'
}}>
{o.fileDetail.map((k, i) => <li key={k.id} style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<span>{k.name}</span>
<div className="appPageSection__iconActions">
<ArchiveDocument ndg={data.ndg} fileId={k.id}/>
<Button icon="pi pi-eye" rounded
onClick={() => window.open(k.filePath, '_blank').focus()}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/>
</div>
</li>)}
</ul>
: null}
</li>)}
</ol>
</div>
</div>
</div>
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>
<div className="appPageSection__hr"> <div className="appPageSection__hr">
@@ -647,36 +680,36 @@ const DomandaEditPreInstructor = () => {
<div className="appPageSection__actions"> <div className="appPageSection__actions">
{['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus) {['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus)
? <Button ? <Button
type="button" type="button"
disabled={!data.id || data.status === 'CLOSE'} disabled={!data.id || data.status === 'CLOSE' || !allFilesRated || !atLeastOneChecked}
onClick={doNewSoccorso} onClick={doNewSoccorso}
outlined outlined
label={<> label={<>
{data.applicationStatus === 'EVALUATION' {data.applicationStatus === 'EVALUATION'
? __('Richiedi Soccorso Istruttorio', 'gepafin') ? __('Richiedi Soccorso Istruttorio', 'gepafin')
: __('Apri Soccorso Istruttorio', 'gepafin')} : __('Apri Soccorso Istruttorio', 'gepafin')}
<i style={{ marginLeft: 7 }}> <i style={{ marginLeft: 7 }}>
<HelpIcon/> <HelpIcon/>
</i> </i>
</>} </>}
/> : null} /> : null}
{data.id {data.id
? <Button ? <Button
type="button" type="button"
disabled={data.status === 'CLOSE'} disabled={data.status === 'CLOSE'}
onClick={doSaveDraft} onClick={() => doSaveDraft()}
outlined outlined
label={__('Salva bozza valutazione', 'gepafin')} label={__('Salva bozza valutazione', 'gepafin')}
icon="pi pi-save" iconPos="right"/> icon="pi pi-save" iconPos="right"/>
: <Button : <Button
type="button" type="button"
onClick={doSaveDraft} onClick={() => doSaveDraft()}
label={__('Crea valutazione', 'gepafin')} label={__('Crea valutazione', 'gepafin')}
icon="pi pi-save" iconPos="right"/>} icon="pi pi-save" iconPos="right"/>}
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus) {APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
? <Button ? <Button
type="button" type="button"
disabled={!data.id} disabled={!data.id || !allFilesRated || !allChecksChecked}
onClick={doCheckNDG} onClick={doCheckNDG}
label={__('Controlla NDG', 'gepafin')} label={__('Controlla NDG', 'gepafin')}
/> : null} /> : null}
@@ -748,7 +781,8 @@ const DomandaEditPreInstructor = () => {
style={{ maxWidth: '600px', width: '100%' }} style={{ maxWidth: '600px', width: '100%' }}
onHide={hideAppointmentDialog}> onHide={hideAppointmentDialog}>
<div className="appForm__field"> <div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(appointmentData.amount) || appointmentData.amount === 0})}> <label
className={classNames({ 'p-error': isEmpty(appointmentData.amount) || appointmentData.amount === 0 })}>
{__('Importo', 'gepafin')} {__('Importo', 'gepafin')}
</label> </label>
<InputNumber <InputNumber
@@ -758,13 +792,14 @@ const DomandaEditPreInstructor = () => {
onChange={(e) => setValue('amount', e.value)}/> onChange={(e) => setValue('amount', e.value)}/>
</div> </div>
<div className="appForm__field"> <div className="appForm__field">
<label className={classNames({ 'p-error': isEmpty(appointmentData.duration) || appointmentData.duration === 0 })}> <label
className={classNames({ 'p-error': isEmpty(appointmentData.duration) || appointmentData.duration === 0 })}>
{__('Durata', 'gepafin')} {__('Durata', 'gepafin')}
</label> </label>
<InputNumber <InputNumber
value={appointmentData.duration} value={appointmentData.duration}
keyfilter="int" keyfilter="int"
invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0} invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0}
onChange={(e) => setValue('duration', e.value)}/> onChange={(e) => setValue('duration', e.value)}/>
</div> </div>
<div className="appForm__field"> <div className="appForm__field">

View File

@@ -98,9 +98,9 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
return formatDate(rowData.submissionDate); return formatDate(rowData.submissionDate);
}; };
const dateEndBodyTemplate = (rowData) => { /*const dateEndBodyTemplate = (rowData) => {
return formatDate(rowData.callEndDate); return formatDate(rowData.callEndDate);
}; };*/
const dateFilterTemplate = (options) => { const dateFilterTemplate = (options) => {
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)}
@@ -138,9 +138,11 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
emptyMessage={translationStrings.emptyMessage} emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}> onFilter={(e) => setFilters(e.filters)}>
<Column field="id" header={__('ID domanda', 'gepafin')} <Column field="id" header={__('ID domanda', 'gepafin')}
sortable sortable filterPlaceholder={__('Cerca', 'gepafin')}
filterPlaceholder={__('Cerca', 'gepafin')} style={{ minWidth: '6rem' }}/>
style={{ minWidth: '8rem' }}/> <Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="callTitle" header={__('Bando', 'gepafin')} <Column field="callTitle" header={__('Bando', 'gepafin')}
filter sortable filter sortable
filterPlaceholder={__('Cerca', 'gepafin')} filterPlaceholder={__('Cerca', 'gepafin')}
@@ -153,10 +155,10 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
filterField="submissionDate" dataType="date" filterField="submissionDate" dataType="date"
style={{ minWidth: '8rem' }} style={{ minWidth: '8rem' }}
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')} {/*<Column header={__('Scadenza', 'gepafin')}
filterField="callEndDate" dataType="date" filterField="callEndDate" dataType="date"
style={{ minWidth: '8rem' }} style={{ minWidth: '8rem' }}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>*/}
<Column field="status" header={__('Stato', 'gepafin')} <Column field="status" header={__('Stato', 'gepafin')}
style={{ minWidth: '8rem' }} body={statusBodyTemplate}/> style={{ minWidth: '8rem' }} body={statusBodyTemplate}/>
<Column header={__('Azioni', 'gepafin')} <Column header={__('Azioni', 'gepafin')}

View File

@@ -37,7 +37,7 @@ const BeneficiarioDomandeTable = () => {
setLocalAsyncRequest(true); setLocalAsyncRequest(true);
ApplicationService.getApplications(getApplCallback, errGetApplCallback, [ ApplicationService.getApplications(getApplCallback, errGetApplCallback, [
['companyId', chosenCompanyId], ['companyId', chosenCompanyId],
['statuses', ['SOCCORSO', 'APPROVED', 'REJECTED', 'EVALUATION', 'SUBMIT']] ['statuses', ['SOCCORSO', 'APPROVED', 'REJECTED', 'EVALUATION', 'SUBMIT']] // 'NDG', 'ADMISSIBLE', 'APPOINTMENT'
]); ]);
} }
}, [chosenCompanyId]); }, [chosenCompanyId]);
@@ -156,8 +156,10 @@ const BeneficiarioDomandeTable = () => {
emptyMessage={translationStrings.emptyMessage} emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}> onFilter={(e) => setFilters(e.filters)}>
<Column field="id" header={__('ID domanda', 'gepafin')} <Column field="id" header={__('ID domanda', 'gepafin')}
sortable sortable filterPlaceholder={__('Cerca', 'gepafin')}
filterPlaceholder={__('Cerca il nome', 'gepafin')} style={{ minWidth: '6rem' }}/>
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/> style={{ minWidth: '6rem' }}/>
<Column field="callTitle" header={__('Titolo bando', 'gepafin')} <Column field="callTitle" header={__('Titolo bando', 'gepafin')}
filter sortable filter sortable

View File

@@ -3,6 +3,7 @@ import { __, sprintf } from '@wordpress/i18n';
import { classNames } from 'primereact/utils'; import { classNames } from 'primereact/utils';
import { isEmpty, isNil } from 'ramda'; import { isEmpty, isNil } from 'ramda';
import hotkeys from 'hotkeys-js'; import hotkeys from 'hotkeys-js';
import { useSearchParams } from 'react-router-dom';
// store // store
import { storeSet, useStore } from '../../store'; import { storeSet, useStore } from '../../store';
@@ -13,7 +14,6 @@ import AuthenticationService from '../../service/authentication-service';
// components // components
import LogoIcon from '../../icons/LogoIcon'; import LogoIcon from '../../icons/LogoIcon';
import { Messages } from 'primereact/messages'; import { Messages } from 'primereact/messages';
import { useSearchParams } from 'react-router-dom';
import { Dialog } from 'primereact/dialog'; import { Dialog } from 'primereact/dialog';
import { Accordion } from 'primereact/accordion'; import { Accordion } from 'primereact/accordion';
import { AccordionTab } from 'primereact/accordion'; import { AccordionTab } from 'primereact/accordion';
@@ -98,7 +98,9 @@ const Login = () => {
}, [isMaintenance]) }, [isMaintenance])
useEffect(() => { useEffect(() => {
if (!isEmpty(token)) { const queryParams = Object.fromEntries(searchParams);
if (!isEmpty(token) && isNil(queryParams.redirectReason)) {
window.location.replace('/') window.location.replace('/')
} }
}, [token]); }, [token]);
@@ -116,7 +118,7 @@ const Login = () => {
/*if ('t7jh5wfg9QXylNaTZkPoE' === APP_HUB_ID) { /*if ('t7jh5wfg9QXylNaTZkPoE' === APP_HUB_ID) {
setIsMaintenance(true); setIsMaintenance(true);
}*/ }*/
hotkeys('command+x', function(event, handler){ hotkeys('command+x,ctrl+x', function(event, handler){
window.location.replace('/loginadmin') window.location.replace('/loginadmin')
}); });
}, []); }, []);

View File

@@ -341,7 +341,9 @@ const ProfileCompany = () => {
useEffect(() => { useEffect(() => {
if (formInitialData.id) { if (formInitialData.id) {
storeSet.main.setAsyncRequest(); storeSet.main.setAsyncRequest();
CompanyService.getCompanyDelega(formInitialData.id, getDellegaCallback, errDellegaCallback); CompanyService.getCompanyDelega(getDellegaCallback, errDellegaCallback, [
['companyId', formInitialData.id]
]);
} }
}, [formInitialData]) }, [formInitialData])

View File

@@ -407,6 +407,7 @@ const SoccorsoEditPreInstructor = () => {
errors={errors} errors={errors}
defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []} defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []}
accept={[]} accept={[]}
source="AMENDMENT"
sourceId={data.applicationId} sourceId={data.applicationId}
multiple={true} multiple={true}
/> />

View File

@@ -54,7 +54,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
const getFormattedData = (data) => { const getFormattedData = (data) => {
return data.map((d) => { return data.map((d) => {
d.startDate = is(String, d.startDate) ? new Date(d.startDate) : (d.startDate ? d.startDate : ''); d.startDate = is(String, d.startDate) ? new Date(d.startDate) : (d.startDate ? d.startDate : '');
d.expirationDate = is(String, d.expirationDate) ? new Date(d.expirationDate) : (d.expirationDate ? d.expirationDate : ''); d.evaluationEndDate = is(String, d.evaluationEndDate) ? new Date(d.evaluationEndDate) : (d.evaluationEndDate ? d.evaluationEndDate : '');
return d; return d;
}); });
}; };
@@ -86,7 +86,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}, },
expirationDate: { evaluationEndDate: {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
} }
@@ -106,7 +106,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
}; };
const dateExpirationBodyTemplate = (rowData) => { const dateExpirationBodyTemplate = (rowData) => {
return rowData.expirationDate ? formatDate(rowData.expirationDate) : ''; return rowData.evaluationEndDate ? formatDate(rowData.evaluationEndDate) : '';
}; };
const dateFilterTemplate = (options) => { const dateFilterTemplate = (options) => {
@@ -141,7 +141,10 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
emptyMessage={translationStrings.emptyMessage} emptyMessage={translationStrings.emptyMessage}
onFilter={(e) => setFilters(e.filters)}> onFilter={(e) => setFilters(e.filters)}>
<Column field="applicationId" header={__('ID domanda', 'gepafin')} <Column field="applicationId" header={__('ID domanda', 'gepafin')}
filter filterPlaceholder={__('Cerca', 'gepafin')} sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/>
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
sortable filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '6rem' }}/> style={{ minWidth: '6rem' }}/>
<Column field="callName" header={__('Bando', 'gepafin')} <Column field="callName" header={__('Bando', 'gepafin')}
filter filterPlaceholder={__('Cerca', 'gepafin')} filter filterPlaceholder={__('Cerca', 'gepafin')}
@@ -154,7 +157,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
style={{ minWidth: '8rem' }} style={{ minWidth: '8rem' }}
body={dateStartBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateStartBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')} <Column header={__('Scadenza', 'gepafin')}
filterField="expirationDate" dataType="date" filterField="evaluationEndDate" dataType="date"
style={{ minWidth: '8rem' }} style={{ minWidth: '8rem' }}
body={dateExpirationBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateExpirationBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="status" header={__('Stato', 'gepafin')} <Column field="status" header={__('Stato', 'gepafin')}

View File

@@ -47,4 +47,8 @@ export default class ApplicationService {
static deleteApplicationSignedPdf = (id, callback, errCallback) => { static deleteApplicationSignedPdf = (id, callback, errCallback) => {
NetworkService.delete(`${API_BASE_URL}/application/${id}/signedDocument`, {}, callback, errCallback); NetworkService.delete(`${API_BASE_URL}/application/${id}/signedDocument`, {}, callback, errCallback);
}; };
static downloadCompleteZip = (id, callback, errCallback, queryParams) => {
NetworkService.getBlob(`${API_BASE_URL}/application/${id}/documents/zip`, callback, errCallback, queryParams);
};
} }

View File

@@ -0,0 +1,14 @@
import { NetworkService } from './network-service';
const API_BASE_URL = process.env.REACT_APP_API_EXECUTION_ADDRESS;
export default class AppointmentService {
static getNdg = (id, callback, errCallback, queryParams) => {
NetworkService.get(`${API_BASE_URL}/appointment/application/${id}/check-ndg`, callback, errCallback, queryParams);
};
static archiveDocument = (applicationId, documentId, body, callback, errCallback, queryParams) => {
NetworkService.post(`${API_BASE_URL}/appointment/application/${applicationId}/document/${documentId}`, {}, callback, errCallback, queryParams);
};
}

View File

@@ -20,8 +20,8 @@ export default class CompanyService {
NetworkService.get(`${API_BASE_URL}/company/user/${id}`, callback, errCallback); NetworkService.get(`${API_BASE_URL}/company/user/${id}`, callback, errCallback);
}; };
static getCompanyDelega = (id, callback, errCallback) => { static getCompanyDelega = (callback, errCallback, queryParams) => {
NetworkService.get(`${API_BASE_URL}/company/${id}/delegation`, callback, errCallback); NetworkService.get(`${API_BASE_URL}/company/delegation`, callback, errCallback, queryParams);
}; };
static downloadCompanyDelega = (id, body, callback, errCallback) => { static downloadCompanyDelega = (id, body, callback, errCallback) => {

View File

@@ -1,73 +1,20 @@
import { storeGet } from '../store'; import { storeGet, storeSet } from '../store';
import * as Sentry from "@sentry/browser"; import logMsgWithSentry from '../helpers/logMsgWithSentry';
export class NetworkService { export class NetworkService {
static TOKEN_KEY
static REFRESH_TOKEN_KEY
static logApiError = (endpoint, status = 0, resp) => { static logApiError = (endpoint, status = 0, resp = {}) => {
try { if (status === 500) {
if ([500].includes(status)) { logMsgWithSentry(endpoint, status, resp);
Sentry.init({ } else if (status === 403) {
dsn: "https://e7b2134f7d816f663bb83e51b106a694@o4508381921738752.ingest.de.sentry.io/4508381935501392", storeSet.main.token('');
environment: process.env.NODE_ENV || "development" const { pathname } = window.location;
}); if (!['/login', '/loginadmin', '/reset-password', '/registration'].includes(pathname)) {
window.location.replace('/login');
const error = new Error(`Status ${status}`);
Sentry.captureException(`Error in endpoint: ${endpoint}`, {
level: 'error',
extra: {
originalError: error,
details: resp
}
});
} }
} catch (err) {
console.log(err);
} }
} }
static postEmptyResponse = (url, body, callback, errorCallback) => {
fetch(url, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': storeGet.main.getToken(),
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(body)
})
.then(data => {
if (data.status >= 400 && data.status <= 599)
errorCallback(data.status)
else
callback()
})
.catch(err => errorCallback(err));
};
static putEmptyResponse = (url, body, callback, errorCallback) => {
fetch(url, {
method: 'PUT',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': storeGet.main.getToken(),
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(body)
})
.then(data => {
if (data.status >= 400 && data.status <= 599)
errorCallback(data.status)
else
callback()
})
.catch(err => errorCallback(err));
};
static post = (url, body, callback, errorCallback, queryParams) => { static post = (url, body, callback, errorCallback, queryParams) => {
if (queryParams) { if (queryParams) {
@@ -98,6 +45,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
this.logApiError(url, status);
return { response: await response.json(), status: status } return { response: await response.json(), status: status }
}) })
.then(data => { .then(data => {
@@ -141,6 +89,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
this.logApiError(url, status);
return { response: await response.json(), status: status } return { response: await response.json(), status: status }
}) })
.then(data => { .then(data => {
@@ -184,6 +133,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
this.logApiError(url, status);
return { response: await response.blob(), status: status } return { response: await response.blob(), status: status }
}) })
.then(data => { .then(data => {
@@ -225,6 +175,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
this.logApiError(url, status);
return { response: await response.json(), status: status } return { response: await response.json(), status: status }
}) })
.then(data => { .then(data => {
@@ -238,28 +189,6 @@ export class NetworkService {
.catch(err => errorCallback(err)); .catch(err => errorCallback(err));
}; };
static patch = (url, body, callback, errorCallback) => {
fetch(url, {
method: 'PATCH',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
})
.then(async response => {
let status = response.status;
return { response: await response.json(), status: status }
})
.then(data => {
if (data.status >= 400 && data.status <= 599)
errorCallback(data.response)
else
callback(data.response)
})
.catch(err => errorCallback(err));
};
static put = (url, body, callback, errorCallback, queryParams = null) => { static put = (url, body, callback, errorCallback, queryParams = null) => {
if (queryParams) { if (queryParams) {
url += '?' url += '?'
@@ -290,6 +219,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
this.logApiError(url, status);
return { response: await response.json(), status: status } return { response: await response.json(), status: status }
}) })
.then(data => { .then(data => {
@@ -303,79 +233,6 @@ export class NetworkService {
.catch(err => errorCallback(err)); .catch(err => errorCallback(err));
}; };
static unauthorizedPostEmptyResponse = (url, body, callback, errorCallback) => {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(body)
})
.then(data => callback(data))
.catch(err => errorCallback(err));
};
static unauthorizedPutEmptyResponse = (url, body, callback, errorCallback) => {
fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(body)
})
.then(data => callback(data))
.catch(err => errorCallback(err));
};
static unauthorizedGet = (url, queryParams, callback, errorCallback) => {
fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
}
})
.then(async response => {
let status = response.status;
return { response: await response.json(), status: status }
})
.then(data => {
if (data.status >= 400 && data.status <= 599)
errorCallback(data.response)
else
callback(data.response)
})
.catch(err => errorCallback(err));
};
static unauthorizedPatch = (url, body, callback, errorCallback) => {
fetch(url, {
method: 'PATCH',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
})
.then(async response => {
let status = response.status;
return { response: await response.json(), status: status }
})
.then(data => {
if (data.status >= 400 && data.status <= 599)
errorCallback(data.response)
else
callback(data.response)
})
.catch(err => errorCallback(err));
};
static isNotBlank(value) { static isNotBlank(value) {
return value !== null && value !== undefined && value !== '' return value !== null && value !== undefined && value !== ''
} }
@@ -410,7 +267,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
//console.log('status in fetch:', status) this.logApiError(url, status);
return { response: await response.json(), status: status } return { response: await response.json(), status: status }
}) })
.then(data => { .then(data => {
@@ -456,6 +313,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
this.logApiError(url, status);
return { response: await response.blob(), status: status } return { response: await response.blob(), status: status }
}) })
.then(data => { .then(data => {
@@ -469,53 +327,6 @@ export class NetworkService {
.catch(err => errorCallback(err)); .catch(err => errorCallback(err));
}; };
static promiseGet = async (url, queryParams = null) => {
const response = await fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + storeGet.main.getToken(),
'Access-Control-Allow-Origin': '*'
}
});
const json = await response.json();
return json;
}
static deleteEmptyResponse = (url, callback, errorCallback, queryParams = null) => {
if (queryParams) {
let params = '?'
for (let i = 0; i < queryParams.length; i++) {
params += queryParams[i][0] + '=' + queryParams[i][1]
if (queryParams.length !== i + 1)
params += '&'
url += params
params = ''
}
}
fetch(url, {
method: 'DELETE',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': storeGet.main.getToken(),
'Access-Control-Allow-Origin': '*'
}
})
.then(data => {
if (data.status >= 400 && data.status <= 599)
errorCallback(data.status)
else
callback()
})
.catch(err => errorCallback(err));
}
static delete = (url, body, callback, errorCallback, queryParams = null) => { static delete = (url, body, callback, errorCallback, queryParams = null) => {
if (queryParams) { if (queryParams) {
let params = '?' let params = '?'
@@ -540,6 +351,7 @@ export class NetworkService {
}) })
.then(async response => { .then(async response => {
let status = response.status; let status = response.status;
this.logApiError(url, status);
return { response: await response.json(), status: status } return { response: await response.json(), status: status }
}) })
.then(data => { .then(data => {