diff --git a/src/modules/rendicontazione/pages/RendicontazioniMie.js b/src/modules/rendicontazione/pages/RendicontazioniMie.js index 25475fb..eabb2cd 100644 --- a/src/modules/rendicontazione/pages/RendicontazioniMie.js +++ b/src/modules/rendicontazione/pages/RendicontazioniMie.js @@ -9,16 +9,18 @@ import { Skeleton } from 'primereact/skeleton'; import { Dialog } from 'primereact/dialog'; import { InputText } from 'primereact/inputtext'; import { Checkbox } from 'primereact/checkbox'; +import { Card } from 'primereact/card'; +import { Divider } from 'primereact/divider'; import RendicontazioneService from '../service/rendicontazioneService'; const STATUS_TAGS = { - DRAFT: { severity: 'warning', label: 'In compilazione' }, - SUBMITTED: { severity: 'info', label: 'Inviata' }, - UNDER_REVIEW: { severity: 'info', label: 'In valutazione' }, - APPROVED: { severity: 'success', label: 'Approvata' }, - REJECTED: { severity: 'danger', label: 'Respinta' }, - AWAITING_AMENDMENT: { severity: 'warning', label: 'Soccorso istruttorio' } + DRAFT: { severity: 'warning', label: 'In compilazione', icon: 'pi pi-pencil' }, + SUBMITTED: { severity: 'info', label: 'Inviata', icon: 'pi pi-send' }, + UNDER_REVIEW: { severity: 'info', label: 'In valutazione', icon: 'pi pi-eye' }, + APPROVED: { severity: 'success', label: 'Approvata', icon: 'pi pi-check-circle' }, + REJECTED: { severity: 'danger', label: 'Respinta', icon: 'pi pi-times-circle' }, + AWAITING_AMENDMENT: { severity: 'warning', label: 'Soccorso istruttorio',icon: 'pi pi-exclamation-triangle' } }; const fmtEur = (v) => { @@ -26,6 +28,106 @@ const fmtEur = (v) => { return `€ ${n.toLocaleString('it-IT', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; }; +// -------- Sottocomponenti di presentazione -------- + +const StatTile = ({ label, value, accent = 'var(--text-color)', muted = false }) => ( +
+
+ {label} +
+
+ {value} +
+
+); + +const TrancheRow = ({ tranche, onOpen, isLast }) => { + const tag = STATUS_TAGS[tranche.status] || { severity: 'secondary', label: tranche.status, icon: 'pi pi-circle' }; + const isEditable = tranche.status === 'DRAFT' || tranche.status === 'AWAITING_AMENDMENT'; + const hasContent = (tranche.invoice_count || tranche.ula_count || tranche.document_count); + + return ( +
+ {/* Icona circolare con numero tranche */} +
+ T{tranche.sequence_number} +
+ + {/* Descrizione tranche */} +
+
+ {tranche.period_label || {__('Nessun periodo indicato','gepafin')}} +
+
+ {hasContent ? ( + <> + + {tranche.invoice_count || 0} {__('fatture','gepafin')} + · + + {tranche.ula_count || 0} {__('dipendenti','gepafin')} + · + + {tranche.document_count || 0} {__('documenti','gepafin')} + + ) : ( + {__('Nessun contenuto ancora inserito','gepafin')} + )} +
+
+ + {/* Stato + CTA */} + +
+ ); +}; + +// -------- Componente principale -------- + const RendicontazioniMie = () => { const navigate = useNavigate(); const toast = useRef(null); @@ -58,152 +160,213 @@ const RendicontazioniMie = () => { call_name: app.call_name, max_tranches: app.max_tranches, next_seq: nextSeq, - max_remission_next: app.max_remission_next_tranche, show_copy_ula: nextSeq > 1, + max_remission_next: app.max_remission_next_tranche, }); - setStartForm({ period_label: '', copy_ula: true }); + setStartForm({ period_label: '', copy_ula: nextSeq > 1 }); }; const confirmStart = () => { if (!startDialog) return; setStarting(true); - RendicontazioneService.startPractice(startDialog.application_id, + RendicontazioneService.startPractice( + startDialog.application_id, (resp) => { setStarting(false); setStartDialog(null); - toast.current?.show({ - severity: 'success', - summary: __('Tranche avviata', 'gepafin'), - detail: resp?.message - }); - const newId = resp?.data?.id; - if (newId) navigate(`/rendicontazioni/${newId}`); - else load(); + toast.current?.show({ severity: 'success', summary: resp?.message || __('Tranche avviata', 'gepafin') }); + navigate(`/rendicontazioni/${resp.data.id}`); }, (err) => { setStarting(false); - toast.current?.show({ - severity: 'error', - summary: __('Avvio fallito', 'gepafin'), - detail: err?.detail || err?.message - }); + toast.current?.show({ severity: 'error', summary: __('Avvio fallito', 'gepafin'), detail: err?.detail }); }, { - period_label: startForm.period_label || null, - copy_ula_from_previous: startDialog.show_copy_ula ? startForm.copy_ula : false, + period_label: startForm.period_label?.trim() || null, + copy_ula_from_previous: startForm.copy_ula, } ); }; const renderApplicationCard = (app) => { - const hasTranches = (app.tranches?.length || 0) > 0; - const nextSeq = (app.tranches?.length || 0) + 1; + const tranchesCount = app.tranches?.length || 0; + const hasTranches = tranchesCount > 0; + const nextSeq = tranchesCount + 1; const canStart = !!app.can_start_new; const blockReason = app.start_blocked_reason; + const progressPct = app.max_remission_global > 0 + ? Math.min(100, (app.already_approved_sum / app.max_remission_global) * 100) + : 0; - return ( -
- {/* HEADER: bando + erogato */} -
-
-

- {app.call_name || `Bando #${app.call_id}`} -

-

- {app.company_name || ''} · {__('Domanda', 'gepafin')} #{app.application_id} -

-
-
-
- {__('Finanziamento erogato','gepafin')} -
-
{fmtEur(app.amount_erogato)}
+ const headerTemplate = ( +
+
+

+ {app.call_name || `Bando #${app.call_id}`} +

+
+ + {app.company_name || '—'} + · + {__('Domanda', 'gepafin')} #{app.application_id}
- - {/* METRICHE cap/approvato/disponibile/tranches in griglia 4 colonne */} -
-

- {__('Cap remissione totale', 'gepafin')} - {fmtEur(app.max_remission_global)} -

-

- {__('Già approvato', 'gepafin')} - 0 ? 'var(--green-700)' : 'inherit' }}> - {fmtEur(app.already_approved_sum)} - -

-

- {__('Disponibile prossima tranche', 'gepafin')} - - {fmtEur(app.max_remission_next_tranche)} - -

-

- {__('Tranches', 'gepafin')} - {app.tranches?.length || 0} / {app.max_tranches} -

-
- - {/* LISTA TRANCHES */} - {hasTranches && ( -
    - {app.tranches.map((t) => { - const tag = STATUS_TAGS[t.status] || { severity: 'secondary', label: t.status }; - const isEditable = t.status === 'DRAFT'; - return ( -
  • -
    -
    - T{t.sequence_number} -
    -
    -
    - {t.period_label || ( - - {__('nessun periodo indicato','gepafin')} - - )} -
    -
    - {t.invoice_count || 0} {__('fatture','gepafin')} · {t.ula_count || 0} {__('dipendenti','gepafin')} · {t.document_count || 0} {__('doc','gepafin')} -
    -
    -
    -
    - -
    -
  • - ); - })} -
- )} - - {/* AZIONI: nuova tranche */} -
- {!canStart && blockReason && ( - - - {blockReason} - - )} -
); + + return ( + + + {/* BLOCCO TOTALI — 4 stat tile affiancati */} +
+ + + + +
+ + {/* PROGRESS BAR utilizzo cap */} + {app.max_remission_global > 0 && ( +
+
+
= 100 ? 'var(--red-500)' : '#16a34a', + transition: 'width 0.3s', + }} /> +
+
+ {progressPct.toFixed(1)}% {__('del cap già utilizzato','gepafin')} +
+
+ )} + + {/* TRANCHES */} + {hasTranches ? ( +
+
+ {__('Elenco tranche','gepafin')} +
+
+ {app.tranches.map((t, idx) => ( + navigate(`/rendicontazioni/${id}`)} + isLast={idx === app.tranches.length - 1} + /> + ))} +
+
+ ) : ( +
+ + {__('Non hai ancora avviato nessuna tranche di rendicontazione per questo bando.','gepafin')} +
+ )} + + {/* FOOTER — bottone nuova tranche */} + +
+ {!canStart && blockReason ? ( +
+ + {blockReason} +
+ ) : } + +
+ + ); }; return ( @@ -212,56 +375,75 @@ const RendicontazioniMie = () => {

{__('Le mie rendicontazioni', 'gepafin')}

-

{__('Per ogni pratica finanziata puoi avviare la rendicontazione delle spese e il calcolo della remissione del debito. I bandi che prevedono più tranches permettono rendicontazioni multi-fase.', 'gepafin')}

+

{__('Per ogni pratica finanziata puoi avviare la rendicontazione delle spese e il calcolo della remissione del debito. I bandi che prevedono piu tranches permettono rendicontazioni multi-fase.', 'gepafin')}

{loading && ( -
- +
+ +
)} {!loading && apps.length === 0 && ( -
- -

{__('Non ci sono rendicontazioni disponibili al momento.', 'gepafin')}

- - {__('Le rendicontazioni diventano disponibili dopo la firma del contratto e quando l\'ente ha pubblicato lo schema di rendicontazione per il bando.', 'gepafin')} - -
+ +
+ +

{__('Non ci sono rendicontazioni disponibili al momento.', 'gepafin')}

+ + {__('Le rendicontazioni diventano disponibili dopo la firma del contratto e quando l\'ente ha pubblicato lo schema di rendicontazione per il bando.', 'gepafin')} + +
+
)} - {!loading && apps.length > 0 && ( -
- {apps.map(renderApplicationCard)} -
- )} + {!loading && apps.length > 0 && apps.map(renderApplicationCard)} - !starting && setStartDialog(null)} - modal - footer={( -
-
- )}> + {/* START DIALOG */} + !starting && setStartDialog(null)} + modal + footer={( +
+
+ )} + > {startDialog && (
-

- {__('Stai per avviare la tranche', 'gepafin')} - {' '}T{startDialog.next_seq} / {startDialog.max_tranches} - {' '}{__('del bando', 'gepafin')} {startDialog.call_name}. -

-

- {__('Cap remissione disponibile per questa tranche', 'gepafin')}: - {' '}{fmtEur(startDialog.max_remission_next)} -

+
+
+ {__('Stai per avviare la tranche', 'gepafin')} + {' '}T{startDialog.next_seq} / {startDialog.max_tranches} + {' '}{__('del bando', 'gepafin')} +
+
+ {startDialog.call_name} +
+
+ {__('Cap remissione disponibile', 'gepafin')}: + {' '}{fmtEur(startDialog.max_remission_next)} +
+
@@ -269,22 +451,22 @@ const RendicontazioniMie = () => { onChange={(e) => setStartForm(f => ({ ...f, period_label: e.target.value }))} placeholder={__('es. "I trimestre 2021", "Stato avanzamento II"', 'gepafin')} disabled={starting} /> - + {__('Descrizione libera per identificare la tranche. Apparirà sul verbale.', 'gepafin')}
{startDialog.show_copy_ula && (
-
+
setStartForm(f => ({ ...f, copy_ula: e.checked }))} disabled={starting} /> -
- + {__('Se attivo, i dipendenti censiti nella tranche precedente saranno precaricati. Potrai modificarli o rimuoverli prima di inviare.', 'gepafin')}