- saving progress;

This commit is contained in:
Vitalii Kiiko
2024-10-29 09:56:03 +01:00
14 changed files with 941 additions and 133 deletions

View File

@@ -26,6 +26,9 @@ const getBandoLabel = (status) => {
case 'AWAIT': case 'AWAIT':
return __('In attesa', 'gepafin'); return __('In attesa', 'gepafin');
case 'OPEN':
return __('Aperto', 'gepafin');
case 'ASSIGNED': case 'ASSIGNED':
return __('Assegnato', 'gepafin'); return __('Assegnato', 'gepafin');

View File

@@ -24,6 +24,9 @@ const getBandoSeverity = (status) => {
case 'AWAIT': case 'AWAIT':
return 'warning'; return 'warning';
case 'OPEN':
return 'warning';
case 'ASSIGNED': case 'ASSIGNED':
return 'warning'; return 'warning';

View File

@@ -0,0 +1,20 @@
import React from 'react';
const HelpIcon = () => {
return <svg width="15" height="14" viewBox="0 0 15 14" fill="none"
xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1665_1656)">
<path
d="M7.50129 14C6.53308 14 5.62302 13.8163 4.7711 13.4488C3.91919 13.0814 3.17818 12.5827 2.54805 11.9529C1.91793 11.323 1.41903 10.5823 1.05134 9.73074C0.683781 8.87919 0.5 7.96938 0.5 7.00129C0.5 6.03308 0.683719 5.12302 1.05116 4.2711C1.4186 3.41919 1.91725 2.67818 2.54713 2.04805C3.17701 1.41793 3.91772 0.919026 4.76926 0.551342C5.62081 0.183781 6.53062 0 7.49871 0C8.46692 0 9.37698 0.183719 10.2289 0.551158C11.0808 0.918596 11.8218 1.41725 12.4519 2.04713C13.0821 2.67701 13.581 3.41772 13.9487 4.26926C14.3162 5.12081 14.5 6.03062 14.5 6.99871C14.5 7.96692 14.3163 8.87698 13.9488 9.72889C13.5814 10.5808 13.0827 11.3218 12.4529 11.9519C11.823 12.5821 11.0823 13.081 10.2307 13.4487C9.37919 13.8162 8.46938 14 7.50129 14ZM5.36316 12.4895L6.44576 10.0238C5.98585 9.86147 5.58888 9.60977 5.25484 9.26874C4.92081 8.92758 4.66598 8.52747 4.49037 8.06842L1.99634 9.1C2.28359 9.88596 2.72195 10.5737 3.31142 11.1632C3.90089 11.7526 4.58481 12.1947 5.36316 12.4895ZM4.49037 5.93158C4.65665 5.47253 4.90816 5.07555 5.24489 4.74066C5.58163 4.40576 5.97719 4.15567 6.43158 3.99037L5.4 1.49634C4.60937 1.79587 3.91932 2.24037 3.32984 2.82984C2.74037 3.41932 2.29587 4.10937 1.99634 4.9L4.49037 5.93158ZM7.49834 9.09724C8.08045 9.09724 8.57579 8.8935 8.98437 8.48603C9.39295 8.07855 9.59724 7.58376 9.59724 7.00166C9.59724 6.41955 9.3935 5.92421 8.98603 5.51563C8.57855 5.10705 8.08376 4.90276 7.50166 4.90276C6.91955 4.90276 6.42421 5.1065 6.01563 5.51397C5.60705 5.92145 5.40276 6.41624 5.40276 6.99834C5.40276 7.58045 5.6065 8.07579 6.01397 8.48437C6.42145 8.89295 6.91624 9.09724 7.49834 9.09724ZM9.63684 12.4895C10.4105 12.1947 11.089 11.7557 11.6724 11.1724C12.2557 10.589 12.6947 9.91053 12.9895 9.13684L10.5238 8.05424C10.368 8.50862 10.1209 8.90302 9.78274 9.23742C9.44453 9.57182 9.05203 9.82923 8.60526 10.0096L9.63684 12.4895ZM10.5096 5.89474L12.9895 4.86316C12.6947 4.08947 12.2557 3.41096 11.6724 2.82763C11.089 2.2443 10.4105 1.80526 9.63684 1.51053L8.60526 4.01303C9.04258 4.18299 9.4242 4.43051 9.75013 4.75558C10.0761 5.08053 10.3292 5.46025 10.5096 5.89474Z"
fill="currentColor"/>
</g>
<defs>
<clipPath id="clip0_1665_1656">
<rect width="14" height="14" fill="white"
transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>
}
export default HelpIcon;

View File

@@ -1,12 +1,13 @@
import React from 'react'; import React from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { intersection } from 'ramda'; import { intersection, is } from 'ramda';
// store // store
import { useStore } from '../../../../store'; import { useStore } from '../../../../store';
// components // components
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import HelpIcon from '../../../../icons/HelpIcon';
const AppSidebar = () => { const AppSidebar = () => {
const permissions = useStore().main.getPermissions(); const permissions = useStore().main.getPermissions();
@@ -54,32 +55,39 @@ const AppSidebar = () => {
id: 6, id: 6,
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
}, },
{
label: __('Soccorso Istruttorio', 'gepafin'),
icon: <HelpIcon/>,
href: '/soccorso-istruttorio',
id: 7,
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
},
{ {
label: __('Gestione Utenti', 'gepafin'), label: __('Gestione Utenti', 'gepafin'),
icon: 'pi pi-users', icon: 'pi pi-users',
href: '/utenti', href: '/utenti',
id: 7, id: 8,
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
}, },
{ {
label: __('Configurazione', 'gepafin'), label: __('Configurazione', 'gepafin'),
icon: 'pi pi-cog', icon: 'pi pi-cog',
//href: '/configurazione', //href: '/configurazione',
id: 8, id: 9,
enable: false enable: false
}, },
{ {
label: __('Report e Analisi', 'gepafin'), label: __('Report e Analisi', 'gepafin'),
icon: 'pi pi-chart-bar', icon: 'pi pi-chart-bar',
//href: '/stats', //href: '/stats',
id: 9, id: 10,
enable: false enable: false
}, },
{ {
label: __('Log di Sistema', 'gepafin'), label: __('Log di Sistema', 'gepafin'),
icon: 'pi pi-receipt', icon: 'pi pi-receipt',
clickFn: () => {}, clickFn: () => {},
id: 10, id: 11,
enable: false enable: false
} }
] ]
@@ -91,11 +99,15 @@ const AppSidebar = () => {
.map(o => <li key={o.id}> .map(o => <li key={o.id}>
{o.href {o.href
? <NavLink to={o.href}> ? <NavLink to={o.href}>
<i className={o.icon}></i> {is(String, o.icon)
? <i className={o.icon}></i>
: o.icon}
<span>{o.label}</span> <span>{o.label}</span>
</NavLink> </NavLink>
: <button onClick={() => {}}> : <button onClick={() => {}}>
<i className={o.icon}></i> {is(String, o.icon)
? <i className={o.icon}></i>
: o.icon}
<span>{o.label}</span> <span>{o.label}</span>
</button>} </button>}
</li>)} </li>)}

