diff --git a/src/modules/ar1/pages/Ar1AdminConfig.js b/src/modules/ar1/pages/Ar1AdminConfig.js
index df9b9ba..2d3f0fe 100644
--- a/src/modules/ar1/pages/Ar1AdminConfig.js
+++ b/src/modules/ar1/pages/Ar1AdminConfig.js
@@ -1,532 +1,490 @@
import React, { useEffect, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n';
-// primereact
+// prime
import { Card } from 'primereact/card';
import { Button } from 'primereact/button';
import { Toast } from 'primereact/toast';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { TabView, TabPanel } from 'primereact/tabview';
-import { InputText } from 'primereact/inputtext';
import { InputNumber } from 'primereact/inputnumber';
import { InputSwitch } from 'primereact/inputswitch';
+import { InputText } from 'primereact/inputtext';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Checkbox } from 'primereact/checkbox';
import { Dialog } from 'primereact/dialog';
import { Tag } from 'primereact/tag';
+import { Message } from 'primereact/message';
import { ConfirmDialog, confirmDialog } from 'primereact/confirmdialog';
-import { Chips } from 'primereact/chips';
-import { Checkbox } from 'primereact/checkbox';
-import { Calendar } from 'primereact/calendar';
-import { Dropdown } from 'primereact/dropdown';
+// service
import Ar1Service from '../service/ar1Service';
/**
- * Configurazione AR1 (superadmin). 4 sottosezioni in TabView:
- * 1. Template — lista versioni con status (ACTIVE/ARCHIVED/DRAFT), edit L2 layout_config, nuova versione
- * 2. Policy — singleton (validity, popup, auto-archive, bulk flag)
- * 3. Regole Reminder PEC — CRUD ar1_pec_schedule_config
- * 4. Invio Massivo PEC — filtri azienda + dry-run + submit live
+ * Ar1AdminConfig — configurazione AR1 per superadmin.
+ * URL: /ar1-admin
*
- * Percorso: /ar1-admin (permessi MANAGE_TENDERS)
+ * 4 sezioni (TabView):
+ * 1. Template — lista + layout editor L2 + nuova versione
+ * 2. Policy — singleton (validity, popup, auto-archive, category)
+ * 3. Regole reminder PEC — CRUD pec-schedule-config
+ * 4. Invio massivo PEC — bulk-request-recompilation (dry-run + live)
*/
const Ar1AdminConfig = () => {
const toast = useRef(null);
- const [activeTab, setActiveTab] = useState(0);
+ const [activeIndex, setActiveIndex] = useState(0);
+
+ // ========= TEMPLATES =========
+ const [templates, setTemplates] = useState([]);
+ const [loadingTpl, setLoadingTpl] = useState(false);
+ const [editLayoutOpen, setEditLayoutOpen] = useState(false);
+ const [editLayoutTpl, setEditLayoutTpl] = useState(null);
+ const [layoutJsonText, setLayoutJsonText] = useState('');
+ const [newVersionOpen, setNewVersionOpen] = useState(false);
+ const [newVersionVariant, setNewVersionVariant] = useState('A1');
+ const [newVersionData, setNewVersionData] = useState({ version: '', layout_config: '{}', activate_now: true });
+
+ // ========= POLICY =========
+ const [policy, setPolicy] = useState(null);
+ const [policyDraft, setPolicyDraft] = useState(null);
+ const [savingPolicy, setSavingPolicy] = useState(false);
+
+ // ========= PEC RULES =========
+ const [pecRules, setPecRules] = useState([]);
+ const [pecDialogOpen, setPecDialogOpen] = useState(false);
+ const [pecEditing, setPecEditing] = useState(null);
+ const [pecDraft, setPecDraft] = useState({ kind: '', offset_days: 0, is_recurring: false, recurring_interval_days: null, enabled: true, description: '' });
+
+ // ========= BULK =========
+ const [bulkCompanyIds, setBulkCompanyIds] = useState('');
+ const [bulkOnlyExpired, setBulkOnlyExpired] = useState(false);
+ const [bulkOnlyMissing, setBulkOnlyMissing] = useState(false);
+ const [bulkResult, setBulkResult] = useState(null);
+ const [bulkRunning, setBulkRunning] = useState(false);
+
+ // ---- load all ----
+ const loadTemplates = () => {
+ setLoadingTpl(true);
+ Ar1Service.listTemplates(
+ (resp) => { setTemplates(resp?.items || resp || []); setLoadingTpl(false); },
+ (err) => { setLoadingTpl(false); if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Load templates fallito' }); }
+ );
+ };
+ const loadPolicy = () => {
+ Ar1Service.getPolicy(
+ (resp) => { setPolicy(resp); setPolicyDraft(resp); },
+ (err) => { if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Load policy fallito' }); }
+ );
+ };
+ const loadPecRules = () => {
+ Ar1Service.listPecSchedule(
+ (resp) => setPecRules(resp?.items || resp || []),
+ (err) => { if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Load pec rules fallito' }); }
+ );
+ };
+
+ useEffect(() => {
+ loadTemplates();
+ loadPolicy();
+ loadPecRules();
+ }, []);
+
+ // ========= TEMPLATE HANDLERS =========
+ const openEditLayout = (tpl) => {
+ setEditLayoutTpl(tpl);
+ setLayoutJsonText(JSON.stringify(tpl.layout_config || {}, null, 2));
+ setEditLayoutOpen(true);
+ };
+
+ const saveLayout = () => {
+ let parsed;
+ try { parsed = JSON.parse(layoutJsonText); }
+ catch (e) { if (toast.current) toast.current.show({ severity: 'error', summary: 'JSON invalido', detail: e.message }); return; }
+ Ar1Service.updateTemplateLayout(editLayoutTpl.id, parsed,
+ () => {
+ if (toast.current) toast.current.show({ severity: 'success', summary: 'OK', detail: 'Layout aggiornato' });
+ setEditLayoutOpen(false);
+ loadTemplates();
+ },
+ (err) => { if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Save fallito' }); }
+ );
+ };
+
+ const openNewVersion = (variant) => {
+ setNewVersionVariant(variant);
+ setNewVersionData({ version: '', layout_config: '{}', activate_now: true });
+ setNewVersionOpen(true);
+ };
+
+ const saveNewVersion = () => {
+ let layoutParsed;
+ try { layoutParsed = JSON.parse(newVersionData.layout_config); }
+ catch (e) { if (toast.current) toast.current.show({ severity: 'error', summary: 'Layout JSON invalido', detail: e.message }); return; }
+ Ar1Service.createNewTemplateVersion(newVersionVariant, {
+ version: newVersionData.version,
+ layout_config: layoutParsed,
+ activate_now: newVersionData.activate_now
+ },
+ () => {
+ if (toast.current) toast.current.show({ severity: 'success', summary: 'OK', detail: `Nuova versione ${newVersionVariant} v${newVersionData.version} creata` });
+ setNewVersionOpen(false);
+ loadTemplates();
+ },
+ (err) => { if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Create fallito' }); }
+ );
+ };
+
+ // ========= POLICY HANDLERS =========
+ const savePolicy = () => {
+ setSavingPolicy(true);
+ const patch = {
+ validity_days: policyDraft.validity_days,
+ popup_dismiss_hours: policyDraft.popup_dismiss_hours,
+ popup_force_on_expired: policyDraft.popup_force_on_expired,
+ auto_archive_on_company_document: policyDraft.auto_archive_on_company_document,
+ company_document_category_id: policyDraft.company_document_category_id,
+ allow_bulk_recompilation_request: policyDraft.allow_bulk_recompilation_request,
+ };
+ Ar1Service.updatePolicy(patch,
+ (resp) => {
+ setSavingPolicy(false);
+ setPolicy(resp);
+ setPolicyDraft(resp);
+ if (toast.current) toast.current.show({ severity: 'success', summary: 'OK', detail: 'Policy aggiornata' });
+ },
+ (err) => {
+ setSavingPolicy(false);
+ if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Save policy fallito' });
+ }
+ );
+ };
+
+ // ========= PEC RULE HANDLERS =========
+ const openPecDialog = (rule) => {
+ if (rule) {
+ setPecEditing(rule);
+ setPecDraft({
+ kind: rule.kind,
+ offset_days: rule.offset_days,
+ is_recurring: rule.is_recurring,
+ recurring_interval_days: rule.recurring_interval_days,
+ enabled: rule.enabled,
+ description: rule.description || ''
+ });
+ } else {
+ setPecEditing(null);
+ setPecDraft({ kind: '', offset_days: 0, is_recurring: false, recurring_interval_days: null, enabled: true, description: '' });
+ }
+ setPecDialogOpen(true);
+ };
+
+ const savePecRule = () => {
+ const payload = { ...pecDraft };
+ const onOk = () => {
+ if (toast.current) toast.current.show({ severity: 'success', summary: 'OK', detail: pecEditing ? 'Regola aggiornata' : 'Regola creata' });
+ setPecDialogOpen(false);
+ loadPecRules();
+ };
+ const onKo = (err) => { if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Save fallito' }); };
+ if (pecEditing) Ar1Service.updatePecRule(pecEditing.id, payload, onOk, onKo);
+ else Ar1Service.createPecRule(payload, onOk, onKo);
+ };
+
+ const deletePecRule = (rule) => {
+ confirmDialog({
+ message: `Eliminare la regola "${rule.kind}"?`,
+ header: 'Conferma eliminazione',
+ icon: 'pi pi-exclamation-triangle',
+ acceptClassName: 'p-button-danger',
+ accept: () => {
+ Ar1Service.deletePecRule(rule.id,
+ () => {
+ if (toast.current) toast.current.show({ severity: 'success', summary: 'OK', detail: 'Regola eliminata' });
+ loadPecRules();
+ },
+ (err) => { if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Delete fallito' }); }
+ );
+ }
+ });
+ };
+
+ // ========= BULK HANDLERS =========
+ const runBulk = (dryRun) => {
+ setBulkRunning(true);
+ const companyIds = bulkCompanyIds.trim()
+ ? bulkCompanyIds.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n))
+ : null;
+ const payload = {
+ dry_run: dryRun,
+ only_expired: bulkOnlyExpired,
+ only_missing: bulkOnlyMissing,
+ company_ids: companyIds,
+ };
+ Ar1Service.bulkRequestRecompilation(payload,
+ (resp) => {
+ setBulkRunning(false);
+ setBulkResult({ ...resp, was_dry_run: dryRun });
+ if (toast.current) toast.current.show({
+ severity: 'success',
+ summary: dryRun ? 'Dry-run completato' : 'Bulk eseguito',
+ detail: `${resp.matched || 0} aziende matchate`
+ });
+ },
+ (err) => {
+ setBulkRunning(false);
+ if (toast.current) toast.current.show({ severity: 'error', summary: 'Errore', detail: err?.detail || 'Bulk fallito' });
+ }
+ );
+ };
+
+ // ---------- RENDER ----------
+ const tplStatusTpl = (row) => {
+ const severity = row.status === 'ACTIVE' ? 'success' : row.status === 'ARCHIVED' ? 'secondary' : 'warning';
+ return
- {__('Gestione template, policy, regole reminder PEC e invio massivo solleciti per la dichiarazione AR1 (D.Lgs. 231/2007).', 'gepafin')} + {__('Gestione template, policy, regole di scadenza e invio massivo PEC per il modulo di adeguata verifica.', 'gepafin')}
-{__('Caricamento...', 'gepafin')}
} + {policyDraft && ( +{__('Caricamento...', 'gepafin')}