From 522d2e3c871597d5d2f229e0eca3f5043aafdd10 Mon Sep 17 00:00:00 2001 From: Manus Date: Wed, 15 Apr 2026 12:14:03 -0400 Subject: [PATCH] =?UTF-8?q?Checkpoint:=20Application=20SONUM=20v1.0=20-=20?= =?UTF-8?q?Cartographie=20des=20Solutions=20Num=C3=A9riques=20FEHAP.=20Tou?= =?UTF-8?q?tes=20les=20fonctionnalit=C3=A9s=20impl=C3=A9ment=C3=A9es=20:?= =?UTF-8?q?=20charte=20CGU,=20moteur=20de=20recherche=20multicrit=C3=A8res?= =?UTF-8?q?=20avec=20tri,=20Mes=20=C3=89tablissements=20avec=20accord?= =?UTF-8?q?=C3=A9ons=20et=20=C3=A9dition=20inline,=20formulaire=20de=20sai?= =?UTF-8?q?sie=20guid=C3=A9=20en=203=20=C3=A9tapes,=20fiche=20=C3=A9tablis?= =?UTF-8?q?sement=20avec=20compteur=20de=20consultation,=20prise=20de=20co?= =?UTF-8?q?ntact,=20Mes=20Demandes=20de=20Contact=20avec=20r=C3=A9ponse=20?= =?UTF-8?q?directe,=20administration=20SONUM,=20gestion=20des=20r=C3=B4les?= =?UTF-8?q?=20(R=C3=A9f=C3=A9rent=20/=20Gestionnaire),=20tra=C3=A7abilit?= =?UTF-8?q?=C3=A9,=20lien=20espace=20adh=C3=A9rent=20FEHAP.=2014=20tests?= =?UTF-8?q?=20Vitest=20pass=C3=A9s.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitkeep | 0 client/src/App.tsx | 26 +- client/src/components/CguModal.tsx | 151 ++++ client/src/components/ContactModal.tsx | 96 +++ client/src/components/EtatBadge.tsx | 35 + .../src/components/RattacherSolutionModal.tsx | 417 +++++++++++ client/src/components/SonumLayout.tsx | 240 +++++++ client/src/index.css | 68 +- client/src/pages/Admin.tsx | 283 ++++++++ client/src/pages/FicheEtablissement.tsx | 240 +++++++ client/src/pages/Home.tsx | 428 ++++++++++- client/src/pages/MesDemandes.tsx | 248 +++++++ client/src/pages/MesEtablissements.tsx | 369 ++++++++++ client/src/pages/NotFound.tsx | 62 +- drizzle/0000_complete_luminals.sql | 13 + drizzle/0001_wide_frightful_four.sql | 89 +++ drizzle/meta/0000_snapshot.json | 110 +++ drizzle/meta/0001_snapshot.json | 677 ++++++++++++++++++ drizzle/meta/_journal.json | 19 +- drizzle/schema.ts | 155 +++- scripts/seed.mjs | 71 ++ server/db.ts | 424 +++++++++-- server/routers.ts | 334 ++++++++- server/sonum.test.ts | 154 ++++ shared/referentiel.ts | 94 +++ todo.md | 33 + 26 files changed, 4638 insertions(+), 198 deletions(-) create mode 100644 .gitkeep create mode 100644 client/src/components/CguModal.tsx create mode 100644 client/src/components/ContactModal.tsx create mode 100644 client/src/components/EtatBadge.tsx create mode 100644 client/src/components/RattacherSolutionModal.tsx create mode 100644 client/src/components/SonumLayout.tsx create mode 100644 client/src/pages/Admin.tsx create mode 100644 client/src/pages/FicheEtablissement.tsx create mode 100644 client/src/pages/MesDemandes.tsx create mode 100644 client/src/pages/MesEtablissements.tsx create mode 100644 drizzle/0000_complete_luminals.sql create mode 100644 drizzle/0001_wide_frightful_four.sql create mode 100644 drizzle/meta/0000_snapshot.json create mode 100644 drizzle/meta/0001_snapshot.json create mode 100644 scripts/seed.mjs create mode 100644 server/sonum.test.ts create mode 100644 shared/referentiel.ts create mode 100644 todo.md diff --git a/.gitkeep b/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/client/src/App.tsx b/client/src/App.tsx index 5c7a610..c8ff2b4 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -5,33 +5,31 @@ import { Route, Switch } from "wouter"; import ErrorBoundary from "./components/ErrorBoundary"; import { ThemeProvider } from "./contexts/ThemeContext"; import Home from "./pages/Home"; +import MesEtablissements from "./pages/MesEtablissements"; +import MesDemandes from "./pages/MesDemandes"; +import FicheEtablissement from "./pages/FicheEtablissement"; +import Admin from "./pages/Admin"; function Router() { - // make sure to consider if you need authentication for certain routes return ( - - - {/* Final fallback route */} + + + + + + ); } -// NOTE: About Theme -// - First choose a default theme according to your design style (dark or light bg), than change color palette in index.css -// to keep consistent foreground/background color across components -// - If you want to make theme switchable, pass `switchable` ThemeProvider and use `useTheme` hook - function App() { return ( - + - + diff --git a/client/src/components/CguModal.tsx b/client/src/components/CguModal.tsx new file mode 100644 index 0000000..620dbea --- /dev/null +++ b/client/src/components/CguModal.tsx @@ -0,0 +1,151 @@ +import { trpc } from "@/lib/trpc"; +import { AlertCircle, CheckCircle2, FileText, Shield } from "lucide-react"; +import { useState } from "react"; + +interface CguModalProps { + onAccepted: () => void; +} + +export default function CguModal({ onAccepted }: CguModalProps) { + const [checked, setChecked] = useState(false); + const acceptMutation = trpc.cgu.accept.useMutation({ + onSuccess: () => onAccepted(), + }); + + return ( +
+
+ {/* En-tête */} +
+
+
+ +
+
+

Charte d'utilisation SONUM

+

+ Veuillez lire et accepter les conditions d'utilisation avant d'accéder à la plateforme. +

+
+
+
+ + {/* Contenu CGU */} +
+
+

+ Objet de la plateforme SONUM +

+

+ La plateforme SONUM (Solutions Numériques) est un outil collaboratif mis à disposition par la FEHAP + (Fédération des Établissements Hospitaliers et d'Aide à la Personne Privés Non Lucratifs) à destination + de ses établissements adhérents. Elle permet le référencement, le partage et la consultation des + solutions logicielles utilisées par les établissements membres. +

+
+ +
+

Données collectées et traitées

+

+ En utilisant SONUM, vous acceptez que les informations relatives aux logiciels utilisés par votre + établissement (nom de la solution, éditeur, état de déploiement, mode d'hébergement, etc.) soient + enregistrées et rendues accessibles aux autres référents numériques des établissements adhérents FEHAP, + selon les paramètres de visibilité que vous définissez. +

+

+ Vos coordonnées professionnelles (nom, fonction, adresse email) pourront être partagées dans le cadre + des demandes de mise en relation entre établissements. +

+
+ +
+

Responsabilités de l'utilisateur

+

+ En tant que référent numérique, vous vous engagez à : +

+
    + {[ + "Renseigner des informations exactes, à jour et complètes concernant les logiciels de vos établissements.", + "Mettre à jour régulièrement les informations saisies pour garantir la fiabilité des données.", + "Utiliser les fonctionnalités de mise en relation dans un cadre strictement professionnel.", + "Ne pas diffuser d'informations confidentielles ou sensibles via la plateforme.", + ].map((item, i) => ( +
  • + + {item} +
  • + ))} +
+
+ +
+

Traçabilité et confidentialité

+

+ Chaque consultation d'une fiche logiciels est enregistrée à des fins de traçabilité. Ces données + sont accessibles uniquement au référent numérique responsable de l'établissement consulté et aux + gestionnaires SONUM de la FEHAP. +

+
+ +
+

Gestion des données personnelles

+

+ Conformément au Règlement Général sur la Protection des Données (RGPD), vous disposez d'un droit + d'accès, de rectification et de suppression de vos données personnelles. Pour exercer ces droits, + contactez : sonum@fehap.fr +

+
+ +
+ +

+ L'accès à la plateforme SONUM est réservé aux référents numériques des établissements adhérents FEHAP. + Toute utilisation à des fins commerciales ou non professionnelles est strictement interdite. +

+
+
+ + {/* Pied de modale */} +
+ + + +
+
+
+ ); +} diff --git a/client/src/components/ContactModal.tsx b/client/src/components/ContactModal.tsx new file mode 100644 index 0000000..59b65e9 --- /dev/null +++ b/client/src/components/ContactModal.tsx @@ -0,0 +1,96 @@ +import { trpc } from "@/lib/trpc"; +import { Building2, Mail, Send, X } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; + +interface ContactModalProps { + etablissementId: number; + etablissementNom: string; + onClose: () => void; +} + +export default function ContactModal({ etablissementId, etablissementNom, onClose }: ContactModalProps) { + const [message, setMessage] = useState(""); + + const sendMutation = trpc.contact.envoyer.useMutation({ + onSuccess: () => { + toast.success("Votre demande de contact a été envoyée avec succès."); + onClose(); + }, + onError: (err) => { + toast.error("Erreur lors de l'envoi : " + err.message); + }, + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (!message.trim()) return; + sendMutation.mutate({ etablissementCibleId: etablissementId, message }); + }; + + return ( +
+
+ {/* En-tête */} +
+
+
+ +
+
+

Demande de contact

+
+ + {etablissementNom} +
+
+
+ +
+ + {/* Formulaire */} +
+
+ +