Backend (rendicontazione-api):
- 4 nuove colonne su remission_practice: assigned_instructor_id, reviewed_at,
reviewed_by, rejection_reason, approved_remission
- Nuova tabella remission_amendment_request (id, practice_id, request_text,
scope jsonb, deadline, status AWAITING/RESPONSE_RECEIVED/CLOSED/EXPIRED,
response_text, audit cols)
- Router instructor.py con 8 endpoint:
GET /instructor/queue (SUBMITTED pool + UNDER_REVIEW/AWAITING_AMENDMENT assigned,
o tutto se manager/superadmin)
GET /instructor/{id} (practice + gate_check + amendments)
POST /instructor/{id}/claim (SUBMITTED -> UNDER_REVIEW)
POST /instructor/{id}/approve (approved_remission opz, default = remission_due calcolato)
POST /instructor/{id}/reject (rejection_reason min 10 char)
POST /instructor/{id}/amendment (crea soccorso: request_text + deadline)
POST /instructor/{id}/amendment/{aid}/close (chiude soccorso, pratica torna UNDER_REVIEW)
POST /instructor/{id}/amendment/{aid}/respond-beneficiary (benef risponde)
- GET /{id} ora ritorna anche amendments (per beneficiario)
Frontend:
- Pagina IstruttoriaQueue (125 righe): coda pratiche con stato, istruttore
assegnato, erogato, remission_due calcolata, azioni contestuali
- Pagina IstruttoriaPratica (483 righe): dettaglio pratica readonly per istruttore,
riepilogo esteso, amendments panel con chiudi, gate check, fatture/ULA/docs,
3 Dialog per approva/respingi/soccorso
- PraticaRendicontazioneEdit esteso con sezione 'Richieste di soccorso istruttorio'
visibile al beneficiario + Dialog rispondi con request_text dell'istruttore
- Sidebar: voce 'Istruttoria rendicontazioni' per EVALUATE_APPLICATIONS
(pre_instructor + instructor_manager)
- Routes /istruttoria e /istruttoria/:id con gate sui tre ruoli
Test end-to-end OK: benef crea+submit, istruttore claim+amendment, benef risponde,
istruttore chiude+approva -> APPROVED remission 8500 EUR su NAPOLI SAS (erogato 17000).
Utenti sandbox creati:
- istruttore@sandbox.local / istruttore123 (ROLE_PRE_INSTRUCTOR)
- manager@sandbox.local / manager123 (ROLE_INSTRUCTOR_MANAGER)
231 lines
7.7 KiB
JavaScript
231 lines
7.7 KiB
JavaScript
import React from 'react';
|
|
import { __ } from '@wordpress/i18n';
|
|
import { intersection, is } from 'ramda';
|
|
|
|
// store
|
|
import { useStoreValue } from '../../../../store';
|
|
|
|
// components
|
|
import { NavLink } from 'react-router-dom';
|
|
import HelpIcon from '../../../../icons/HelpIcon';
|
|
|
|
const AppSidebar = () => {
|
|
const permissions = useStoreValue('getPermissions');
|
|
|
|
const items = [
|
|
{
|
|
label: __('Riepilogo', 'gepafin'),
|
|
icon: 'pi pi-objects-column',
|
|
href: '/',
|
|
id: 1,
|
|
enable: true
|
|
},
|
|
{
|
|
label: __('Gestione bandi', 'gepafin'),
|
|
icon: 'pi pi-file',
|
|
href: '/bandi',
|
|
id: 2,
|
|
enable: intersection(permissions, ['MANAGE_TENDERS']).length
|
|
},
|
|
{
|
|
label: __('Istruttoria rendicontazioni', 'gepafin'),
|
|
icon: 'pi pi-check-square',
|
|
href: '/istruttoria',
|
|
id: 12,
|
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
|
},
|
|
{
|
|
label: __('Rendicontazione', 'gepafin'),
|
|
icon: 'pi pi-receipt',
|
|
href: '/rendicontazione',
|
|
id: 21,
|
|
enable: intersection(permissions, ['MANAGE_TENDERS']).length
|
|
},
|
|
{
|
|
label: __('Dev: cambia utente', 'gepafin'),
|
|
icon: 'pi pi-user-edit',
|
|
href: '/dev-switch-user',
|
|
id: 99,
|
|
enable: intersection(permissions, ['MANAGE_USERS']).length
|
|
},
|
|
{
|
|
label: __('Domande in lavorazione', 'gepafin'),
|
|
icon: 'pi pi-file',
|
|
href: '/imieibandi',
|
|
id: 3,
|
|
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
|
|
},
|
|
{
|
|
label: __('Bandi disponibili', 'gepafin'),
|
|
icon: 'pi pi-bookmark',
|
|
href: '/bandi',
|
|
id: 4,
|
|
enable: intersection(permissions, ['VIEW_CALLS', 'VIEW_CONFIDI_CALLS']).length
|
|
},
|
|
{
|
|
label: __('Bandi osservati', 'gepafin'),
|
|
icon: 'pi pi-star',
|
|
href: '/bandi-osservati',
|
|
id: 5,
|
|
enable: intersection(permissions, ['VIEW_CALLS', 'VIEW_CONFIDI_CALLS']).length
|
|
},
|
|
{
|
|
label: __('Gestione domande', 'gepafin'),
|
|
icon: 'pi pi-file',
|
|
href: '/domande',
|
|
id: 6,
|
|
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS', 'ASSIGED_APPLICATION']).length
|
|
},
|
|
{
|
|
label: __('Domande da valutare', 'gepafin'),
|
|
icon: 'pi pi-calendar-clock',
|
|
href: '/domande',
|
|
id: 7,
|
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length && !intersection(permissions, ['ASSIGED_APPLICATION']).length
|
|
},
|
|
{
|
|
label: __('Bandi attivi', 'gepafin'),
|
|
icon: 'pi pi-file',
|
|
href: '/bandi',
|
|
id: 8,
|
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
|
},
|
|
{
|
|
label: __('Soccorso', 'gepafin'),
|
|
icon: <HelpIcon/>,
|
|
href: '/soccorso-istruttorio',
|
|
id: 9,
|
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
|
},
|
|
{
|
|
label: __('Archivio domande', 'gepafin'),
|
|
icon: 'pi pi-briefcase',
|
|
href: '/domande',
|
|
id: 10,
|
|
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
|
|
},
|
|
{
|
|
label: __('Le mie rendicontazioni', 'gepafin'),
|
|
icon: 'pi pi-receipt',
|
|
href: '/rendicontazioni',
|
|
id: 11,
|
|
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
|
|
},
|
|
{
|
|
label: __('Archivio domande', 'gepafin'),
|
|
icon: 'pi pi-briefcase',
|
|
href: '/domande-archivio',
|
|
id: 11,
|
|
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
|
|
},
|
|
{
|
|
label: __('Archivio domande', 'gepafin'),
|
|
icon: 'pi pi-briefcase',
|
|
href: '/domande-archivio',
|
|
id: 12,
|
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
|
},
|
|
{
|
|
label: __('Area personale', 'gepafin'),
|
|
icon: 'pi pi-calendar-clock',
|
|
id: 17,
|
|
enable: intersection(permissions, ['ASSIGED_APPLICATION']).length
|
|
},
|
|
{
|
|
label: __('Domande da valutare', 'gepafin'),
|
|
icon: 'pi pi-calendar-clock',
|
|
href: '/mie-domande',
|
|
id: 18,
|
|
enable: intersection(permissions, ['ASSIGED_APPLICATION']).length
|
|
},
|
|
{
|
|
label: __('Soccorso istruttorio', 'gepafin'),
|
|
icon: <HelpIcon/>,
|
|
href: '/mio-soccorso-istruttorio',
|
|
id: 19,
|
|
enable: intersection(permissions, ['ASSIGED_APPLICATION']).length
|
|
},
|
|
{
|
|
label: __('Gestione utenti', 'gepafin'),
|
|
icon: 'pi pi-users',
|
|
href: '/utenti',
|
|
id: 13,
|
|
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
|
|
},
|
|
{
|
|
label: __('Configurazione', 'gepafin'),
|
|
icon: 'pi pi-cog',
|
|
//href: '/configurazione',
|
|
id: 14,
|
|
enable: false
|
|
},
|
|
{
|
|
label: __('Statistiche', 'gepafin'),
|
|
icon: 'pi pi-chart-bar',
|
|
href: '/stats',
|
|
id: 15,
|
|
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
|
|
},
|
|
{
|
|
label: __('Documenti', 'gepafin'),
|
|
icon: 'pi pi-folder-open',
|
|
href: '/documenti',
|
|
id: 16,
|
|
enable: intersection(permissions, ['APPLY_CALLS', 'APPLY_CONFIDI_CALLS']).length
|
|
},
|
|
{
|
|
label: __('Admin', 'gepafin'),
|
|
icon: 'pi pi-shield',
|
|
href: '/admin',
|
|
id: 20,
|
|
enable: intersection(permissions, [
|
|
'ROOT_MANAGE_NDG',
|
|
'ROOT_MANAGE_APPL_STATUS',
|
|
'ROOT_MANAGE_AMENDMENT_REOPEN',
|
|
'ROOT_MANAGE_AMENDMENT_EXTEND',
|
|
'ROOT_MANAGE_APPL_VIEW_DELETED',
|
|
'ROOT_MANAGE_APPL_DELETE_CONFIRM',
|
|
'ROOT_MANAGE_APPL_DELETE',
|
|
'ROOT_MANAGE_PEC_SEND',
|
|
'ROOT_MANAGE_VIEW_LOG'
|
|
]).length
|
|
},
|
|
{
|
|
label: __('Log di Sistema', 'gepafin'),
|
|
icon: 'pi pi-receipt',
|
|
clickFn: () => {
|
|
},
|
|
id: 16,
|
|
enable: false
|
|
}
|
|
]
|
|
|
|
return <aside>
|
|
<ul>
|
|
{items
|
|
.filter(o => o.enable)
|
|
.map(o => <li key={o.id}>
|
|
{o.href
|
|
? <NavLink to={o.href}>
|
|
{is(String, o.icon)
|
|
? <i className={o.icon}></i>
|
|
: o.icon}
|
|
<span>{o.label}</span>
|
|
</NavLink>
|
|
: (o.clickFn ?
|
|
<button onClick={() => {
|
|
}}>
|
|
{is(String, o.icon)
|
|
? <i className={o.icon}></i>
|
|
: o.icon}
|
|
<span>{o.label}</span>
|
|
</button>
|
|
: <div className="nonLink">
|
|
<span>{o.label}</span>
|
|
</div>)}
|
|
</li>)}
|
|
</ul>
|
|
</aside>
|
|
}
|
|
|
|
export default AppSidebar; |