230 lines
7.0 KiB
React
230 lines
7.0 KiB
React
// src/pages/Admin/Admin.jsx
|
||
// Page Administration : onglets pour gérer monitorings, services, catégories, contacts
|
||
import { useState, useEffect } from 'react';
|
||
import { Plus, Edit, Trash2 } from 'lucide-react';
|
||
import { getMonitorings, getServices, getCategories, getContacts } from '../../services/api';
|
||
import DataTable from '../../components/common/DataTable';
|
||
import LoadingSpinner from '../../components/common/LoadingSpinner';
|
||
import ErrorMessage from '../../components/common/ErrorMessage';
|
||
import Button from '../../components/common/Button';
|
||
import styles from './Admin.module.css';
|
||
|
||
/* Modale générique pour ajouter/modifier */
|
||
function Modal({ isOpen, onClose, title, children }) {
|
||
if (!isOpen) return null;
|
||
|
||
return (
|
||
<div className={styles.modalOverlay} onClick={onClose}>
|
||
<div className={styles.modal} onClick={e => e.stopPropagation()}>
|
||
<div className={styles.modalHeader}>
|
||
<h2>{title}</h2>
|
||
<button className={styles.closeBtn} onClick={onClose}>×</button>
|
||
</div>
|
||
<div className={styles.modalBody}>
|
||
{children}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default function Admin() {
|
||
const [activeTab, setActiveTab] = useState('monitorings');
|
||
const [data, setData] = useState({});
|
||
const [loading, setLoading] = useState(true);
|
||
const [erreur, setErreur] = useState('');
|
||
const [modalOpen, setModalOpen] = useState(false);
|
||
const [editingItem, setEditingItem] = useState(null);
|
||
|
||
useEffect(() => {
|
||
async function loadData() {
|
||
setLoading(true);
|
||
setErreur('');
|
||
try {
|
||
const [monitorings, services, categories, contacts] = await Promise.all([
|
||
getMonitorings(),
|
||
getServices(),
|
||
getCategories(),
|
||
getContacts()
|
||
]);
|
||
setData({
|
||
monitorings: Array.isArray(monitorings) ? monitorings : [],
|
||
services: Array.isArray(services) ? services : [],
|
||
categories: Array.isArray(categories) ? categories : [],
|
||
contacts: Array.isArray(contacts) ? contacts : []
|
||
});
|
||
} catch (e) {
|
||
setErreur(e.message || 'Erreur lors du chargement des données administratives.');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
loadData();
|
||
}, []);
|
||
|
||
function handleAdd() {
|
||
setEditingItem(null);
|
||
setModalOpen(true);
|
||
}
|
||
|
||
function handleEdit(item) {
|
||
setEditingItem(item);
|
||
setModalOpen(true);
|
||
}
|
||
|
||
function handleDelete(item) {
|
||
// Simulation de suppression (pas d'API pour ça)
|
||
console.log('Supprimer', item);
|
||
}
|
||
|
||
const tabs = [
|
||
{ key: 'monitorings', label: 'Monitorings' },
|
||
{ key: 'services', label: 'Services' },
|
||
{ key: 'categories', label: 'Catégories' },
|
||
{ key: 'contacts', label: 'Contacts' }
|
||
];
|
||
|
||
const columns = {
|
||
monitorings: [
|
||
{ key: 'monito_intitule', label: 'Nom' },
|
||
{ key: 'id_service', label: 'Service' },
|
||
{ key: 'id_categorie', label: 'Catégorie' },
|
||
{ key: 'bdd_source', label: 'Source' },
|
||
{ key: 'table_source', label: 'Table' },
|
||
{
|
||
key: 'actions',
|
||
label: 'Actions',
|
||
render: (val, row) => (
|
||
<div className={styles.actions}>
|
||
<button className={styles.actionBtn} onClick={() => handleEdit(row)}>
|
||
<Edit size={14} />
|
||
Modifier
|
||
</button>
|
||
<button className={styles.actionBtn} onClick={() => handleDelete(row)}>
|
||
<Trash2 size={14} />
|
||
Désactiver
|
||
</button>
|
||
</div>
|
||
)
|
||
}
|
||
],
|
||
services: [
|
||
{ key: 'nom_service', label: 'Nom' },
|
||
{
|
||
key: 'actions',
|
||
label: 'Actions',
|
||
render: (val, row) => (
|
||
<div className={styles.actions}>
|
||
<button className={styles.actionBtn} onClick={() => handleEdit(row)}>
|
||
<Edit size={14} />
|
||
Modifier
|
||
</button>
|
||
<button className={styles.actionBtn} onClick={() => handleDelete(row)}>
|
||
<Trash2 size={14} />
|
||
Désactiver
|
||
</button>
|
||
</div>
|
||
)
|
||
}
|
||
],
|
||
categories: [
|
||
{ key: 'intitule_categorie', label: 'Nom' },
|
||
{
|
||
key: 'actions',
|
||
label: 'Actions',
|
||
render: (val, row) => (
|
||
<div className={styles.actions}>
|
||
<button className={styles.actionBtn} onClick={() => handleEdit(row)}>
|
||
<Edit size={14} />
|
||
Modifier
|
||
</button>
|
||
<button className={styles.actionBtn} onClick={() => handleDelete(row)}>
|
||
<Trash2 size={14} />
|
||
Désactiver
|
||
</button>
|
||
</div>
|
||
)
|
||
}
|
||
],
|
||
contacts: [
|
||
{ key: 'intitule_contact', label: 'Intitulé' },
|
||
{ key: 'nom', label: 'Nom' },
|
||
{ key: 'prenom', label: 'Prénom' },
|
||
{ key: 'mail', label: 'Email' },
|
||
{ key: 'id_service', label: 'Service' },
|
||
{
|
||
key: 'actions',
|
||
label: 'Actions',
|
||
render: (val, row) => (
|
||
<div className={styles.actions}>
|
||
<button className={styles.actionBtn} onClick={() => handleEdit(row)}>
|
||
<Edit size={14} />
|
||
Modifier
|
||
</button>
|
||
<button className={styles.actionBtn} onClick={() => handleDelete(row)}>
|
||
<Trash2 size={14} />
|
||
Désactiver
|
||
</button>
|
||
</div>
|
||
)
|
||
}
|
||
]
|
||
};
|
||
|
||
if (loading) return <LoadingSpinner message="Chargement des données administratives..." />;
|
||
if (erreur) return <ErrorMessage message={erreur} />;
|
||
|
||
return (
|
||
<div className={styles.page}>
|
||
<h1 className={styles.title}>Administration</h1>
|
||
|
||
{/* Onglets */}
|
||
<div className={styles.tabs}>
|
||
{tabs.map(tab => (
|
||
<button
|
||
key={tab.key}
|
||
className={`${styles.tab} ${activeTab === tab.key ? styles.active : ''}`}
|
||
onClick={() => setActiveTab(tab.key)}
|
||
>
|
||
{tab.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Contenu de l'onglet actif */}
|
||
<div className={styles.tabContent}>
|
||
<div className={styles.header}>
|
||
<h2>{tabs.find(t => t.key === activeTab)?.label}</h2>
|
||
<Button variant="primary" onClick={handleAdd}>
|
||
<Plus size={14} />
|
||
Ajouter
|
||
</Button>
|
||
</div>
|
||
|
||
<DataTable
|
||
columns={columns[activeTab]}
|
||
data={data[activeTab] || []}
|
||
pageSize={50}
|
||
emptyMessage={`Aucun ${activeTab.slice(0, -1)} trouvé.`}
|
||
/>
|
||
</div>
|
||
|
||
{/* Modale */}
|
||
<Modal
|
||
isOpen={modalOpen}
|
||
onClose={() => setModalOpen(false)}
|
||
title={`${editingItem ? 'Modifier' : 'Ajouter'} ${tabs.find(t => t.key === activeTab)?.label.slice(0, -1)}`}
|
||
>
|
||
<p>Formulaire à implémenter selon les besoins.</p>
|
||
<div className={styles.modalActions}>
|
||
<Button variant="secondary" onClick={() => setModalOpen(false)}>
|
||
Annuler
|
||
</Button>
|
||
<Button variant="primary" onClick={() => setModalOpen(false)}>
|
||
Enregistrer
|
||
</Button>
|
||
</div>
|
||
</Modal>
|
||
</div>
|
||
);
|
||
} |