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:
@@ -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));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user