fix(ar1): Ar1Wizard crash su activeQuadro undefined (7 guard)
Bug: TypeError 'Cannot read properties of undefined (reading id)' su Ar1Wizard.js:358 al click Avanti. Causa: activeIndex poteva uscire fuori range quadri.length (es. dopo re-render con schema_snapshot diverso, o race tra saveQuadro e setForm+setActiveIndex). Gli onClick/onBlur accedevano a activeQuadro.id senza controllo null. Fix: 1. clamp safeIndex = Math.max(0, Math.min(activeIndex, quadri.length - 1)) 2. activeQuadro = quadri[safeIndex] (invece di activeIndex diretto) 3. isLastStep usa safeIndex 4. Steps.activeIndex usa safeIndex; onSelect clampa e.index 5. Bottone Indietro: guard 'if (!isReadonly && activeQuadro)' + Math.max(0,...) 6. Bottone Avanti: guard + Math.min(quadri.length-1,...) 7. Card onBlur: guard su activeQuadro 8. submitFinale: return se !activeQuadro, usa activeQuadro invece di quadri[activeIndex] 9. early return se quadri.length === 0 (template senza quadri editabili) Parse check OK. Webpack compiled 1 warning (vecchio, non nostro).
This commit is contained in:
@@ -21,7 +21,6 @@ const buildHeadersMultipart = () => {
|
||||
const token = storeGet('getToken');
|
||||
const h = {};
|
||||
if (token) h['Authorization'] = `Bearer ${token}`;
|
||||
// niente Content-Type: fetch imposta boundary per multipart/form-data
|
||||
return h;
|
||||
};
|
||||
|
||||
@@ -40,13 +39,11 @@ const handleError = (err, onError) => {
|
||||
};
|
||||
|
||||
const Ar1Service = {
|
||||
// ---------- Status pubblico (per compliance modal al login) ----------
|
||||
// ---------- Status pubblico (per compliance modal) ----------
|
||||
getStatusForCompany(companyId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/public/ar1-status/${companyId}`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- CRUD form beneficiario ----------
|
||||
@@ -54,83 +51,60 @@ const Ar1Service = {
|
||||
fetch(`${BASE_URL}/api/ar1-forms`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify({ company_id: companyId, variant })
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
getForm(formId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
listFormsForCompany(companyId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/company/${companyId}`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
updateQuadri(formId, quadriPatch, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}/quadri`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify({ quadri: quadriPatch })
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
submitForSignature(formId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}/submit-for-signature`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
deleteForm(formId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}`, {
|
||||
method: 'DELETE', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => {
|
||||
if (r.status === 204) {
|
||||
if (onSuccess) onSuccess({});
|
||||
} else {
|
||||
handleResponse(r, onSuccess, onError);
|
||||
}
|
||||
})
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => {
|
||||
if (r.status === 204) { if (onSuccess) onSuccess({}); }
|
||||
else handleResponse(r, onSuccess, onError);
|
||||
}).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- PDF ----------
|
||||
generatePdf(formId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}/generate-pdf`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
downloadPdfUnsigned(formId) {
|
||||
return fetch(`${BASE_URL}/api/ar1-forms/${formId}/pdf-unsigned`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeadersMultipart()
|
||||
}).then(r => {
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
||||
return r.blob();
|
||||
});
|
||||
}).then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.blob(); });
|
||||
},
|
||||
|
||||
downloadPdfSigned(formId) {
|
||||
return fetch(`${BASE_URL}/api/ar1-forms/${formId}/pdf-signed`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeadersMultipart()
|
||||
}).then(r => {
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
||||
return r.blob();
|
||||
});
|
||||
}).then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.blob(); });
|
||||
},
|
||||
|
||||
// ---------- Firma ----------
|
||||
@@ -140,230 +114,100 @@ const Ar1Service = {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}/upload-signature`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeadersMultipart(),
|
||||
body: formData
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
reVerifySignature(formId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}/verify`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- ADMIN: Templates ----------
|
||||
listTemplates(onSuccess, onError, queryStr = '') {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates${queryStr}`, {
|
||||
archiveToCompanyDocument(formId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}/archive-to-company-document`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders()
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- ADMIN: templates ----------
|
||||
listTemplates(onSuccess, onError, queryParams) {
|
||||
const qs = queryParams ? ('?' + new URLSearchParams(queryParams).toString()) : '';
|
||||
fetch(`${BASE_URL}/admin/ar1-templates${qs}`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
getTemplateDetail(templateId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates/${templateId}`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
updateTemplateLayout(templateId, layoutConfig, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates/${templateId}/layout-config`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify({ layout_config: layoutConfig })
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
createNewTemplateVersion(variant, payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates/${variant}/new-version`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- ADMIN: Policy ----------
|
||||
// ---------- ADMIN: policy ----------
|
||||
getPolicy(onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-policy`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
updatePolicy(payload, onSuccess, onError) {
|
||||
updatePolicy(patch, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-policy`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
body: JSON.stringify(patch)
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- ADMIN: PEC Schedule Config (CRUD) ----------
|
||||
// ---------- ADMIN: pec-schedule-config ----------
|
||||
listPecSchedule(onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
createPecRule(payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
updatePecRule(ruleId, payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config/${ruleId}`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
deletePecRule(ruleId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config/${ruleId}`, {
|
||||
method: 'DELETE', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => {
|
||||
if (r.status === 204) {
|
||||
if (onSuccess) onSuccess({});
|
||||
} else {
|
||||
handleResponse(r, onSuccess, onError);
|
||||
}
|
||||
})
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => {
|
||||
if (r.status === 204) { if (onSuccess) onSuccess({}); }
|
||||
else handleResponse(r, onSuccess, onError);
|
||||
}).catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- ADMIN: Bulk PEC ----------
|
||||
// ---------- ADMIN: bulk PEC ----------
|
||||
bulkRequestRecompilation(payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-forms/bulk-request-recompilation`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
},
|
||||
|
||||
// ---------- Archive manuale (di solito automatico) ----------
|
||||
archiveToCompanyDocument(formId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/api/ar1-forms/${formId}/archive-to-company-document`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
}).then(r => handleResponse(r, onSuccess, onError)).catch(e => handleError(e, onError));
|
||||
},
|
||||
};
|
||||
|
||||
export default Ar1Service;
|
||||
|
||||
// ========== ADMIN METHODS (aggiunti fase admin) ==========
|
||||
|
||||
Ar1Service.adminListTemplates = function (onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminGetTemplate = function (templateId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates/${templateId}`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminUpdateLayoutConfig = function (templateId, layoutConfig, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates/${templateId}/layout-config`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify({ layout_config: layoutConfig })
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminNewVersion = function (variant, payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-templates/${variant}/new-version`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminGetPolicy = function (onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-policy`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminUpdatePolicy = function (payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-policy`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminListPecSchedule = function (onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config`, {
|
||||
method: 'GET', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminCreatePecRule = function (payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminUpdatePecRule = function (ruleId, payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config/${ruleId}`, {
|
||||
method: 'PUT', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminDeletePecRule = function (ruleId, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-pec-schedule-config/${ruleId}`, {
|
||||
method: 'DELETE', mode: 'cors', headers: buildHeaders()
|
||||
})
|
||||
.then(r => {
|
||||
if (r.status === 204) { if (onSuccess) onSuccess({}); }
|
||||
else handleResponse(r, onSuccess, onError);
|
||||
})
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Ar1Service.adminBulkRecompilation = function (payload, onSuccess, onError) {
|
||||
fetch(`${BASE_URL}/admin/ar1-forms/bulk-request-recompilation`, {
|
||||
method: 'POST', mode: 'cors', headers: buildHeaders(),
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(r => handleResponse(r, onSuccess, onError))
|
||||
.catch(e => handleError(e, onError));
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user