From 206578605233e32ac21b360fbd1627a4b6f2e221 Mon Sep 17 00:00:00 2001 From: Manus Date: Mon, 16 Mar 2026 15:00:15 -0400 Subject: [PATCH] =?UTF-8?q?Checkpoint:=20Bouton=20=C5=93il=20(Eye)=20ajout?= =?UTF-8?q?=C3=A9=20sur=20chaque=20ligne=20du=20tableau=20Veille=20(vue=20?= =?UTF-8?q?liste=20et=20vignettes)=20ouvrant=20une=20bo=C3=AEte=20de=20dia?= =?UTF-8?q?logue=20avec=20titre=20complet,=20badge=20type=20color=C3=A9,?= =?UTF-8?q?=20m=C3=A9tadonn=C3=A9es=20en=20grille=20(cat=C3=A9gorie,=20niv?= =?UTF-8?q?eau,=20territoire,=20source,=20passage=20en=20vigueur),=20r?= =?UTF-8?q?=C3=A9sum=C3=A9=20int=C3=A9gral=20et=20lien=20externe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/VeilleDashboard.tsx | 220 +++++++++++++++++++++++++-- todo.md | 1 + 2 files changed, 205 insertions(+), 16 deletions(-) diff --git a/client/src/pages/VeilleDashboard.tsx b/client/src/pages/VeilleDashboard.tsx index 2e19493..80df777 100644 --- a/client/src/pages/VeilleDashboard.tsx +++ b/client/src/pages/VeilleDashboard.tsx @@ -5,6 +5,12 @@ import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; import { LayoutGrid, List, @@ -17,6 +23,9 @@ import { Loader2, ChevronLeft, ChevronRight, + Eye, + Globe, + BookOpen, } from "lucide-react"; import { cn } from "@/lib/utils"; import { format } from "date-fns"; @@ -32,6 +41,8 @@ interface VeilleItem { niveau: string | null; territoire: string | null; resume: string | null; + source: string | null; + passage: string | null; lien: string | null; datePublication: Date | null; importedAt: Date; @@ -58,19 +69,157 @@ const TYPE_ACCENT: Record = { generale: "border-l-amber-500", }; +const TYPE_HEADER_BG: Record = { + reglementaire: "from-blue-50 to-blue-100/30 border-blue-200", + concurrentielle: "from-purple-50 to-purple-100/30 border-purple-200", + technologique: "from-emerald-50 to-emerald-100/30 border-emerald-200", + generale: "from-amber-50 to-amber-100/30 border-amber-200", +}; + const PAGE_SIZE = 24; function formatDate(d: Date | null | undefined): string | null { if (!d) return null; - try { return format(new Date(d), "d MMM yyyy", { locale: fr }); } + try { return format(new Date(d), "d MMMM yyyy", { locale: fr }); } catch { return null; } } +// ─── Boîte de dialogue Détail ───────────────────────────────────────────────── + +function VeilleDetailDialog({ + item, + open, + onClose, +}: { + item: VeilleItem | null; + open: boolean; + onClose: () => void; +}) { + if (!item) return null; + + const typeKey = item.typeVeille as TypeVeille; + const headerBg = TYPE_HEADER_BG[typeKey] || "from-muted to-muted/30 border-border"; + + return ( + !v && onClose()}> + + {/* En-tête coloré */} +
+ +
+ + {TYPE_LABELS[typeKey] || item.typeVeille} + + {item.datePublication && ( + + + {formatDate(item.datePublication)} + + )} +
+ + {item.titre} + +
+
+ + {/* Corps */} +
+ + {/* Métadonnées en grille */} +
+ {item.categorie && ( +
+ +
+

Catégorie

+

{item.categorie}

+
+
+ )} + {item.niveau && ( +
+ +
+

Niveau

+

{item.niveau}

+
+
+ )} + {item.territoire && ( +
+ +
+

Territoire

+

{item.territoire}

+
+
+ )} + {item.source && ( +
+ +
+

Source

+

{item.source}

+
+
+ )} + {item.passage && ( +
+ +
+

Passage en vigueur

+

{item.passage}

+
+
+ )} +
+ + {/* Résumé complet */} + {item.resume && ( +
+
+ +

Résumé

+
+
+

{item.resume}

+
+
+ )} + + {/* Lien externe */} + {item.lien && ( + + )} +
+
+
+ ); +} + +// ─── Composant principal ────────────────────────────────────────────────────── + export default function VeilleDashboard() { const [viewMode, setViewMode] = useState<"list" | "grid">("list"); const [activeTab, setActiveTab] = useState("all"); const [page, setPage] = useState(1); const [filterValues, setFilterValues] = useState>({}); + const [selectedItem, setSelectedItem] = useState(null); + const [dialogOpen, setDialogOpen] = useState(false); const filtersQuery = trpc.veille.filters.useQuery(); @@ -98,6 +247,11 @@ export default function VeilleDashboard() { setPage(1); }; + const openDetail = (item: VeilleItem) => { + setSelectedItem(item); + setDialogOpen(true); + }; + const items = (itemsQuery.data?.items ?? []) as VeilleItem[]; const total = itemsQuery.data?.total ?? 0; const totalPages = Math.ceil(total / PAGE_SIZE); @@ -165,9 +319,9 @@ export default function VeilleDashboard() {

Modifiez vos filtres ou importez des données

) : viewMode === "list" ? ( - + ) : ( - + )} {/* Pagination */} @@ -182,13 +336,20 @@ export default function VeilleDashboard() { )} + + {/* Boîte de dialogue détail */} + setDialogOpen(false)} + /> ); } // ─── Vue Liste ──────────────────────────────────────────────────────────────── -function VeilleListView({ items }: { items: VeilleItem[] }) { +function VeilleListView({ items, onDetail }: { items: VeilleItem[]; onDetail: (item: VeilleItem) => void }) { return (
@@ -202,7 +363,7 @@ function VeilleListView({ items }: { items: VeilleItem[] }) { Niveau Territoire Date - Lien + Actions @@ -225,11 +386,28 @@ function VeilleListView({ items }: { items: VeilleItem[] }) { {item.territoire || "—"} {formatDate(item.datePublication) || "—"} - {item.lien && ( - - - - )} +
+ {/* Bouton Détail */} + + {/* Bouton Lien externe */} + {item.lien && ( + + + + )} +
))} @@ -242,7 +420,7 @@ function VeilleListView({ items }: { items: VeilleItem[] }) { // ─── Vue Vignettes ──────────────────────────────────────────────────────────── -function VeilleGridView({ items }: { items: VeilleItem[] }) { +function VeilleGridView({ items, onDetail }: { items: VeilleItem[]; onDetail: (item: VeilleItem) => void }) { return (
{items.map((item) => ( @@ -252,11 +430,21 @@ function VeilleGridView({ items }: { items: VeilleItem[] }) { {TYPE_LABELS[item.typeVeille as TypeVeille] || item.typeVeille} - {item.lien && ( - - - - )} +
+ {/* Bouton Détail */} + + {item.lien && ( + + + + )} +

{item.titre}

diff --git a/todo.md b/todo.md index 646fc36..8df6e8f 100644 --- a/todo.md +++ b/todo.md @@ -38,3 +38,4 @@ - [x] Frontend : zone de dépôt (drag & drop) dans la page Paramètres pour les deux fichiers - [x] Frontend : afficher le résultat de l'import (nouvelles entrées, erreurs) après upload - [x] Page Paramètres : afficher les zones d'upload (drag & drop) quand la source "local" est sélectionnée +- [x] Veille : bouton "Détail" sur chaque ligne ouvrant une boîte de dialogue avec toutes les infos complètes