feat(ar1-admin): pagina superadmin Configurazione AR1 (pattern Rendicontazione)

Seconda voce sidebar per superadmin, pattern identico a Rendicontazione:
- benef (APPLY_CALLS) -> 'Dichiarazione AR1' -> /ar1 (compilazione)
- superadmin (MANAGE_TENDERS) -> 'Configurazione AR1' -> /ar1-admin (config)

service/ar1Service.js: +11 metodi admin (adminList/Get Templates, adminUpdateLayout,
adminNewVersion, adminGet/Update Policy, CRUD PecSchedule, adminBulkRecompilation).

pages/Ar1AdminConfig.js (532 LOC): 4 tab PrimeReact TabView:
  1. Template AR1: DataTable 3 varianti, badge status ACTIVE/DRAFT/ARCHIVED,
     drawer detail con textarea JSON layout_config editabile + save,
     bottone 'nuova versione' con modale (semver regex + activate_now)
  2. Policy: form con InputNumber/InputSwitch/Checkbox per 6 campi policy
     (validity_days 30-1825, popup_dismiss_hours 1-168, popup_force_on_expired,
     auto_archive_on_company_document, company_document_category_id, allow_bulk)
  3. Regole Reminder PEC: DataTable CRUD con dialog edit, Chips, InputSwitch
  4. Invio Massivo PEC: 4 filtri (only_expired, only_missing, company_ids Chips,
     expired_before Calendar) + dry-run counter + confirm dialog + submit live

Sidebar: voce id=23 'Configurazione AR1' icon 'pi pi-cog' href '/ar1-admin'
permessi MANAGE_TENDERS (accanto a 'Rendicontazione').

Routes: /ar1-admin solo ROLE_SUPER_ADMIN, altri ruoli -> PageNotFound.

Parse check @babel/parser+JSX: 4 OK / 0 FAIL. Webpack compiled 1 warning (vecchio,
unrelated).
This commit is contained in:
BFLOWS
2026-04-23 11:06:18 +02:00
parent c407bd0b0e
commit 7c508e743b
4 changed files with 750 additions and 0 deletions

View File

@@ -153,6 +153,110 @@ const Ar1Service = {
.catch(e => handleError(e, onError));
},
// ---------- ADMIN: Templates ----------
listTemplates(onSuccess, onError, queryStr = '') {
fetch(`${BASE_URL}/admin/ar1-templates${queryStr}`, {
method: 'GET', mode: 'cors', headers: buildHeaders()
})
.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));
},
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));
},
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));
},
// ---------- 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));
},
updatePolicy(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));
},
// ---------- ADMIN: PEC Schedule Config (CRUD) ----------
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));
},
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));
},
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));
},
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));
},
// ---------- 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`, {
@@ -164,3 +268,102 @@ const Ar1Service = {
};
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));
};