View File

@@ -1,8 +1,9 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { useParams, useNavigate } from 'react-router-dom'; import { useParams, useNavigate } from 'react-router-dom';
import { is, isEmpty, isNil } from 'ramda'; import { isEmpty } from 'ramda';
import { classNames } from 'primereact/utils'; import { classNames } from 'primereact/utils';
import { klona } from 'klona';
// components // components
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
@@ -15,6 +16,8 @@ import FormsService from '../../service/forms-service';
import { storeSet } from '../../store'; import { storeSet } from '../../store';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import BandoService from '../../service/bando-service'; import BandoService from '../../service/bando-service';
import uniqid from '../../helpers/uniqid';
import { Toast } from 'primereact/toast';
const BandoForms = () => { const BandoForms = () => {
const { id } = useParams(); const { id } = useParams();
@@ -22,8 +25,10 @@ const BandoForms = () => {
const [templates, setTemplates] = useState(null); const [templates, setTemplates] = useState(null);
const [selectedTemplate, setSelectedTemplate] = useState(null); const [selectedTemplate, setSelectedTemplate] = useState(null);
const [selectedForm, setSelectedForm] = useState(null); const [selectedForm, setSelectedForm] = useState(null);
const [selectedForDuplicateForm, setSelectedForDuplicateForm] = useState(null);
const [forms, setForms] = useState([]); const [forms, setForms] = useState([]);
const [bandoStatus, setBandoStatus] = useState(''); const [bandoStatus, setBandoStatus] = useState('');
const toast = useRef(null);
const doCreateNewForm = () => { const doCreateNewForm = () => {
navigate(`/bandi/${id}/forms/new`); navigate(`/bandi/${id}/forms/new`);
@@ -43,10 +48,73 @@ const BandoForms = () => {
} }
} }
const goToEditFormFromTemplate = () => { const doDuplicateForm = () => {
console.log('goToEditFormFromTemplate', selectedTemplate) const selectedFormArr = forms.filter(o => o.value === selectedForDuplicateForm);
//navigate(`/bandi/${id}`);
if (!isEmpty(selectedFormArr)) {
storeSet.main.setAsyncRequest();
FormsService.getFormById(selectedForDuplicateForm, getFormCallback, errGetFormCallbacks);
} }
}
const getFormCallback = (data) => {
if (data.status === 'SUCCESS') {
const newLabel = `${data.data.label} (copy)`;
const formData = {
label: newLabel,
content: data.data.content.map(o => ({
...o,
id: uniqid()
}))
}
FormsService.createFormForCall(
id,
formData,
formCreateCallback,
errFormCreateCallback
);
}
}
const errGetFormCallbacks = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const formCreateCallback = (data) => {
if (data.status === 'SUCCESS') {
storeSet.main.unsetAsyncRequest();
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: __('Il form è stato aggiornato corretamente!', 'gepafin')
});
}
setTimeout(() => {
navigate(`/bandi/${id}/forms/${data.data.id}`);
}, 1000)
}
}
const errFormCreateCallback = (data) => {
storeSet.main.unsetAsyncRequest();
if (toast.current) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
}
/*const goToEditFormFromTemplate = () => {
console.log('goToEditFormFromTemplate', selectedTemplate)
}*/
const getCallback = (data) => { const getCallback = (data) => {
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
@@ -78,7 +146,7 @@ const BandoForms = () => {
const bandoId = !isNaN(parsed) ? parsed : 0; const bandoId = !isNaN(parsed) ? parsed : 0;
setTemplates([ setTemplates([
{label: "Form template", value: 11} { label: 'Form template', value: 11 }
]) ])
storeSet.main.setAsyncRequest(); storeSet.main.setAsyncRequest();
@@ -96,6 +164,7 @@ const BandoForms = () => {
</div> </div>
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>
<Toast ref={toast} />
<div className="appPage__content"> <div className="appPage__content">
@@ -124,16 +193,32 @@ const BandoForms = () => {
<div className="appPageSection__withBorder"> <div className="appPageSection__withBorder">
<h2>{__('Crea un nuovo Form da Zero', 'gepafin')}</h2> <h2>{__('Crea un nuovo Form da Zero', 'gepafin')}</h2>
<div className="row"> <div className="row">
<p>{__('Inizia con un form completamente vuoto e personalizzabil', 'gepafin')}</p> <p>{__('Inizia con un form completamente vuoto e personalizzabile', 'gepafin')}</p>
<Button <Button
type="button" type="button"
disabled={'PUBLISH' === bandoStatus} disabled={'PUBLISH' === bandoStatus}
onClick={doCreateNewForm} onClick={doCreateNewForm}
label={__('Crea form', 'gepafin')}/> label={__('Crea form', 'gepafin')}/>
</div> </div>
<div className="row">
<p>{__('Duplica il form creato in precedenza', 'gepafin')}</p>
<Dropdown
id="form"
disabled={isEmpty(forms)}
value={selectedForDuplicateForm}
onChange={(e) => setSelectedForDuplicateForm(e.value)}
options={forms}
optionLabel="label"
placeholder={__('Seleziona form', 'gepafin')}/>
<Button
type="button"
disabled={'PUBLISH' === bandoStatus || isEmpty(forms)}
onClick={doDuplicateForm}
label={__('Duplicare', 'gepafin')}/>
</div>
</div> </div>
<div className={classNames(["appPageSection__withBorder", (isEmpty(forms) ? 'disabled' : '')])}> <div className={classNames(['appPageSection__withBorder', (isEmpty(forms) ? 'disabled' : '')])}>
<h2>{__('Modifica form esistente', 'gepafin')}</h2> <h2>{__('Modifica form esistente', 'gepafin')}</h2>
<div className="row"> <div className="row">
<p>{__('Continua a lavorare su un form precedentemente salvato', 'gepafin')}</p> <p>{__('Continua a lavorare su un form precedentemente salvato', 'gepafin')}</p>

View File

@@ -50,7 +50,6 @@ 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.callEndDate = is(String, d.callEndDate) ? new Date(d.callEndDate) : (d.callEndDate ? d.callEndDate : '');
d.updatedDate = is(String, d.updatedDate) ? new Date(d.updatedDate) : (d.updatedDate ? d.updatedDate : '');
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;
}); });
@@ -89,7 +88,7 @@ const PreInstructorDomandeTable = () => {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}, },
updatedDate : { callEndDate : {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
} }
@@ -114,8 +113,7 @@ const PreInstructorDomandeTable = () => {
}; };
const dateEndBodyTemplate = (rowData) => { const dateEndBodyTemplate = (rowData) => {
//return formatDate(rowData.callEndDate); return formatDate(rowData.callEndDate);
return '';
}; };
const dateFilterTemplate = (options) => { const dateFilterTemplate = (options) => {
@@ -156,7 +154,7 @@ const PreInstructorDomandeTable = () => {
<Column field="callName" header={__('Bando', 'gepafin')} <Column field="callName" header={__('Bando', 'gepafin')}
filter filterPlaceholder={__('Cerca', 'gepafin')} filter filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '12rem' }}/> style={{ minWidth: '12rem' }}/>
<Column header={__('Data Ricezione', 'gepafin')} filterField="modifiedDate" dataType="date" <Column header={__('Data Ricezione', 'gepafin')} filterField="submissionDate" dataType="date"
style={{ minWidth: '10rem' }} style={{ minWidth: '10rem' }}
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')} filterField="callEndDate" dataType="date" <Column header={__('Scadenza', 'gepafin')} filterField="callEndDate" dataType="date"

View File

@@ -1,60 +1,69 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { __, sprintf } from '@wordpress/i18n'; import { __, sprintf } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { is, isEmpty, isNil } from 'ramda'; import { is, isEmpty, isNil, sum, pathOr } from 'ramda';
import { klona } from 'klona';
import { wrap } from 'object-path-immutable';
// store // store
import { storeSet, useStore } from '../../store'; import { storeSet, useStore } from '../../store';
// api
import ApplicationEvaluationService from '../../service/application-evaluation-service';
// tools // tools
//import getNumberWithCurrency from '../../helpers/getNumberWithCurrency'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
//import getDateFromISOstring from '../../helpers/getDateFromISOstring'; import getBandoLabel from '../../helpers/getBandoLabel';
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
// components // components
import { Skeleton } from 'primereact/skeleton'; import { Skeleton } from 'primereact/skeleton';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
import { Tag } from 'primereact/tag'; import { Tag } from 'primereact/tag';
import { Checkbox } from 'primereact/checkbox'; import { Checkbox } from 'primereact/checkbox';
import { Editor } from 'primereact/editor'; import { Editor } from 'primereact/editor';
import { InputNumber } from 'primereact/inputnumber';
import BlockingOverlay from '../../components/BlockingOverlay';
import { Toast } from 'primereact/toast';
import HelpIcon from '../../icons/HelpIcon';
const DomandaEdit = () => { const DomandaEditPreInstructor = () => {
const isAsyncRequest = useStore().main.isAsyncRequest(); const isAsyncRequest = useStore().main.isAsyncRequest();
const { id } = useParams(); const { id } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const [data, setData] = useState({}); const [data, setData] = useState({});
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
const pageMsgs = useRef(null); const [isAdmissible, setIsAdmissible] = useState(false);
const toast = useRef(null);
const goToEvaluationsPage = () => { const goToEvaluationsPage = () => {
navigate('/domande'); navigate('/domande');
} }
/*const getCallback = (data) => { const getCallback = (data) => {
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
setData(getFormattedBandiData(data.data)); setData(getFormattedData(data.data));
} }
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
} }
const errGetCallback = (data) => { const errGetCallback = (data) => {
if (pageMsgs.current && data.message) { if (toast.current && data.message) {
pageMsgs.current.show([ toast.current.show({
{ severity: 'error',
sticky: true, severity: 'error', summary: '', summary: '',
detail: data.message, detail: data.message
closable: true });
}
]);
} }
set404FromErrorResponse(data); set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
}*/ }
/*const getFormattedBandiData = (data) => { const getFormattedData = (data) => {
data.dates = data.dates.map(v => is(String, v) ? new Date(v) : (v ? v : '')); data.submissionDate = is(String, data.submissionDate) ? new Date(data.submissionDate) : (data.submissionDate ? data.submissionDate : '');
data.evaluationDate = is(String, data.evaluationDate) ? new Date(data.evaluationDate) : (data.evaluationDate ? data.evaluationDate : '');
return data; return data;
};*/ };
const renderHeader = () => { const renderHeader = () => {
return ( return (
@@ -76,58 +85,69 @@ const DomandaEdit = () => {
const header = renderHeader(); const header = renderHeader();
const updateEvaluationValue = (value, path, maxValue) => {
let finalValue = value;
if (maxValue) {
finalValue = value > maxValue ? maxValue : value;
}
const newData = wrap(data).set(path.split('.'), finalValue).value();
setData(newData);
}
const doSaveDraft = () => {
const formData = {
criteria: klona(data.criteria),
checklist: klona(data.checklist),
files: klona(data.files),
note: data.note
}
ApplicationEvaluationService.updateEvaluation(id, formData, updateCallback, errUpdateCallback);
}
const updateCallback = (data) => {
if (data.status === 'SUCCESS') {
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: data.message
});
}
}
storeSet.main.unsetAsyncRequest();
}
const errUpdateCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
useEffect(() => {
const maxScore = pathOr(0, ['minScore'], data);
const criteria = pathOr([], ['criteria'], data);
const scoreSum = sum(criteria.map(o => o.score));
setIsAdmissible(scoreSum !== 0 && scoreSum >= maxScore);
}, [data]);
useEffect(() => { useEffect(() => {
const parsed = parseInt(id) const parsed = parseInt(id)
const entityId = !isNaN(parsed) ? parsed : 0; const entityId = !isNaN(parsed) ? parsed : 0;
setData({ ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [
id: 'DOM_2024_001', ['assignedApplicationId', entityId]
callTitle: 'Innovazione 2024', ]);
beneficiario: 'Azienda Alpha SRL',
createdAt: '2024-08-01',
scadenzaAt: '2024-08-05',
status: 'In Valutazione',
criteria: [
{ title: 'Innovatività del progetto', score: 25, id: 12 },
{ title: 'Innovatività del progetto2', score: 35, id: 13 },
{ title: 'Innovatività del progetto3', score: 15, id: 14 }
],
minScore: 60
});
//BandoService.getBando(entityId, getCallback, errGetCallback);
}, [id]); }, [id]);
// TODO
const checklist = [
{
id: 1,
title: 'Requisiti di ammissibilità soddisfatti'
},
{
id: 2,
title: 'Documentazione completa'
},
{
id: 3,
title: 'Obiettivi del progetto chiari e misurabili'
}
];
const documents = [
{
id: 1,
title: 'Doc 1'
},
{
id: 2,
title: 'Bilancio ultimo esercizio Bilancio ultimo esercizio Bilancio ultimo esercizio'
},
{
id: 3,
title: 'Bilancio ultimo esercizio'
}
];
return ( return (
<div className="appPage"> <div className="appPage">
<div className="appPage__pageHeader"> <div className="appPage__pageHeader">
@@ -135,7 +155,8 @@ const DomandaEdit = () => {
</div> </div>
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>
<Messages ref={pageMsgs}/> <Toast ref={toast}/>
<BlockingOverlay shouldDisplay={isAsyncRequest}/>
<div className="appPageSection__row"> <div className="appPageSection__row">
<Button <Button
@@ -153,27 +174,27 @@ const DomandaEdit = () => {
<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.id}</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.callTitle}</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.beneficiario}</span> <span>{data.beneficiary}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Data ricezione', 'gepafin')}</span> <span>{__('Data ricezione', 'gepafin')}</span>
<span>{data.createdAt}</span> <span>{getDateFromISOstring(data.submissionDate)}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Scadenza Valutazione', 'gepafin')}</span> <span>{__('Scadenza Valutazione', 'gepafin')}</span>
<span>{data.scadenzaAt}</span> <span>{getDateFromISOstring(data.callEndDate)}</span>
</p> </p>
<p className="appPageSection__pMeta"> <p className="appPageSection__pMeta">
<span>{__('Stato', 'gepafin')}</span> <span>{__('Stato', 'gepafin')}</span>
<span>{data.status}</span> <span>{getBandoLabel(data.applicationStatus)}</span>
</p> </p>
</div> </div>
@@ -184,29 +205,63 @@ const DomandaEdit = () => {
<thead className="myThead"> <thead className="myThead">
<tr> <tr>
<th>{__('Parametro', 'gepafin')}</th> <th>{__('Parametro', 'gepafin')}</th>
<th>{__('Punteggio', 'gepafin')}</th> <th style={{ width: 200 }}>{__('Punteggio', 'gepafin')}</th>
<th>{__('Stato', 'gepafin')}</th> <th style={{ width: 220 }}>{__('Stato', 'gepafin')}</th>
</tr> </tr>
</thead> </thead>
<tbody className="myTbody"> <tbody className="myTbody">
{data.criteria.map(o => <tr key={o.id}> {data.criteria.map((o, i) => <tr key={o.id}>
<td>{o.title}</td> <td>{o.label}</td>
<td>{o.score}</td> <td>
<div className="p-inputgroup">
<InputNumber
placeholder={__('Punteggio', 'gepafin')}
keyfilter="int"
value={o.score}
max={o.maxScore}
onChange={(e) => updateEvaluationValue(
e.value,
`criteria.${i}.score`,
o.maxScore
)}/>
<span className="p-inputgroup-addon">
/ {o.maxScore}
</span>
</div>
</td>
<td> <td>
<div className="appPageSection__iconActions"> <div className="appPageSection__iconActions">
<Button icon="pi pi-eye" rounded outlined severity="info" {!isEmpty(o.criteriaMappedFields)
aria-label={__('Mostra', 'gepafin')}/> ? <Button icon="pi pi-eye" rounded outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/> : null}
<Button icon="pi pi-thumbs-up" rounded outlined <Button icon="pi pi-thumbs-up" rounded outlined
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
onClick={() => updateEvaluationValue(
true,
`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
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
onClick={() => updateEvaluationValue(
false,
`criteria.${i}.valid`
)}
aria-label={__('Giu', 'gepafin')}/> aria-label={__('Giu', 'gepafin')}/>
</div> </div>
</td> </td>
</tr>)} </tr>)}
<tr> <tr>
<td>{__('Punteggio:', 'gepafin')}</td> <td>{__('Punteggio:', 'gepafin')}</td>
<td>{68}</td> <td>{sum(data.criteria.map(o => o.score))}</td>
<td><Tag icon="pi pi-check" severity="success" value={__('Ammissibile')}></Tag></td> <td>
{isAdmissible
? <Tag icon="pi pi-check" severity="success"
value={__('Ammissibile')}></Tag> : null}
{!isAdmissible
? <Tag icon="pi pi-times" severity="warning"
value={__('Inammissibile')}></Tag> : null}
</td>
</tr> </tr>
</tbody> </tbody>
<tfoot className="myTfoot"> <tfoot className="myTfoot">
@@ -224,12 +279,15 @@ const DomandaEdit = () => {
<h3>{__('Lista', 'gepafin')}</h3> <h3>{__('Lista', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey"> <div className="appPageSection__withBorder grey">
<div className="appPageSection__checklist"> <div className="appPageSection__checklist">
{checklist.map(o => <div key={o.id}> {data.checklist.map((o, i) => <div key={o.id}>
<Checkbox <Checkbox
inputId={`checklist_${o.id}`} inputId={`checklist_${o.id}`}
onChange={(e) => console.log(e.checked)} onChange={(e) => updateEvaluationValue(
checked={false}></Checkbox> e.checked,
<label htmlFor={`checklist_${o.id}`}>{o.title}</label> `checklist.${i}.valid`
)}
checked={o.valid}></Checkbox>
<label htmlFor={`checklist_${o.id}`}>{o.label}</label>
</div>)} </div>)}
</div> </div>
</div> </div>
@@ -237,10 +295,13 @@ const DomandaEdit = () => {
<h3>{__('Note', 'gepafin')}</h3> <h3>{__('Note', 'gepafin')}</h3>
<div> <div>
<Editor <Editor
value={message} value={data.note}
placeholder={__('Digita qui il messagio', 'gepafin')} placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header} headerTemplate={header}
onTextChange={(e) => setMessage(e.htmlValue)} onTextChange={(e) => updateEvaluationValue(
e.htmlValue,
'note'
)}
style={{ height: 80 * 3, width: '100%' }} style={{ height: 80 * 3, width: '100%' }}
/> />
</div> </div>
@@ -248,14 +309,27 @@ const DomandaEdit = () => {
<div> <div>
<h3>{__('Documenti allegati', 'gepafin')}</h3> <h3>{__('Documenti allegati', 'gepafin')}</h3>
<ol className="appPageSection__list"> <ol className="appPageSection__list">
{documents.map(o => <li key={o.id}> {data.files.map((o, i) => <li key={o.id}>
<span>{o.title}</span> <span>{o.label}</span>
<div className="appPageSection__iconActions"> <div className="appPageSection__iconActions">
<Button icon="pi pi-eye" rounded outlined severity="info" {o.fileDetail.length === 1
aria-label={__('Mostra', 'gepafin')}/> ? <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 <Button icon="pi pi-thumbs-up" rounded outlined
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
onClick={() => updateEvaluationValue(
true,
`files.${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
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
onClick={() => updateEvaluationValue(
false,
`files.${i}.valid`
)}
aria-label={__('Giu', 'gepafin')}/> aria-label={__('Giu', 'gepafin')}/>
</div> </div>
</li>)} </li>)}
@@ -278,30 +352,19 @@ const DomandaEdit = () => {
label={<> label={<>
{__('Richiedi Soccorso Istruttorio', 'gepafin')} {__('Richiedi Soccorso Istruttorio', 'gepafin')}
<i style={{ marginLeft: 7 }}> <i style={{ marginLeft: 7 }}>
<svg width="15" height="14" viewBox="0 0 15 14" fill="none" <HelpIcon/>
xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1665_1656)">
<path
d="M7.50129 14C6.53308 14 5.62302 13.8163 4.7711 13.4488C3.91919 13.0814 3.17818 12.5827 2.54805 11.9529C1.91793 11.323 1.41903 10.5823 1.05134 9.73074C0.683781 8.87919 0.5 7.96938 0.5 7.00129C0.5 6.03308 0.683719 5.12302 1.05116 4.2711C1.4186 3.41919 1.91725 2.67818 2.54713 2.04805C3.17701 1.41793 3.91772 0.919026 4.76926 0.551342C5.62081 0.183781 6.53062 0 7.49871 0C8.46692 0 9.37698 0.183719 10.2289 0.551158C11.0808 0.918596 11.8218 1.41725 12.4519 2.04713C13.0821 2.67701 13.581 3.41772 13.9487 4.26926C14.3162 5.12081 14.5 6.03062 14.5 6.99871C14.5 7.96692 14.3163 8.87698 13.9488 9.72889C13.5814 10.5808 13.0827 11.3218 12.4529 11.9519C11.823 12.5821 11.0823 13.081 10.2307 13.4487C9.37919 13.8162 8.46938 14 7.50129 14ZM5.36316 12.4895L6.44576 10.0238C5.98585 9.86147 5.58888 9.60977 5.25484 9.26874C4.92081 8.92758 4.66598 8.52747 4.49037 8.06842L1.99634 9.1C2.28359 9.88596 2.72195 10.5737 3.31142 11.1632C3.90089 11.7526 4.58481 12.1947 5.36316 12.4895ZM4.49037 5.93158C4.65665 5.47253 4.90816 5.07555 5.24489 4.74066C5.58163 4.40576 5.97719 4.15567 6.43158 3.99037L5.4 1.49634C4.60937 1.79587 3.91932 2.24037 3.32984 2.82984C2.74037 3.41932 2.29587 4.10937 1.99634 4.9L4.49037 5.93158ZM7.49834 9.09724C8.08045 9.09724 8.57579 8.8935 8.98437 8.48603C9.39295 8.07855 9.59724 7.58376 9.59724 7.00166C9.59724 6.41955 9.3935 5.92421 8.98603 5.51563C8.57855 5.10705 8.08376 4.90276 7.50166 4.90276C6.91955 4.90276 6.42421 5.1065 6.01563 5.51397C5.60705 5.92145 5.40276 6.41624 5.40276 6.99834C5.40276 7.58045 5.6065 8.07579 6.01397 8.48437C6.42145 8.89295 6.91624 9.09724 7.49834 9.09724ZM9.63684 12.4895C10.4105 12.1947 11.089 11.7557 11.6724 11.1724C12.2557 10.589 12.6947 9.91053 12.9895 9.13684L10.5238 8.05424C10.368 8.50862 10.1209 8.90302 9.78274 9.23742C9.44453 9.57182 9.05203 9.82923 8.60526 10.0096L9.63684 12.4895ZM10.5096 5.89474L12.9895 4.86316C12.6947 4.08947 12.2557 3.41096 11.6724 2.82763C11.089 2.2443 10.4105 1.80526 9.63684 1.51053L8.60526 4.01303C9.04258 4.18299 9.4242 4.43051 9.75013 4.75558C10.0761 5.08053 10.3292 5.46025 10.5096 5.89474Z"
fill="#3B7C43"/>
</g>
<defs>
<clipPath id="clip0_1665_1656">
<rect width="14" height="14" fill="white"
transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>
</i> </i>
</>} </>}
/> />
<Button <Button
type="button" type="button"
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"
disabled={!isAdmissible}
label={__('Approva Domanda', 'gepafin')} label={__('Approva Domanda', 'gepafin')}
icon="pi pi-check" iconPos="right"/> icon="pi pi-check" iconPos="right"/>
<Button <Button
@@ -327,4 +390,4 @@ const DomandaEdit = () => {
} }
export default DomandaEdit; export default DomandaEditPreInstructor;

View File

@@ -84,7 +84,7 @@ const AllDomandeTable = ({ openDialogFn }) => {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
}, },
appliedDate: { submissionDate: {
operator: FilterOperator.AND, operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}, },
@@ -152,7 +152,7 @@ const AllDomandeTable = ({ openDialogFn }) => {
filter filterPlaceholder={__('Cerca', 'gepafin')} filter filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '12rem' }}/> style={{ minWidth: '12rem' }}/>
<Column header={__('Data Ricezione', 'gepafin')} <Column header={__('Data Ricezione', 'gepafin')}
filterField="modifiedDate" dataType="date" filterField="submissionDate" dataType="date"
style={{ minWidth: '10rem' }} style={{ minWidth: '10rem' }}
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/> body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')} <Column header={__('Scadenza', 'gepafin')}

View File

@@ -0,0 +1,385 @@
import React, { useState, useEffect, useRef } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { is, isEmpty, isNil, sum, pathOr } from 'ramda';
import { klona } from 'klona';
import { wrap } from 'object-path-immutable';
// store
import { storeSet, useStore } from '../../store';
// api
import ApplicationEvaluationService from '../../service/application-evaluation-service';
// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import getBandoLabel from '../../helpers/getBandoLabel';
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
// components
import { Skeleton } from 'primereact/skeleton';
import { Button } from 'primereact/button';
import { Tag } from 'primereact/tag';
import { Checkbox } from 'primereact/checkbox';
import { Editor } from 'primereact/editor';
import { InputNumber } from 'primereact/inputnumber';
import BlockingOverlay from '../../components/BlockingOverlay';
import { Toast } from 'primereact/toast';
import HelpIcon from '../../icons/HelpIcon';
const SoccorsoEditPreInstructor = () => {
const isAsyncRequest = useStore().main.isAsyncRequest();
const { id, soccorsoId } = useParams();
const navigate = useNavigate();
const [data, setData] = useState({});
const toast = useRef(null);
const goToEvaluationPage = () => {
//navigate('/domande');
}
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data));
}
storeSet.main.unsetAsyncRequest();
}
const errGetCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const getFormattedData = (data) => {
data.submissionDate = is(String, data.submissionDate) ? new Date(data.submissionDate) : (data.submissionDate ? data.submissionDate : '');
data.evaluationDate = is(String, data.evaluationDate) ? new Date(data.evaluationDate) : (data.evaluationDate ? data.evaluationDate : '');
return data;
};
const renderHeader = () => {
return (
<span className="ql-formats">
<button className="ql-bold" aria-label="Bold"></button>
<button className="ql-italic" aria-label="Italic"></button>
<button className="ql-underline" aria-label="Underline"></button>
<button className="ql-link" aria-label="Link"></button>
<button className="ql-list" value="ordered"></button>
<button className="ql-header" value="2"></button>
<button className="ql-header" value="3"></button>
<button className="ql-blockquote"></button>
<button className="ql-list" value="bullet"></button>
<button className="ql-indent" value="-1"></button>
<button className="ql-indent" value="+1"></button>
</span>
);
};
const header = renderHeader();
const updateEvaluationValue = (value, path, maxValue) => {
let finalValue = value;
if (maxValue) {
finalValue = value > maxValue ? maxValue : value;
}
const newData = wrap(data).set(path.split('.'), finalValue).value();
setData(newData);
}
/*const doSaveDraft = () => {
const formData = {
criteria: klona(data.criteria),
checklist: klona(data.checklist),
files: klona(data.files),
note: data.note
}
ApplicationEvaluationService.updateEvaluation(id, formData, updateCallback, errUpdateCallback);
}
const updateCallback = (data) => {
if (data.status === 'SUCCESS') {
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: data.message
});
}
}
storeSet.main.unsetAsyncRequest();
}
const errUpdateCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}*/
useEffect(() => {
const parsed = parseInt(id)
const assignedCallId = !isNaN(parsed) ? parsed : 0;
const parsedSoccorsoId = parseInt(soccorsoId)
const soccorsoEntityId = !isNaN(parsedSoccorsoId) ? parsedSoccorsoId : 0;
ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [
['assignedApplicationId', assignedCallId]
]);
}, [id, soccorsoId]);
return (
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Soccorso Istruttorio - Dettagli', 'gepafin')}</h1>
</div>
<div className="appPage__spacer"></div>
<Toast ref={toast}/>
<BlockingOverlay shouldDisplay={isAsyncRequest}/>
<div className="appPageSection__row">
<Button
type="button"
outlined
onClick={goToEvaluationPage}
label={__('Indietro', 'gepafin')}
icon="pi pi-arrow-left" iconPos="left"/>
</div>
<div className="appPage__spacer"></div>
{!isAsyncRequest && !isEmpty(data)
? <div className="appPage__content">
<div className="appPageSection__withBorder columns">
<p className="appPageSection__pMeta">
<span>{__('ID domanda', 'gepafin')}</span>
<span>{data.applicationId}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Bando', 'gepafin')}</span>
<span>{data.callName}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Beneficiario', 'gepafin')}</span>
<span>{data.beneficiary}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Data ricezione', 'gepafin')}</span>
<span>{getDateFromISOstring(data.submissionDate)}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Scadenza Valutazione', 'gepafin')}</span>
<span>{getDateFromISOstring(data.callEndDate)}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Stato', 'gepafin')}</span>
<span>{getBandoLabel(data.applicationStatus)}</span>
</p>
</div>
<div className="appPageSection">
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
{data.criteria
? <table className="myTable">
<thead className="myThead">
<tr>
<th>{__('Parametro', 'gepafin')}</th>
<th style={{ width: 200 }}>{__('Punteggio', 'gepafin')}</th>
<th style={{ width: 220 }}>{__('Stato', 'gepafin')}</th>
</tr>
</thead>
<tbody className="myTbody">
{data.criteria.map((o, i) => <tr key={o.id}>
<td>{o.label}</td>
<td>
<div className="p-inputgroup">
<InputNumber
placeholder={__('Punteggio', 'gepafin')}
keyfilter="int"
value={o.score}
max={o.maxScore}
onChange={(e) => updateEvaluationValue(
e.value,
`criteria.${i}.score`,
o.maxScore
)}/>
<span className="p-inputgroup-addon">
/ {o.maxScore}
</span>
</div>
</td>
<td>
<div className="appPageSection__iconActions">
{!isEmpty(o.criteriaMappedFields)
? <Button icon="pi pi-eye" rounded outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/> : null}
<Button icon="pi pi-thumbs-up" rounded outlined
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
onClick={() => updateEvaluationValue(
true,
`criteria.${i}.valid`
)}
aria-label={__('Su', 'gepafin')}/>
<Button icon="pi pi-thumbs-down" rounded outlined
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
onClick={() => updateEvaluationValue(
false,
`criteria.${i}.valid`
)}
aria-label={__('Giu', 'gepafin')}/>
</div>
</td>
</tr>)}
<tr>
<td>{__('Punteggio:', 'gepafin')}</td>
<td>{sum(data.criteria.map(o => o.score))}</td>
<td>
{isAdmissible
? <Tag icon="pi pi-check" severity="success"
value={__('Ammissibile')}></Tag> : null}
{!isAdmissible
? <Tag icon="pi pi-times" severity="warning"
value={__('Inammissibile')}></Tag> : null}
</td>
</tr>
</tbody>
<tfoot className="myTfoot">
<tr>
<td colSpan="3">{sprintf(__('Punteggio minimo per l\'ammissione: %d'), data.minScore)}</td>
</tr>
</tfoot>
</table> : null}
</div>
<div className="appPageSection">
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
<div className="appPageSection columns">
<div>
<h3>{__('Lista', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey">
<div className="appPageSection__checklist">
{data.checklist.map((o, i) => <div key={o.id}>
<Checkbox
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}
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}>
<span>{o.label}</span>
<div className="appPageSection__iconActions">
{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
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
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
onClick={() => updateEvaluationValue(
false,
`files.${i}.valid`
)}
aria-label={__('Giu', 'gepafin')}/>
</div>
</li>)}
</ol>
</div>
</div>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection__hr">
<span>{__('Azioni rapide', 'gepafin')}</span>
</div>
<div className="appPageSection">
<div className="appPageSection__actions">
<Button
type="button"
outlined
label={<>
{__('Richiedi Soccorso Istruttorio', 'gepafin')}
<i style={{ marginLeft: 7 }}>
<HelpIcon/>
</i>
</>}
/>
<Button
type="button"
onClick={doSaveDraft}
outlined
label={__('Salva Bozza Valutazione', 'gepafin')}
icon="pi pi-save" iconPos="right"/>
<Button
type="button"
disabled={!isAdmissible}
label={__('Approva Domanda', 'gepafin')}
icon="pi pi-check" iconPos="right"/>
<Button
type="button"
label={__('Respingi Domanda', 'gepafin')}
icon="pi pi-times" iconPos="right"/>
</div>
</div>
</div>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="4rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="4rem"></Skeleton>
</>}
</div>
)
}
export default SoccorsoEditPreInstructor;

