// ECO-PANNEAU.FR - _react/_admin_regles.jsx
window.pano_AdminReglesTab = ({ data, refreshData, openLocalDialog, closeCurrentLayer, activeDialog }) => {
const { useState } = React;
// ZÉRO-DETTE : Utilisation de notre Hook abstrait !
const { isMounted, safeFetch } = window.pano_useSafeFetch();
// Routage et modales
const {
activeDialog: hookActiveDialog,
openDialog: hookOpenDialog,
closeCurrentLayer: hookCloseLayer
} = window.pano_useUrlModal ? window.pano_useUrlModal() : {};
const routerActiveDialog = activeDialog || hookActiveDialog;
const routerCloseLayer = closeCurrentLayer || hookCloseLayer;
const routerOpenDialog = openLocalDialog || hookOpenDialog;
// États
const [isSaving, setIsSaving] = useState(false);
const [settings, setSettings] = useState(data.settings || {});
const [pwdRequestData, setPwdRequestData] = useState(null);
// Composants et Icônes
const {
SettingsIcon, EyeIcon, SaveIcon, LoaderIcon, DatabaseIcon, ServerIcon,
ClockIcon, HardDriveIcon, UploadCloudIcon, Trash2Icon, KeyRoundIcon,
RefreshCwIcon, ZapIcon, EditIcon
} = window.pano_getIcons();
const { FormInput, PasswordPromptModal, TextLogo, Button, DataCard } = window.pano_getComponents();
// Fallback pour les icônes si manquantes
const DBIconToUse = DatabaseIcon || ServerIcon || SettingsIcon;
const ClockIconToUse = ClockIcon || RefreshCwIcon || ZapIcon;
const HardDriveIconToUse = HardDriveIcon || SaveIcon || UploadCloudIcon;
// Méthodes métier
const updateSetting = (key, val) => setSettings({ ...settings, [key]: val });
const handleSave = async (e) => {
e.preventDefault();
const payload = {};
let isProtectedChanged = false;
// Champs nécessitant une protection par mot de passe dans cet onglet
const protectedFields = [
'limit_rgpd_delete', 'limit_draft_delete', 'limit_keepalive_delete',
'limit_shipping_force', 'limit_history_max', 'quota_vault_mb',
'quota_upload_private_mb', 'quota_upload_public_mb', 'limit_pdf_pages',
'purge_zip_transit_hours', 'purge_zip_doe_hours', 'token_register_hours',
'token_reset_hours', 'token_invite_days', 'token_support_days', 'support_access_hours'
];
for (const key in settings) {
const oldVal = String(data.settings?.[key] ?? '').replace(/\r\n/g, '\n');
const newVal = String(settings[key] ?? '').replace(/\r\n/g, '\n');
if (oldVal !== newVal) {
payload[key] = settings[key];
if (protectedFields.includes(key)) {
isProtectedChanged = true;
}
}
}
if (Object.keys(payload).length === 0) {
if (window.pano_showToast) window.pano_showToast("Aucune modification à sauvegarder.", "info");
return;
}
if (isProtectedChanged) {
setPwdRequestData({
title: "Confirmation de sécurité",
desc: "La modification des seuils du système nécessite le mot de passe administrateur :",
onConfirm: async (pwd, submitEvt) => {
const d = await executeSave({ ...payload, pwd });
if (!isMounted.current) return;
if (d) routerCloseLayer(submitEvt);
}
});
routerOpenDialog('pwd_request', null, e);
return;
}
await executeSave(payload);
};
const executeSave = async (finalPayload) => {
const d = await safeFetch('settings/update', {
body: finalPayload,
setLoading: setIsSaving,
successMessage: "Règles et options sauvegardées avec succès !"
});
if (!isMounted.current) return;
if (d && refreshData) refreshData();
return d;
};
// Helper pour le rendu des menus déroulants à 4 choix stricts
const renderSelectRow = (key, label) => {
const val = settings[key] || 'active'; // Par défaut
return (
{label}
);
};
// Calcul de "hasChanges" pour afficher/griser le bouton "Sauvegarder"
let hasChanges = false;
for (const key in settings) {
const oldVal = String(data.settings?.[key] ?? '').replace(/\r\n/g, '\n');
const newVal = String(settings[key] ?? '').replace(/\r\n/g, '\n');
if (oldVal !== newVal) {
hasChanges = true;
break;
}
}
// Configuration des rendus répétitifs
const clientOptionsGlobal = [
{ id: 'opt_collab', label: 'Travail en collaboration' },
{ id: 'opt_messaging', label: 'Messagerie des riverains' },
{ id: 'opt_newsletter', label: 'Info riverains' }
];
const clientOptionsChamps = [
{ id: 'simp_opt_description', label: 'Description des travaux' },
{ id: 'simp_opt_image', label: 'Vue du projet (Image)' },
{ id: 'simp_opt_theme', label: 'Couleur du thème' },
{ id: 'simp_opt_link', label: 'Lien vers le promoteur' },
{ id: 'simp_opt_emergency', label: 'Téléphone d\'urgence' },
{ id: 'simp_opt_schedule', label: 'Horaires de nuisances' }
];
const clientOptionsOnglets = [
{ id: 'simp_opt_hide_intervenants', label: 'Masquer l\'onglet Intervenants' },
{ id: 'simp_opt_hide_lots', label: 'Masquer l\'onglet Lots de travaux' },
{ id: 'simp_opt_hide_legal', label: 'Masquer l\'affichage public de l\'Arrêté' }
];
// Rendu UI
return (
<>
Règles et Options
Personnalisation des règles métier de .
{/* Options clients Unifiées */}
Options côté clients
Gérez la disponibilité globale des fonctionnalités pour l'ensemble des clients. L'état "En option" leur permet d'activer ou masquer eux-mêmes ces champs par projet.