Ajout des cgu
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
// src/pages/CGU/CGU.jsx
|
||||
// Conditions Générales d'Utilisation — page publique sans sidebar
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import Button from '../../components/common/Button';
|
||||
import styles from './CGU.module.css';
|
||||
|
||||
export default function CGU() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<div className={styles.container}>
|
||||
<header className={styles.header}>
|
||||
<span className={styles.logo} aria-label="Data Sentinel">▶ Data Sentinel</span>
|
||||
<Button variant="link" onClick={() => navigate(-1)} aria-label="Retour à la page précédente">
|
||||
<ArrowLeft size={14} />
|
||||
Retour
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
<main id="main-content">
|
||||
<h1 className={styles.mainTitle}>Conditions Générales d'Utilisation</h1>
|
||||
<p className={styles.subtitle}>Version 1.0 — en vigueur depuis le 1er janvier 2026</p>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art1">
|
||||
<h2 id="art1">Article 1 — Objet et champ d'application</h2>
|
||||
<p>
|
||||
Les présentes Conditions Générales d'Utilisation (ci-après « CGU ») régissent l'accès et
|
||||
l'utilisation de la plateforme <strong>Data Sentinel</strong>, outil interne de monitoring
|
||||
de la qualité des données développé par COYAUD Anthony pour le compte de <strong>XEFI SA</strong>
|
||||
(ci-après « l'Éditeur »).
|
||||
</p>
|
||||
<p>
|
||||
Data Sentinel est une application web à usage professionnel interne, accessible uniquement
|
||||
aux collaborateurs habilités de XEFI et de ses filiales. Toute utilisation de la plateforme
|
||||
implique l'acceptation pleine et entière des présentes CGU.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art2">
|
||||
<h2 id="art2">Article 2 — Accès au service</h2>
|
||||
<p>
|
||||
L'accès à Data Sentinel est réservé aux utilisateurs disposant d'un compte valide créé
|
||||
par un administrateur système XEFI. L'authentification s'effectue via un identifiant et
|
||||
un mot de passe fournis par l'entreprise.
|
||||
</p>
|
||||
<ul className={styles.list}>
|
||||
<li>Chaque utilisateur est responsable de la confidentialité de ses identifiants.</li>
|
||||
<li>Le partage de comptes est strictement interdit.</li>
|
||||
<li>Tout accès non autorisé doit être signalé immédiatement au service informatique.</li>
|
||||
<li>L'Éditeur se réserve le droit de suspendre tout accès en cas d'utilisation non conforme.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art3">
|
||||
<h2 id="art3">Article 3 — Description du service</h2>
|
||||
<p>Data Sentinel offre les fonctionnalités suivantes :</p>
|
||||
<ul className={styles.list}>
|
||||
<li><strong>Dashboard</strong> — Vue d'ensemble des indicateurs clés de qualité des données (KPI).</li>
|
||||
<li><strong>Monitoring</strong> — Suivi en temps réel des monitorings CRM, Sage et Infocentre.</li>
|
||||
<li><strong>Vue consolidée</strong> — Agrégation des résultats par service et catégorie.</li>
|
||||
<li><strong>Historique</strong> — Consultation et export des données historiques.</li>
|
||||
<li><strong>Administration</strong> — Gestion des nomenclatures, utilisateurs et journaux.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art4">
|
||||
<h2 id="art4">Article 4 — Obligations de l'utilisateur</h2>
|
||||
<p>L'utilisateur s'engage à :</p>
|
||||
<ul className={styles.list}>
|
||||
<li>Utiliser la plateforme exclusivement dans le cadre de ses missions professionnelles.</li>
|
||||
<li>Ne pas tenter de contourner les mécanismes de sécurité (authentification, contrôle d'accès).</li>
|
||||
<li>Ne pas extraire, reproduire ou diffuser les données sans autorisation.</li>
|
||||
<li>Signaler tout dysfonctionnement ou anomalie de sécurité à l'équipe informatique.</li>
|
||||
<li>Respecter les règles internes XEFI relatives à la sécurité des systèmes d'information.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art5">
|
||||
<h2 id="art5">Article 5 — Protection des données personnelles (RGPD)</h2>
|
||||
<p>
|
||||
Conformément au Règlement Général sur la Protection des Données (UE 2016/679), XEFI SA
|
||||
traite les données personnelles des utilisateurs dans le strict respect de la réglementation.
|
||||
</p>
|
||||
<div className={styles.infoBox} role="note" aria-label="Informations RGPD">
|
||||
<p><strong>Responsable du traitement :</strong> XEFI SA — 2507 Avenue de l'Europe, 69140 Rillieux-la-Pape</p>
|
||||
<p><strong>Délégué à la Protection des Données (DPO) :</strong> dpo@xefi.fr</p>
|
||||
<p><strong>Finalité :</strong> Authentification, traçabilité des actions, sécurité du système.</p>
|
||||
<p><strong>Durée de conservation :</strong> 24 mois à compter de la dernière connexion.</p>
|
||||
<p><strong>Droits :</strong> Accès, rectification, effacement, portabilité — à exercer auprès de dpo@xefi.fr.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art6">
|
||||
<h2 id="art6">Article 6 — Accessibilité</h2>
|
||||
<p>
|
||||
XEFI s'engage à rendre Data Sentinel accessible conformément au Référentiel Général
|
||||
d'Amélioration de l'Accessibilité (RGAA). L'application respecte les principes WCAG 2.1
|
||||
niveau AA : perceptibilité, utilisabilité, compréhension et robustesse.
|
||||
</p>
|
||||
<ul className={styles.list}>
|
||||
<li>Navigation clavier intégrale supportée.</li>
|
||||
<li>Compatibilité avec les lecteurs d'écran (ARIA labels, landmarks, roles).</li>
|
||||
<li>Contrastes de couleurs conformes aux exigences WCAG 2.1 AA (ratio 4.5:1 minimum).</li>
|
||||
<li>Interface responsive adaptée aux écrans de 320px à 1920px.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Pour signaler un problème d'accessibilité : <strong>dpo@xefi.fr</strong>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art7">
|
||||
<h2 id="art7">Article 7 — Disponibilité et maintenance</h2>
|
||||
<p>
|
||||
L'Éditeur s'efforce de maintenir la plateforme disponible 24h/24, 7j/7, sans garantie
|
||||
de continuité de service. Des interruptions peuvent survenir pour maintenance planifiée
|
||||
ou en cas d'incident technique. Les utilisateurs seront prévenus dans la mesure du possible.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art8">
|
||||
<h2 id="art8">Article 8 — Propriété intellectuelle</h2>
|
||||
<p>
|
||||
L'ensemble des éléments composant Data Sentinel (code source, design, données, documentation)
|
||||
est la propriété exclusive de <strong>XEFI SA</strong>. Toute reproduction, modification
|
||||
ou diffusion sans autorisation écrite préalable est interdite.
|
||||
</p>
|
||||
<p>Application développée par <strong>COYAUD Anthony</strong> — Bachelor DBI, Nexa Digital School, 2026.</p>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art9">
|
||||
<h2 id="art9">Article 9 — Modification des CGU</h2>
|
||||
<p>
|
||||
XEFI SA se réserve le droit de modifier les présentes CGU à tout moment. Les utilisateurs
|
||||
seront informés de toute modification substantielle. La poursuite de l'utilisation de la
|
||||
plateforme après notification vaut acceptation des nouvelles conditions.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className={styles.section} aria-labelledby="art10">
|
||||
<h2 id="art10">Article 10 — Droit applicable et contact</h2>
|
||||
<p>Les présentes CGU sont soumises au droit français. Pour toute question :</p>
|
||||
<div className={styles.infoBox} role="note" aria-label="Coordonnées de contact">
|
||||
<p><strong>XEFI SA</strong></p>
|
||||
<p>2507 Avenue de l'Europe — 69140 Rillieux-la-Pape</p>
|
||||
<p>Email : dpo@xefi.fr</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer className={styles.footer} role="contentinfo">
|
||||
<p>Data Sentinel v1.0 — © XEFI SA 2026</p>
|
||||
<nav aria-label="Liens légaux">
|
||||
<a href="/mentions-legales">Mentions légales</a>
|
||||
</nav>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/* src/pages/CGU/CGU.module.css */
|
||||
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background-color: var(--color-white);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.mainTitle {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 12px;
|
||||
padding-left: 14px;
|
||||
border-left: 4px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.section p {
|
||||
margin: 8px 0;
|
||||
line-height: 1.65;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.list {
|
||||
list-style: disc;
|
||||
padding-left: 24px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.list li {
|
||||
margin: 6px 0;
|
||||
line-height: 1.6;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.infoBox {
|
||||
background-color: var(--color-gray-light);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
border-radius: var(--radius);
|
||||
padding: 16px 20px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.infoBox p {
|
||||
margin: 4px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 64px;
|
||||
padding: 16px 24px;
|
||||
background-color: var(--color-black);
|
||||
color: var(--color-white);
|
||||
text-align: center;
|
||||
margin-left: -24px;
|
||||
margin-right: -24px;
|
||||
margin-bottom: -24px;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.footer nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.footer nav a {
|
||||
color: #aaa;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer nav a:hover {
|
||||
color: var(--color-white);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 640px) {
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.mainTitle {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
@@ -108,3 +108,49 @@
|
||||
padding: 32px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 640px) {
|
||||
.page {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.pageHeader {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.kpiGrid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.kpiValue {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.filtres {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.select {
|
||||
width: 100%;
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// src/pages/Documentation/Documentation.jsx
|
||||
// Page documentation technique de Data Sentinel
|
||||
import { ExternalLink, Book, Code, Database, Shield } from 'lucide-react';
|
||||
import styles from './Documentation.module.css';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
icon: Book,
|
||||
title: 'Guide utilisateur',
|
||||
items: [
|
||||
{ label: 'Dashboard — Lecture des KPI et monitorings', desc: 'Comprendre les indicateurs clés : total, sans erreur, en erreur, total erreurs.' },
|
||||
{ label: 'Vue consolidée — Agrégation par service', desc: 'Analyse croisée des résultats par service métier et catégorie de monitoring.' },
|
||||
{ label: 'Historique — Export et graphiques', desc: 'Consultation des données passées avec export CSV et visualisation en courbe.' },
|
||||
{ label: 'Gestion des contrats et fournisseurs', desc: 'Référentiel des contrats de service et fournisseurs associés.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: Code,
|
||||
title: 'Architecture technique',
|
||||
items: [
|
||||
{ label: 'Frontend — React 18 + Vite', desc: 'SPA React 18 avec CSS Modules, React Router v7, Recharts. Build Vite.' },
|
||||
{ label: 'Backend — API REST', desc: 'API REST avec authentification JWT. Endpoints documentés via Swagger.' },
|
||||
{ label: 'Base de données — SQL Server', desc: 'SQL Server avec vues SQL optimisées et jobs CRON pour les agrégations.' },
|
||||
{ label: 'Infrastructure — NEXERN (XEFI)', desc: 'Hébergement souverain français sur les datacenters NEXERN de XEFI.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: Database,
|
||||
title: 'Monitorings disponibles',
|
||||
items: [
|
||||
{ label: 'CRM — Données clients et prospects', desc: 'Surveillance de la cohérence et de la complétude des données CRM.' },
|
||||
{ label: 'Sage — Données comptables et financières', desc: 'Contrôle qualité des flux comptables issus de Sage.' },
|
||||
{ label: 'Infocentre — Reporting décisionnel', desc: 'Validation des données alimentant les rapports de direction.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: 'Sécurité et conformité',
|
||||
items: [
|
||||
{ label: 'Authentification JWT', desc: 'Token JWT stocké en sessionStorage, expiration automatique.' },
|
||||
{ label: 'Contrôle d\'accès RBAC', desc: 'Rôles : Administrateur, Superviseur, Consultant. Accès aux fonctions selon le rôle.' },
|
||||
{ label: 'Conformité RGPD', desc: 'Conservation 24 mois, DPO joignable sur dpo@xefi.fr, droits exercés à la demande.' },
|
||||
{ label: 'Accessibilité RGAA / WCAG 2.1 AA', desc: 'Navigation clavier, ARIA, contrastes conformes, responsive 320px–1920px.' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function Documentation() {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<div className={styles.pageHeader}>
|
||||
<h1 className={styles.title}>Documentation</h1>
|
||||
<p className={styles.subtitle}>Référence technique et guide d'utilisation de Data Sentinel</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.grid}>
|
||||
{sections.map(({ icon: Icon, title, items }) => (
|
||||
<section key={title} className={styles.card} aria-labelledby={`section-${title.replace(/\s+/g, '-')}`}>
|
||||
<div className={styles.cardHeader}>
|
||||
<Icon size={18} className={styles.cardIcon} aria-hidden="true" />
|
||||
<h2 id={`section-${title.replace(/\s+/g, '-')}`} className={styles.cardTitle}>{title}</h2>
|
||||
</div>
|
||||
<ul className={styles.list}>
|
||||
{items.map(({ label, desc }) => (
|
||||
<li key={label} className={styles.item}>
|
||||
<span className={styles.itemLabel}>{label}</span>
|
||||
<span className={styles.itemDesc}>{desc}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className={styles.footer}>
|
||||
<p>Data Sentinel v1.0 — Développé par COYAUD Anthony, Nexa Digital School 2026</p>
|
||||
<p>
|
||||
<a href="/cgu" className={styles.link}>CGU</a>
|
||||
{' · '}
|
||||
<a href="/mentions-legales" className={styles.link}>Mentions légales</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* src/pages/Documentation/Documentation.module.css */
|
||||
|
||||
.page {
|
||||
max-width: 1100px;
|
||||
}
|
||||
|
||||
.pageHeader {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--color-white);
|
||||
border: 1px solid var(--color-gray-border);
|
||||
border-radius: var(--radius);
|
||||
padding: 20px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.cardHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--color-gray-border);
|
||||
}
|
||||
|
||||
.cardIcon {
|
||||
color: var(--color-primary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.itemLabel {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.itemDesc {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.footer {
|
||||
border-top: 1px solid var(--color-gray-border);
|
||||
padding-top: 20px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-secondary);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: var(--color-text-secondary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
color: var(--color-text);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// src/pages/Journal/Journal.jsx
|
||||
// Page Journal d'audit — historique des actions utilisateurs
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getJournal } from '../../services/api';
|
||||
import DataTable from '../../components/common/DataTable';
|
||||
import LoadingSpinner from '../../components/common/LoadingSpinner';
|
||||
import ErrorMessage from '../../components/common/ErrorMessage';
|
||||
import styles from './Journal.module.css';
|
||||
|
||||
export default function Journal() {
|
||||
const [entries, setEntries] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [erreur, setErreur] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
setLoading(true);
|
||||
setErreur('');
|
||||
try {
|
||||
const data = await getJournal();
|
||||
setEntries(Array.isArray(data) ? data : []);
|
||||
} catch (e) {
|
||||
setErreur(e.message || 'Erreur lors du chargement du journal.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
load();
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{ key: 'date_action', label: 'Date' },
|
||||
{ key: 'utilisateur', label: 'Utilisateur' },
|
||||
{ key: 'action', label: 'Action' },
|
||||
{ key: 'detail', label: 'Détail' },
|
||||
{ key: 'ip', label: 'Adresse IP' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<h1 className={styles.title}>Journal d'audit</h1>
|
||||
<p className={styles.description}>
|
||||
Historique des actions effectuées sur la plateforme par les utilisateurs.
|
||||
</p>
|
||||
|
||||
{loading ? (
|
||||
<LoadingSpinner message="Chargement du journal..." />
|
||||
) : erreur ? (
|
||||
<ErrorMessage message={erreur} />
|
||||
) : (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={entries}
|
||||
pageSize={50}
|
||||
emptyMessage="Aucune entrée dans le journal."
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/* src/pages/Journal/Journal.module.css */
|
||||
|
||||
.page {
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.description {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
Reference in New Issue
Block a user