View File

@@ -0,0 +1,171 @@
import React, { useState, useEffect} from 'react';
import { __ } from '@wordpress/i18n';
import { is, uniq } from 'ramda';
import { Link } from 'react-router-dom';
// store
//import { storeSet, storeGet } from '../../../../store';
// api
import ApplicationService from '../../../../service/application-service';
// components
import { FilterMatchMode, FilterOperator } from 'primereact/api';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]);
useEffect(() => {
setLocalAsyncRequest(true);
ApplicationService.getApplications(getCallback, errGetCallbacks, [['status', 'SUBMIT']]);
}, []);
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setItems(getFormattedData(data.data));
setStatuses(uniq(data.data.map(o => o.status)))
initFilters();
}
setLocalAsyncRequest(false);
}
const errGetCallbacks = (data) => {
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 formatDate = (value) => {
return value.toLocaleDateString('it-IT', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
};
const clearFilter = () => {
initFilters();
};
const onGlobalFilterChange = (e) => {
const value = e.target.value;
let _filters = { ...filters };
_filters['global'].value = value;
setFilters(_filters);
setGlobalFilterValue(value);
};
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
callTitle: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
submissionDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
callEndDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
}
});
setGlobalFilterValue('');
};
const renderHeader = () => {
return (
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
<IconField iconPosition="left">
<InputIcon className="pi pi-search" />
<InputText value={globalFilterValue} onChange={onGlobalFilterChange} placeholder={__('Cerca', 'gepafin')} />
</IconField>
</div>
);
};
const dateAppliedBodyTemplate = (rowData) => {
return formatDate(rowData.submissionDate);
};
const dateEndBodyTemplate = (rowData) => {
return formatDate(rowData.callEndDate);
};
const dateFilterTemplate = (options) => {
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
};
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const actionsBodyTemplate = (rowData) => {
return openDialogFn
? <Button severity="info"
onClick={() => openDialogFn(rowData.id)}
label={__('Assegnare', 'gepafin')}
icon="pi pi-pencil" size="small" iconPos="right" />
: <Link to={'/domande'}>
<Button severity="info" label={__('Gestire', 'gepafin')} size="small" />
</Link>
}
const header = renderHeader();
return(
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
filters={filters}
globalFilterFields={['name', 'status']}
header={header}
emptyMessage={__('Nessun dato disponibile', 'gepafin')}
onFilter={(e) => setFilters(e.filters)}>
<Column field="id" header={__('ID domanda', 'gepafin')}
filter filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '12rem' }}/>
<Column field="callTitle" header={__('Bando', 'gepafin')}
filter filterPlaceholder={__('Cerca', 'gepafin')}
style={{ minWidth: '12rem' }}/>
<Column header={__('Data Ricezione', 'gepafin')}
filterField="submissionDate" dataType="date"
style={{ minWidth: '10rem' }}
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Scadenza', 'gepafin')}
filterField="callEndDate" dataType="date"
style={{ minWidth: '10rem' }}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="status" header={__('Stato', 'gepafin')}
style={{ width: '120px' }} body={statusBodyTemplate} />
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default PreInstructorSoccorsiTable;

