fix(ar1): R7 nominativo coincidenza C/D + datepicker timezone + draft continuo + cosmetici

Round 2 test UI 4/7/2026:
- R7 (regressione): campo nominativo di coincidenza (C/D) reso con blocco
  dedicato renderCoincidenceRef, indipendente dal ramo show_if fragile che
  aveva propagato la rotttura; Dropdown editabile prefillato dai titolari del
  Quadro B, valore sempre persistito -> presente in UI e PDF
- datepicker: commit della data in locale (YYYY-MM-DD da get*()) invece di
  toISOString, che shiftava -1 giorno in CET (01/01/1980 -> 1979-12-31)
- R6: con autosave sospeso il draft locale segue ogni modifica (non piu solo
  lo snapshot al 401): niente perdita dei dati inseriti dopo il banner
- cosmetico R1: pannello errori azzerato al cambio step valido / Avanti
This commit is contained in:
Kitzanos
2026-07-04 11:06:08 +02:00
parent 6dc715d997
commit 05cf15cad7

View File

@@ -187,10 +187,15 @@ const Ar1Wizard = () => {
}; };
const handleFieldChange = (quadroId, fieldId, value) => { const handleFieldChange = (quadroId, fieldId, value) => {
setQuadriValues(prev => ({ setQuadriValues(prev => {
...prev, const next = { ...prev, [quadroId]: { ...(prev[quadroId] || {}), [fieldId]: value } };
[quadroId]: { ...(prev[quadroId] || {}), [fieldId]: value } // Autosave sospeso (post-401): il draft locale segue OGNI modifica, non solo
})); // lo snapshot iniziale (fix R6 — niente perdita dei dati inseriti dopo il banner)
if (authExpiredRef.current) {
try { localStorage.setItem(`ar1_draft_${formId}`, JSON.stringify({ ts: Date.now(), quadri: next })); } catch (e) { /* quota */ }
}
return next;
});
}; };
const handleRowFieldChange = (quadroId, rowIndex, fieldId, value) => { const handleRowFieldChange = (quadroId, rowIndex, fieldId, value) => {
@@ -298,7 +303,7 @@ const Ar1Wizard = () => {
return ( return (
<div key={key} style={{ marginBottom: 14 }}> <div key={key} style={{ marginBottom: 14 }}>
{commonLabel} {commonLabel}
<Calendar id={key} value={value ? new Date(value) : null} onChange={(e) => onChange(field.id, e.value ? e.value.toISOString().slice(0, 10) : null)} disabled={disabled} dateFormat="dd/mm/yy" showIcon style={{ width: '100%' }} /> <Calendar id={key} value={value ? new Date(value + 'T00:00:00') : null} onChange={(e) => onChange(field.id, e.value ? `${e.value.getFullYear()}-${String(e.value.getMonth() + 1).padStart(2, '0')}-${String(e.value.getDate()).padStart(2, '0')}` : null)} disabled={disabled} dateFormat="dd/mm/yy" showIcon style={{ width: '100%' }} />
</div> </div>
); );
case 'checkbox': case 'checkbox':
@@ -373,6 +378,43 @@ const Ar1Wizard = () => {
} }
}; };
// Nominativi titolari effettivi dal Quadro B (per prefill coincidenza LR/esecutore)
const titolariB = useMemo(() => {
const b = quadriValues['B'] || {};
const rows = b.rows || [];
return rows.map(r => (r && r.cognome_nome ? String(r.cognome_nome).trim() : '')).filter(Boolean);
}, [quadriValues]);
// Campo nominativo di coincidenza (Quadro C: lr_te_reference, D: esecutore_lr_reference).
// Reso SOLO se la spunta di coincidenza e attiva; il valore e sempre persistito
// cosi da comparire nel PDF (fix regressione R7, modulo 231/2007 mai senza nominativo).
const renderCoincidenceRef = (quadro, field, q) => {
if (!isFieldVisible(field, q)) return null; // spunta OFF: se ne occupa il nested_full
const key = `q-${quadro.id}-${field.id}`;
const val = q[field.id] || '';
const onSet = (v) => handleFieldChange(quadro.id, field.id, v);
return (
<div key={key} style={{ marginBottom: 14 }}>
<label htmlFor={key} style={{ display: 'block', marginBottom: 4, fontWeight: 500 }}>{field.label}{field.required ? ' *' : ''}</label>
{titolariB.length > 0 ? (
<Dropdown
id={key}
value={val}
options={titolariB.map(n => ({ label: n, value: n }))}
onChange={(e) => onSet(e.value)}
disabled={isReadonly}
placeholder={__('Seleziona dal Quadro B', 'gepafin')}
editable
style={{ width: '100%' }}
/>
) : (
<InputText id={key} value={val} onChange={(e) => onSet(e.target.value)} disabled={isReadonly} maxLength={field.max_length} placeholder={__('Cognome e Nome', 'gepafin')} style={{ width: '100%' }} />
)}
<small style={{ color: '#888' }}>{__('Compilare con uno dei titolari effettivi indicati al Quadro B.', 'gepafin')}</small>
</div>
);
};
const renderQuadro = (quadro) => { const renderQuadro = (quadro) => {
const q = quadriValues[quadro.id] || {}; const q = quadriValues[quadro.id] || {};
@@ -448,7 +490,8 @@ const Ar1Wizard = () => {
<div> <div>
<h3>{quadro.title}</h3> <h3>{quadro.title}</h3>
{quadro.description && <p style={{ color: '#666' }}>{quadro.description}</p>} {quadro.description && <p style={{ color: '#666' }}>{quadro.description}</p>}
{(quadro.fields || []).filter(field => isFieldVisible(field, q)).map(field => renderField(field, q[field.id], (fid, val) => handleFieldChange(quadro.id, fid, val), `q-${quadro.id}`))} {(quadro.fields || []).filter(field => isFieldVisible(field, q) && !field.coincidence_ref).map(field => renderField(field, q[field.id], (fid, val) => handleFieldChange(quadro.id, fid, val), `q-${quadro.id}`))}
{(quadro.fields || []).filter(field => field.coincidence_ref).map(field => renderCoincidenceRef(quadro, field, q))}
{quadro.nested_full && evalShowIf(quadro.nested_full.show_if, q) && ( {quadro.nested_full && evalShowIf(quadro.nested_full.show_if, q) && (
<div style={{ marginTop: 16, padding: 12, background: '#f5f5f5', borderRadius: 4 }}> <div style={{ marginTop: 16, padding: 12, background: '#f5f5f5', borderRadius: 4 }}>
<h4 style={{ marginTop: 0 }}>{__('Dettaglio aggiuntivo', 'gepafin')}</h4> <h4 style={{ marginTop: 0 }}>{__('Dettaglio aggiuntivo', 'gepafin')}</h4>
@@ -498,6 +541,7 @@ const Ar1Wizard = () => {
setStepErrors([]); setStepErrors([]);
} }
if (!isReadonly && activeQuadro) saveQuadro(activeQuadro.id); if (!isReadonly && activeQuadro) saveQuadro(activeQuadro.id);
setStepErrors([]);
setActiveIndex(next); setActiveIndex(next);
}} }}
readOnly={false} readOnly={false}
@@ -558,6 +602,7 @@ const Ar1Wizard = () => {
setStepErrors([]); setStepErrors([]);
saveQuadro(activeQuadro.id); saveQuadro(activeQuadro.id);
} }
setStepErrors([]);
setActiveIndex(Math.min(quadri.length - 1, activeIndex + 1)); setActiveIndex(Math.min(quadri.length - 1, activeIndex + 1));
}} }}
/> />