diff --git a/src/App.module.css b/src/App.module.css index cc9891a..9809684 100644 --- a/src/App.module.css +++ b/src/App.module.css @@ -14,9 +14,7 @@ .main { flex: 1; - /* Sans min-width:0 un élément flex garde min-width:auto et déborde de son - conteneur dès qu'il contient un bloc large (tableau, titre non coupable) : - la page entière part alors plus large que l'écran. */ + min-width: 0; margin-left: 16rem; padding: 2rem; diff --git a/src/App.tsx b/src/App.tsx index b41ba9c..642ced1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -104,9 +104,7 @@ export default function App() { : location.pathname === "/admin"? "admin" : "home"; - // Le user de localStorage est un instantané pris au login : un changement de - // rôle en base n'y apparaît jamais. On le resynchronise depuis /me au montage, - // sinon un compte promu admin reste bloqué hors de /admin jusqu'à reconnexion. + useEffect(() => { const token = localStorage.getItem("authToken"); if (!token) return; @@ -155,7 +153,7 @@ export default function App() { ); } - // ← CookieBanner visible même sans connexion + if (!authState.isAuthenticated) { return ( <> diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx index 7e51dc8..80f2e91 100644 --- a/src/components/Pagination.tsx +++ b/src/components/Pagination.tsx @@ -10,7 +10,6 @@ type PaginationProps = { type PageEntry = number | "ellipsis"; -/** Fenêtre de numéros affichés : les extrémités restent toujours atteignables. */ function buildPageList(currentPage: number, totalPages: number): PageEntry[] { if (totalPages <= MAX_VISIBLE_PAGES) { return Array.from({ length: totalPages }, (_, index) => index + 1); diff --git a/src/pages/AboutPage.tsx b/src/pages/AboutPage.tsx index 40a5df3..75eae80 100644 --- a/src/pages/AboutPage.tsx +++ b/src/pages/AboutPage.tsx @@ -10,7 +10,6 @@ export default function AboutPage() {

Plateforme de veille réglementaire pour les ingrédients cosmétiques

- {/* Mission Section */}
@@ -26,7 +25,6 @@ export default function AboutPage() {

- {/* Pour Qui Section */}
@@ -74,7 +72,6 @@ export default function AboutPage() {
- {/* Key Features */}
@@ -110,7 +107,6 @@ export default function AboutPage() {
- {/* About Platform */}
diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx index c1f0fdd..b08874b 100644 --- a/src/pages/Admin.tsx +++ b/src/pages/Admin.tsx @@ -9,9 +9,7 @@ type Document = { id: string; title: string; source: 'CIR' | 'SCCS'; ingredient? type ScraperLog = { id: string; when: string; source: string; status: 'pending' | 'running' | 'success' | 'error' } type Stats = { total_documents?: number; cir_documents?: number; sccs_documents?: number; total_users?: number } -// Un jeton absent ou expiré (30 min de validité) renvoie 401. Le message -// générique laissait croire à une panne du serveur alors qu'il suffit de se -// reconnecter — l'interface, elle, croit toujours la session ouverte. + function assertOk(res: Response, fallback: string){ if(res.ok) return if(res.status === 401){ @@ -42,7 +40,6 @@ export default function Admin() { const [sortKey, setSortKey] = useState(null) const [sortDir, setSortDir] = useState<'asc'|'desc'>('asc') - // Jeton posé par App.tsx au login (handleAuthSuccess). const token = localStorage.getItem('authToken') ?? '' useEffect(() => { diff --git a/src/pages/AuthPage.tsx b/src/pages/AuthPage.tsx index 4983d84..c9526ac 100644 --- a/src/pages/AuthPage.tsx +++ b/src/pages/AuthPage.tsx @@ -72,7 +72,6 @@ export default function AuthPage({ onAuthSuccess }: { onAuthSuccess: (token: str const userData = await response.json(); - // Automatiquement connecter après l'inscription const loginResponse = await fetch(`${API_URL}/login`, { method: "POST", headers: { diff --git a/src/pages/ContactPage.tsx b/src/pages/ContactPage.tsx index c4617b6..9fbfc8f 100644 --- a/src/pages/ContactPage.tsx +++ b/src/pages/ContactPage.tsx @@ -35,11 +35,8 @@ export default function ContactPage() {

Nous sommes à votre écoute pour toute question ou demande d'information

- {/* Main Content */}
- {/* Contact Info */}
- {/* Email */}

@@ -55,7 +52,6 @@ export default function ContactPage() {

- {/* Phone */}

@@ -208,7 +204,6 @@ export default function ContactPage() {

- {/* FAQ Section */}

Questions Fréquentes

diff --git a/src/pages/Documents.tsx b/src/pages/Documents.tsx index 0a95231..658d9cb 100644 --- a/src/pages/Documents.tsx +++ b/src/pages/Documents.tsx @@ -106,7 +106,6 @@ export default function DocumentsPage() { safePage * itemsPerPage ); - // adjust items per page based on viewport width useEffect(() => { const apply = () => { const w = window.innerWidth; @@ -130,7 +129,6 @@ export default function DocumentsPage() { return (
- {/* HEADER */}

Document Database

@@ -138,7 +136,6 @@ export default function DocumentsPage() {

- {/* FILTERS */}
@@ -196,7 +193,6 @@ export default function DocumentsPage() {
- {/* STATS */}

Total Documents: @@ -207,7 +203,6 @@ export default function DocumentsPage() {

- {/* TABLE */}
Title diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 67c1170..076e8d5 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -22,7 +22,6 @@ export default function HomePage({ handleNavClick, recentDocuments }: HomePagePr
- {/* Hero Section */}

RegWatch MedLabs

Cosmetic Regulatory Monitoring Platform

@@ -31,7 +30,6 @@ export default function HomePage({ handleNavClick, recentDocuments }: HomePagePr

- {/* Feature Cards */}
- {/* Recent Documents */}
diff --git a/src/pages/IngredientSearchPage.tsx b/src/pages/IngredientSearchPage.tsx index 28f9a09..b30a1db 100644 --- a/src/pages/IngredientSearchPage.tsx +++ b/src/pages/IngredientSearchPage.tsx @@ -15,7 +15,6 @@ export default function IngredientSearchPage() { const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage, setItemsPerPage] = useState(8); - // FETCH API useEffect(() => { getDocuments() .then((data) => setDocuments(Array.isArray(data) ? data : [])) @@ -26,7 +25,6 @@ export default function IngredientSearchPage() { .finally(() => setLoading(false)); }, []); - // responsive items per page useEffect(() => { const apply = () => { const w = window.innerWidth; @@ -39,7 +37,6 @@ export default function IngredientSearchPage() { return () => window.removeEventListener('resize', apply); }, []); - // FILTER OPTIONS const allSources = useMemo(() => [ "All Sources", ...new Set(documents.map((d) => d.source)), @@ -55,7 +52,6 @@ export default function IngredientSearchPage() { ...new Set(documents.map((d) => String(d.date ?? "").slice(0, 4))).values(), ], [documents]); - // FILTERED RESULTS const filtered = useMemo(() => { return documents .filter((d) => { @@ -82,13 +78,11 @@ export default function IngredientSearchPage() {
- {/* HEADER */}

Ingredient Search

Search cosmetic ingredients and regulatory documents

- {/* SEARCH */}
- {/* FILTERS */}
@@ -121,12 +114,10 @@ export default function IngredientSearchPage() {
- {/* RESULTS */}
{filtered.length} results found
- {/* DOCUMENTS */}
{filtered.length === 0 ? (
diff --git a/src/pages/RecentUpdatesPage.tsx b/src/pages/RecentUpdatesPage.tsx index 31a9246..3134ec7 100644 --- a/src/pages/RecentUpdatesPage.tsx +++ b/src/pages/RecentUpdatesPage.tsx @@ -81,7 +81,6 @@ export default function RecentUpdatesPage() { return (
- {/* HEADER */}
@@ -92,7 +91,6 @@ export default function RecentUpdatesPage() {

- {/* STATS */}

Total Updates

@@ -111,7 +109,6 @@ export default function RecentUpdatesPage() {
- {/* FILTERS */}
@@ -143,13 +140,11 @@ export default function RecentUpdatesPage() {
- {/* RESULTS */}
{filtered.length}{" "} updates found
- {/* TABLE */}
Status diff --git a/src/services/theapi.ts b/src/services/theapi.ts index 6a9b0ba..eecd61f 100644 --- a/src/services/theapi.ts +++ b/src/services/theapi.ts @@ -1,5 +1,3 @@ -// Bakée au build par Vite (ARG/ENV VITE_API_URL du Dockerfile). -// Repli sur l'API locale pour le dev : `pnpm dev` sans .env continue de marcher. export const API_URL = import.meta.env.VITE_API_URL ?? "http://127.0.0.1:8000"; export type ApiDocument = { diff --git a/src/styles/Admin.module.css b/src/styles/Admin.module.css index e753d61..165c706 100644 --- a/src/styles/Admin.module.css +++ b/src/styles/Admin.module.css @@ -1,12 +1,4 @@ -/* Administration — aligné sur la DA des autres pages : - accent violet #7c3aed (celui de la Sidebar), échelle de gris Tailwind, - cartes blanches bordées, rayons 0.5/0.75rem, unités rem. */ -/* main.tsx ne charge pas styles/global.css — vestige d'une ancienne maquette, - jamais importé — donc son `* { box-sizing: border-box }` ne s'applique pas et - l'application tourne en content-box : tout width:100% assorti d'un padding - déborde de son conteneur. Réinitialisation cantonnée à cette page pour ne rien - déplacer sur le reste du site. */ .page, .page *, .page *::before, @@ -22,7 +14,6 @@ margin: 0 auto; } -/* ── En-tête et onglets ─────────────────────────────────────── */ .header { display: flex; @@ -47,8 +38,6 @@ gap: 0.5rem; min-width: 0; max-width: 100%; - /* Les onglets passent à la ligne quand ils ne tiennent plus, plutôt que de - défiler : aucun n'est masqué hors champ. */ flex-wrap: wrap; } @@ -88,7 +77,6 @@ margin-top: 0.5rem; } -/* ── États ──────────────────────────────────────────────────── */ .spinner { padding: 0.875rem 1rem; @@ -114,7 +102,6 @@ color: rgb(107, 114, 128); } -/* ── Barre de panneau ───────────────────────────────────────── */ .panelHeader { display: flex; @@ -137,8 +124,6 @@ max-width: 22rem; } -/* ── Tableaux ───────────────────────────────────────────────── */ - .tableWrap { background: white; border: 1px solid rgb(229, 231, 235); @@ -161,7 +146,6 @@ overflow-wrap: anywhere; } -/* Sans cette borne, un seul titre long étire la colonne et donc tout le tableau. */ .table td:nth-child(2) { min-width: 12rem; max-width: 26rem; @@ -223,7 +207,6 @@ color: white; } -/* ── Badges ─────────────────────────────────────────────────── */ .badgeAdmin, .badgeUser, @@ -270,7 +253,6 @@ border: 1px solid rgba(16, 185, 129, 0.3); } -/* ── Statistiques ───────────────────────────────────────────── */ .cards { display: grid; @@ -342,8 +324,7 @@ color: rgb(55, 65, 81); } -/* La largeur est posée en style inline par le composant : min-width garde une - amorce visible quand la valeur est nulle. */ + .barFill { height: 0.625rem; min-width: 0.625rem; @@ -363,7 +344,6 @@ color: rgb(75, 85, 99); } -/* ── Scrapers ───────────────────────────────────────────────── */ .scraperControls { display: grid; @@ -432,7 +412,6 @@ color: rgb(17, 24, 39); } -/* ── Modale ─────────────────────────────────────────────────── */ .modalBackdrop { position: fixed; @@ -478,7 +457,6 @@ color: white; } -/* ── Responsive ─────────────────────────────────────────────── */ @media (max-width: 1024px) { .scraperControls { @@ -509,8 +487,6 @@ .tabs { width: 100%; } - - /* Chaque ligne devient une carte, avec l'intitulé de colonne en regard. */ .tableWrap { background: transparent; border: none; @@ -548,10 +524,6 @@ background: white; } - /* Surtout pas display:flex ici : le texte de la cellule deviendrait un élément - flex anonyme, avec min-width:auto — un titre long refuserait de se réduire et - sortirait de la carte, en entraînant toute la page. En bloc, l'intitulé passe - au-dessus de la valeur et la coupure de mots suffit. */ .table td { display: block; padding: 0.5rem 1rem; @@ -572,8 +544,7 @@ margin-bottom: 0.125rem; } - /* `.table td { display: block }` l'emporte en spécificité sur `.rowActions` : - on le rétablit ici pour garder les actions sur une rangée. */ + .table td.rowActions { display: flex; } @@ -614,6 +585,4 @@ } } -/* NB : le site n'a pas de mode sombre réel — index.css bascule --bg sur le body - mais aucune page n'utilise ces variables et toutes gardent des cartes claires. - Cette page suit la même convention pour rester cohérente avec ses sœurs. */ + diff --git a/src/styles/BackToTop.module.css b/src/styles/BackToTop.module.css index b32bb51..b3567ad 100644 --- a/src/styles/BackToTop.module.css +++ b/src/styles/BackToTop.module.css @@ -1 +1,12 @@ -.btn{position:fixed;right:20px;bottom:20px;background:#1e293b;color:#fff;border:none;border-radius:999px;width:44px;height:44px;font-size:20px;cursor:pointer;box-shadow:0 8px 20px rgba(2,6,23,0.2);z-index:12000} +.btn{ + position:fixed; + right:20px;bottom:20px; + background:#1e293b; + color:#fff;border:none; + border-radius:999px; + width:44px; + height:44px; + font-size:20px; + cursor:pointer; + box-shadow:0 8px 20px rgba(2,6,23,0.2); + z-index:12000} diff --git a/src/styles/Pagination.module.css b/src/styles/Pagination.module.css index eb2abf1..ba701e4 100644 --- a/src/styles/Pagination.module.css +++ b/src/styles/Pagination.module.css @@ -1,6 +1,3 @@ -/* Style unique de pagination, partagé par toutes les pages. - Reprend l'accent bleu #2563eb du site (boutons primaires, liens d'action). */ - .pagination { display: flex; align-items: center; diff --git a/src/styles/Sidebar.module.css b/src/styles/Sidebar.module.css index 8410fc4..ac47c67 100644 --- a/src/styles/Sidebar.module.css +++ b/src/styles/Sidebar.module.css @@ -194,5 +194,4 @@ .open{transform:translateX(0)} - /* overlay will be handled by a simple full-screen element appended in DOM via JS if needed */ } \ No newline at end of file diff --git a/src/styles/Toast.module.css b/src/styles/Toast.module.css index f7231b6..2b2b526 100644 --- a/src/styles/Toast.module.css +++ b/src/styles/Toast.module.css @@ -1,5 +1,27 @@ -.container{position:fixed;left:16px;bottom:24px;display:flex;flex-direction:column-reverse;gap:8px;z-index:12000} -.toast{padding:10px 14px;border-radius:8px;color:#fff;box-shadow:0 6px 18px rgba(2,6,23,0.12);min-width:200px} -.info{background:#334155} -.success{background:#059669} -.error{background:#ef4444} +.container{ + position:fixed; + left:16px; + bottom:24px; + display:flex; + flex-direction:column-reverse; + gap:8px; + z-index:12000 +} +.toast{padding:10px 14px; + border-radius:8px + ;color:#fff; + box-shadow:0 6px 18px rgba(2,6,23,0.12); + min-width:200px +} + +.info{ + background:#334155 +} + +.success{ + background:#059669 +} + +.error{ + background:#ef4444 +} diff --git a/src/styles/global.css b/src/styles/global.css index 6071c50..50fdb74 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -4,7 +4,6 @@ body { background: #f4f6f8; } -/* Global required rules */ * { box-sizing: border-box; } img, table { max-width: 100%; }