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) => {
|
||||
setQuadriValues(prev => ({
|
||||
...prev,
|
||||
[quadroId]: { ...(prev[quadroId] || {}), [fieldId]: value }
|
||||
}));
|
||||
setQuadriValues(prev => {
|
||||
const next = { ...prev, [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) => {
|
||||
@@ -298,7 +303,7 @@ const Ar1Wizard = () => {
|
||||
return (
|
||||
<div key={key} style={{ marginBottom: 14 }}>
|
||||
{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>
|
||||
);
|
||||
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 q = quadriValues[quadro.id] || {};
|
||||
|
||||
@@ -448,7 +490,8 @@ const Ar1Wizard = () => {
|
||||
<div>
|
||||
<h3>{quadro.title}</h3>
|
||||
{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) && (
|
||||
<div style={{ marginTop: 16, padding: 12, background: '#f5f5f5', borderRadius: 4 }}>
|
||||
<h4 style={{ marginTop: 0 }}>{__('Dettaglio aggiuntivo', 'gepafin')}</h4>
|
||||
@@ -498,6 +541,7 @@ const Ar1Wizard = () => {
|
||||
setStepErrors([]);
|
||||
}
|
||||
if (!isReadonly && activeQuadro) saveQuadro(activeQuadro.id);
|
||||
setStepErrors([]);
|
||||
setActiveIndex(next);
|
||||
}}
|
||||
readOnly={false}
|
||||
@@ -558,6 +602,7 @@ const Ar1Wizard = () => {
|
||||
setStepErrors([]);
|
||||
saveQuadro(activeQuadro.id);
|
||||
}
|
||||
setStepErrors([]);
|
||||
setActiveIndex(Math.min(quadri.length - 1, activeIndex + 1));
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user