init projet
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
// 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user