From 6ad76ca773d3e24ac104b4c4770649fb4188bf58 Mon Sep 17 00:00:00 2001 From: Anthony Coyaud Date: Sat, 15 Aug 2026 14:32:02 +0200 Subject: [PATCH] fix(front): corrige les 4 erreurs eslint restantes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le dépôt sortait 7 erreurs eslint au début de cette série de correctifs, dont certaines antérieures. Il n'en reste aucune. - Dashboard et Users appelaient setState de façon synchrone dans un effet, ce qui provoque des rendus en cascade. Le chargement initial passe par une fonction asynchrone qui n'écrit qu'après l'await, avec annulation au démontage. Sur le Dashboard, l'indicateur de chargement est allumé par les gestionnaires d'événement, et le bouton Actualiser relance l'effet via un compteur plutôt qu'en appelant le chargement. - L'import ExternalLink de Documentation.jsx n'était pas utilisé. - AuthContext.jsx exportait à la fois un composant, le contexte et un hook, ce qui désactivait le rafraîchissement à chaud de Vite pour ce fichier. Le contexte et le hook vivent désormais dans leurs propres modules ; les 5 fichiers concernés sont mis à jour. --- DataSentinel/src/App.jsx | 3 +- .../src/__tests__/AuthContext.test.jsx | 3 +- DataSentinel/src/components/Layout/Header.jsx | 2 +- .../src/components/Layout/Sidebar.jsx | 2 +- DataSentinel/src/context/AuthContext.jsx | 13 +--- DataSentinel/src/context/authContextObject.js | 7 +++ DataSentinel/src/context/useAuth.js | 15 +++++ .../src/pages/Dashboard/Dashboard.jsx | 61 ++++++++++++------- .../src/pages/Documentation/Documentation.jsx | 2 +- DataSentinel/src/pages/Login/Login.jsx | 2 +- DataSentinel/src/pages/Users/Users.jsx | 20 +++++- 11 files changed, 90 insertions(+), 40 deletions(-) create mode 100644 DataSentinel/src/context/authContextObject.js create mode 100644 DataSentinel/src/context/useAuth.js diff --git a/DataSentinel/src/App.jsx b/DataSentinel/src/App.jsx index 24306f8..94b658e 100644 --- a/DataSentinel/src/App.jsx +++ b/DataSentinel/src/App.jsx @@ -1,7 +1,8 @@ // src/App.jsx // Configuration du routing React Router v6 avec protection des routes import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; -import { AuthProvider, useAuth } from './context/AuthContext'; +import { AuthProvider } from './context/AuthContext'; +import { useAuth } from './context/useAuth'; import Layout from './components/Layout/Layout'; import Login from './pages/Login/Login'; import Dashboard from './pages/Dashboard/Dashboard'; diff --git a/DataSentinel/src/__tests__/AuthContext.test.jsx b/DataSentinel/src/__tests__/AuthContext.test.jsx index 439cba2..5c596f4 100644 --- a/DataSentinel/src/__tests__/AuthContext.test.jsx +++ b/DataSentinel/src/__tests__/AuthContext.test.jsx @@ -1,7 +1,8 @@ /* Tests du contexte d'authentification : login / logout */ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { renderHook, act } from '@testing-library/react'; -import { AuthProvider, useAuth } from '../context/AuthContext'; +import { AuthProvider } from '../context/AuthContext'; +import { useAuth } from '../context/useAuth'; import * as api from '../services/api'; describe('AuthContext', () => { diff --git a/DataSentinel/src/components/Layout/Header.jsx b/DataSentinel/src/components/Layout/Header.jsx index 3692e77..72c538d 100644 --- a/DataSentinel/src/components/Layout/Header.jsx +++ b/DataSentinel/src/components/Layout/Header.jsx @@ -1,7 +1,7 @@ /* En-tête fixe de l'application Data Sentinel */ import { Bell, LogOut, Menu } from 'lucide-react'; -import { useAuth } from '../../context/AuthContext'; +import { useAuth } from '../../context/useAuth'; import { useNavigate } from 'react-router-dom'; import styles from './Header.module.css'; diff --git a/DataSentinel/src/components/Layout/Sidebar.jsx b/DataSentinel/src/components/Layout/Sidebar.jsx index 082bd2d..8b6fba9 100644 --- a/DataSentinel/src/components/Layout/Sidebar.jsx +++ b/DataSentinel/src/components/Layout/Sidebar.jsx @@ -13,7 +13,7 @@ import { FileText, ScrollText, } from 'lucide-react'; -import { useAuth } from '../../context/AuthContext'; +import { useAuth } from '../../context/useAuth'; import styles from './Sidebar.module.css'; /* Un lien de navigation avec icône */ diff --git a/DataSentinel/src/context/AuthContext.jsx b/DataSentinel/src/context/AuthContext.jsx index aac8a26..dc3b5aa 100644 --- a/DataSentinel/src/context/AuthContext.jsx +++ b/DataSentinel/src/context/AuthContext.jsx @@ -1,10 +1,9 @@ /* Contexte d'authentification global : gestion de l'utilisateur connecté */ -import { createContext, useContext, useState } from 'react'; +import { useState } from 'react'; import * as api from '../services/api'; import { USER_KEY } from '../services/api'; - -const AuthContext = createContext(null); +import { AuthContext } from './authContextObject'; /* Fournisseur du contexte d'authentification */ export function AuthProvider({ children }) { @@ -39,11 +38,3 @@ export function AuthProvider({ children }) { ); } -/* Hook personnalisé pour accéder au contexte d'authentification */ -export function useAuth() { - const context = useContext(AuthContext); - if (!context) { - throw new Error('useAuth doit être utilisé dans un AuthProvider'); - } - return context; -} diff --git a/DataSentinel/src/context/authContextObject.js b/DataSentinel/src/context/authContextObject.js new file mode 100644 index 0000000..b1cba8b --- /dev/null +++ b/DataSentinel/src/context/authContextObject.js @@ -0,0 +1,7 @@ +/* Objet de contexte isolé : un fichier qui exporte un composant ne doit + exporter que des composants, sans quoi le rafraîchissement à chaud de Vite + (react-refresh) cesse de fonctionner pour ce fichier. */ + +import { createContext } from 'react'; + +export const AuthContext = createContext(null); diff --git a/DataSentinel/src/context/useAuth.js b/DataSentinel/src/context/useAuth.js new file mode 100644 index 0000000..429359d --- /dev/null +++ b/DataSentinel/src/context/useAuth.js @@ -0,0 +1,15 @@ +/* Hook d'accès au contexte d'authentification. + + Séparé de AuthContext.jsx : un fichier qui exporte à la fois un composant + et autre chose casse le rafraîchissement à chaud de Vite (react-refresh). */ + +import { useContext } from 'react'; +import { AuthContext } from './authContextObject'; + +export function useAuth() { + const context = useContext(AuthContext); + if (!context) { + throw new Error('useAuth doit être utilisé dans un AuthProvider'); + } + return context; +} diff --git a/DataSentinel/src/pages/Dashboard/Dashboard.jsx b/DataSentinel/src/pages/Dashboard/Dashboard.jsx index 979484a..ae98b6c 100644 --- a/DataSentinel/src/pages/Dashboard/Dashboard.jsx +++ b/DataSentinel/src/pages/Dashboard/Dashboard.jsx @@ -18,6 +18,7 @@ export default function Dashboard() { const [filtreCategorie, setFiltreCategorie] = useState(''); const [loading, setLoading] = useState(true); const [erreur, setErreur] = useState(''); + const [rafraichissement, setRafraichissement] = useState(0); /* Chargement initial des filtres. On n'utilise pas les référentiels SERVICE / CATEGORIE complets : ils @@ -52,39 +53,57 @@ export default function Dashboard() { /* Changer de service peut rendre la catégorie sélectionnée sans résultat : on la remet à zéro dans le même rendu, pour ne déclencher qu'un seul appel. */ function handleServiceChange(service) { + setLoading(true); setFiltreService(service); if (filtreCategorie && !categoriesDisponibles(service).includes(filtreCategorie)) { setFiltreCategorie(''); } } - /* Chargement des données dashboard */ - const loadData = useCallback(async () => { + function handleCategorieChange(categorie) { setLoading(true); - setErreur(''); - try { - const [sum, data] = await Promise.all([ - getDashboardSummary(), - getDashboard(filtreService, filtreCategorie), - ]); - setSummary(sum); - setMonitorings(Array.isArray(data) ? data : []); - } catch (e) { - setErreur(e.message || 'Erreur lors du chargement du dashboard.'); - } finally { - setLoading(false); - } - }, [filtreService, filtreCategorie]); + setFiltreCategorie(categorie); + } + /* Le bouton Actualiser relance l'effet en changeant cette valeur. */ + function handleActualiser() { + setLoading(true); + setRafraichissement(compteur => compteur + 1); + } + + /* Les données sont rechargées à chaque changement de filtre. L'indicateur de + chargement est allumé par les gestionnaires d'événement ci-dessus, jamais + dans l'effet : y appeler setState de façon synchrone provoquerait un rendu + en cascade. */ useEffect(() => { - loadData(); - }, [loadData]); + let annule = false; + + async function charger() { + try { + const [sum, data] = await Promise.all([ + getDashboardSummary(), + getDashboard(filtreService, filtreCategorie), + ]); + if (annule) return; + setSummary(sum); + setMonitorings(Array.isArray(data) ? data : []); + setErreur(''); + } catch (e) { + if (!annule) setErreur(e.message || 'Erreur lors du chargement du dashboard.'); + } finally { + if (!annule) setLoading(false); + } + } + + charger(); + return () => { annule = true; }; + }, [filtreService, filtreCategorie, rafraichissement]); return (

Dashboard

- @@ -131,7 +150,7 @@ export default function Dashboard() {