View File

@@ -0,0 +1,23 @@
import React from 'react';
import { __ } from '@wordpress/i18n';
// components
import PreInstructorSoccorsiTable from './components/PreInstructorSoccorsiTable';
const SoccorsoIstruttorioPreInstructor = () => {
return(
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Soccorso Istruttorio', 'gepafin')}</h1>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<PreInstructorSoccorsiTable/>
</div>
</div>
)
}
export default SoccorsoIstruttorioPreInstructor;

View File

@@ -29,7 +29,9 @@ import DashboardPreInstructor from './pages/DashboardPreInstructor';
import ProfileBeneficiario from './pages/ProfileBeneficiario'; import ProfileBeneficiario from './pages/ProfileBeneficiario';
import Domande from './pages/Domande'; import Domande from './pages/Domande';
import DomandePreInstructor from './pages/DomandePreInstructor'; import DomandePreInstructor from './pages/DomandePreInstructor';
import DomandaEdit from './pages/DomandaEdit'; import DomandaEditPreInstructor from './pages/DomandaEditPreInstructor';
import SoccorsoIstruttorioPreInstructor from './pages/SoccorsoIstruttorioPreInstructor';
import SoccorsoEditPreInstructor from './pages/SoccorsoEditPreInstructor';
const routes = ({ role, chosenCompanyId }) => { const routes = ({ role, chosenCompanyId }) => {
@@ -89,7 +91,22 @@ const routes = ({ role, chosenCompanyId }) => {
<Route path="/domande/:id/" element={<DefaultLayout> <Route path="/domande/:id/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null} {'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null} {'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandaEdit/> : null} {'ROLE_PRE_INSTRUCTOR' === role ? <DomandaEditPreInstructor/> : null}
</DefaultLayout>}/>
<Route path="/domande/:id/soccorso/new" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoEditPreInstructor/> : null}
</DefaultLayout>}/>
<Route path="/soccorso-istruttorio/" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoIstruttorioPreInstructor/> : null}
</DefaultLayout>}/>
<Route path="/soccorso-istruttorio/:soccorsoId" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoEditPreInstructor/> : null}
</DefaultLayout>}/> </DefaultLayout>}/>
<Route path="/imieibandi" element={<DefaultLayout> <Route path="/imieibandi" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null} {'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}

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 ApplicationEvaluationService {
static getEvaluationByApplId = (callback, errCallback, queryParams) => {
NetworkService.get(`${API_BASE_URL}/applicationEvaluation/application`, callback, errCallback, queryParams);
};
static updateEvaluation = (id, body, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/applicationEvaluation/${id}`, body, 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 ApplicationEvaluationService {
static getEvaluationByApplId = (callback, errCallback, queryParams) => {
NetworkService.get(`${API_BASE_URL}/applicationEvaluation/application`, callback, errCallback, queryParams);
};
static updateEvaluation = (id, body, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/applicationEvaluation/${id}`, body, callback, errCallback, queryParams);
};
}