From 2283e84b54c952ff27254f4304edbe28c5debcbf Mon Sep 17 00:00:00 2001 From: Manus Sandbox Date: Wed, 19 Nov 2025 10:33:48 -0500 Subject: [PATCH] true message --- .manus/db/db-query-1763560417225.json | 25 - .manus/db/db-query-1763560488812.json | 9 - .manus/db/db-query-1763560498104.json | 9 - .manus/db/db-query-1763560527050.json | 9 - .manus/db/db-query-1763561120018.json | 9 - .manus/db/db-query-1763562465933.json | 9 - .manus/db/db-query-1763562834604.json | 9 - .manus/db/db-query-1763564186793.json | 9 - client/src/App.tsx | 4 - client/src/components/CapacityProgressBar.tsx | 43 - client/src/components/DashboardLayout.tsx | 4 +- client/src/components/FormateurCombobox.tsx | 135 --- client/src/components/ui/progress.tsx | 9 +- client/src/pages/AdminCalendrier.tsx | 226 ----- client/src/pages/AdminRappels.tsx | 318 ------ client/src/pages/AdminRapportPublicCible.tsx | 2 - client/src/pages/AdminSequenceInscrits.tsx | 2 - client/src/pages/AdminSequences.tsx | 67 +- client/src/pages/Inscription.tsx | 9 +- drizzle/0010_flat_clint_barton.sql | 7 - drizzle/0011_talented_toad_men.sql | 3 - drizzle/0012_perfect_night_thrasher.sql | 3 - drizzle/0015_brainy_terrax.sql | 1 - drizzle/0016_chunky_landau.sql | 1 - drizzle/0017_dear_tana_nile.sql | 9 - drizzle/0018_breezy_thundra.sql | 18 - drizzle/meta/0010_snapshot.json | 780 -------------- drizzle/meta/0011_snapshot.json | 793 --------------- drizzle/meta/0012_snapshot.json | 780 -------------- drizzle/meta/0013_snapshot.json | 779 -------------- drizzle/meta/0014_snapshot.json | 772 -------------- drizzle/meta/0015_snapshot.json | 772 -------------- drizzle/meta/0016_snapshot.json | 779 -------------- drizzle/meta/0017_snapshot.json | 842 --------------- drizzle/meta/0018_snapshot.json | 958 ------------------ drizzle/meta/_journal.json | 63 -- drizzle/schema.ts | 57 +- server/_core/oauth.ts | 9 - server/db.ts | 121 --- server/emailService.ts | 2 - server/routers.ts | 65 +- todo.md | 76 +- 42 files changed, 38 insertions(+), 8559 deletions(-) delete mode 100644 .manus/db/db-query-1763560417225.json delete mode 100644 .manus/db/db-query-1763560488812.json delete mode 100644 .manus/db/db-query-1763560498104.json delete mode 100644 .manus/db/db-query-1763560527050.json delete mode 100644 .manus/db/db-query-1763561120018.json delete mode 100644 .manus/db/db-query-1763562465933.json delete mode 100644 .manus/db/db-query-1763562834604.json delete mode 100644 .manus/db/db-query-1763564186793.json delete mode 100644 client/src/components/CapacityProgressBar.tsx delete mode 100644 client/src/components/FormateurCombobox.tsx delete mode 100644 client/src/pages/AdminCalendrier.tsx delete mode 100644 client/src/pages/AdminRappels.tsx delete mode 100644 drizzle/0010_flat_clint_barton.sql delete mode 100644 drizzle/0011_talented_toad_men.sql delete mode 100644 drizzle/0012_perfect_night_thrasher.sql delete mode 100644 drizzle/0015_brainy_terrax.sql delete mode 100644 drizzle/0016_chunky_landau.sql delete mode 100644 drizzle/0017_dear_tana_nile.sql delete mode 100644 drizzle/0018_breezy_thundra.sql delete mode 100644 drizzle/meta/0010_snapshot.json delete mode 100644 drizzle/meta/0011_snapshot.json delete mode 100644 drizzle/meta/0012_snapshot.json delete mode 100644 drizzle/meta/0013_snapshot.json delete mode 100644 drizzle/meta/0014_snapshot.json delete mode 100644 drizzle/meta/0015_snapshot.json delete mode 100644 drizzle/meta/0016_snapshot.json delete mode 100644 drizzle/meta/0017_snapshot.json delete mode 100644 drizzle/meta/0018_snapshot.json diff --git a/.manus/db/db-query-1763560417225.json b/.manus/db/db-query-1763560417225.json deleted file mode 100644 index 7b3e797..0000000 --- a/.manus/db/db-query-1763560417225.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "query": "SELECT id, email, openId FROM users LIMIT 10", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SELECT id, email, openId FROM users LIMIT 10", - "rows": [ - { - "id": "1110110", - "email": "opareige@gmail.com", - "openId": "" - }, - { - "id": "2010001", - "email": "o.pareige@itinova.org", - "openId": "" - }, - { - "id": "2040001", - "email": "test@itinova.org", - "openId": "" - } - ], - "messages": [], - "stdout": "id\temail\topenId\n1110110\topareige@gmail.com\t\n2010001\to.pareige@itinova.org\t\n2040001\ttest@itinova.org\t\n", - "stderr": "", - "execution_time_ms": 95 -} \ No newline at end of file diff --git a/.manus/db/db-query-1763560488812.json b/.manus/db/db-query-1763560488812.json deleted file mode 100644 index f0dc187..0000000 --- a/.manus/db/db-query-1763560488812.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "query": "ALTER TABLE users ADD COLUMN IF NOT EXISTS openId VARCHAR(64) NULL", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE users ADD COLUMN IF NOT EXISTS openId VARCHAR(64) NULL", - "rows": [], - "messages": [], - "stdout": "", - "stderr": "", - "execution_time_ms": 51 -} \ No newline at end of file diff --git a/.manus/db/db-query-1763560498104.json b/.manus/db/db-query-1763560498104.json deleted file mode 100644 index 9b40397..0000000 --- a/.manus/db/db-query-1763560498104.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "query": "ALTER TABLE users ADD COLUMN IF NOT EXISTS loginMethod VARCHAR(64) NULL", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE users ADD COLUMN IF NOT EXISTS loginMethod VARCHAR(64) NULL", - "rows": [], - "messages": [], - "stdout": "", - "stderr": "", - "execution_time_ms": 45 -} \ No newline at end of file diff --git a/.manus/db/db-query-1763560527050.json b/.manus/db/db-query-1763560527050.json deleted file mode 100644 index 720867c..0000000 --- a/.manus/db/db-query-1763560527050.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "query": "ALTER TABLE users MODIFY COLUMN password VARCHAR(255) NULL", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE users MODIFY COLUMN password VARCHAR(255) NULL", - "rows": [], - "messages": [], - "stdout": "", - "stderr": "", - "execution_time_ms": 198 -} \ No newline at end of file diff --git a/.manus/db/db-query-1763561120018.json b/.manus/db/db-query-1763561120018.json deleted file mode 100644 index 64acd60..0000000 --- a/.manus/db/db-query-1763561120018.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "query": "ALTER TABLE sequences MODIFY COLUMN publicCible ENUM('directeur', 'chef_service', 'tous', 'autre') NOT NULL", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE sequences MODIFY COLUMN publicCible ENUM('directeur', 'chef_service', 'tous', 'autre') NOT NULL", - "rows": [], - "messages": [], - "stdout": "", - "stderr": "", - "execution_time_ms": 594 -} \ No newline at end of file diff --git a/.manus/db/db-query-1763562465933.json b/.manus/db/db-query-1763562465933.json deleted file mode 100644 index 5b3608f..0000000 --- a/.manus/db/db-query-1763562465933.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "query": "ALTER TABLE sequences ADD COLUMN formateur VARCHAR(255) NULL AFTER publicCible;", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE sequences ADD COLUMN formateur VARCHAR(255) NULL AFTER publicCible;", - "rows": [], - "messages": [], - "stdout": "", - "stderr": "", - "execution_time_ms": 495 -} \ No newline at end of file diff --git a/.manus/db/db-query-1763562834604.json b/.manus/db/db-query-1763562834604.json deleted file mode 100644 index e222708..0000000 --- a/.manus/db/db-query-1763562834604.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "query": "CREATE TABLE IF NOT EXISTS formateurs (\n id INT AUTO_INCREMENT PRIMARY KEY,\n nom VARCHAR(255) NOT NULL UNIQUE,\n actif BOOLEAN DEFAULT TRUE NOT NULL,\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL\n);", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute CREATE TABLE IF NOT EXISTS formateurs (\n id INT AUTO_INCREMENT PRIMARY KEY,\n nom VARCHAR(255) NOT NULL UNIQUE,\n actif BOOLEAN DEFAULT TRUE NOT NULL,\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL\n);", - "rows": [], - "messages": [], - "stdout": "", - "stderr": "", - "execution_time_ms": 189 -} \ No newline at end of file diff --git a/.manus/db/db-query-1763564186793.json b/.manus/db/db-query-1763564186793.json deleted file mode 100644 index 0c8b7ac..0000000 --- a/.manus/db/db-query-1763564186793.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "query": "CREATE TABLE IF NOT EXISTS rappels (\n id INT AUTO_INCREMENT PRIMARY KEY,\n nom VARCHAR(255) NOT NULL,\n joursAvant INT NOT NULL,\n emailTemplate TEXT NOT NULL,\n actif BOOLEAN DEFAULT TRUE NOT NULL,\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS rappelsEnvoyes (\n id INT AUTO_INCREMENT PRIMARY KEY,\n rappelId INT NOT NULL,\n inscriptionId INT NOT NULL,\n dateEnvoi TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n INDEX idx_rappel_inscription (rappelId, inscriptionId)\n);", - "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute CREATE TABLE IF NOT EXISTS rappels (\n id INT AUTO_INCREMENT PRIMARY KEY,\n nom VARCHAR(255) NOT NULL,\n joursAvant INT NOT NULL,\n emailTemplate TEXT NOT NULL,\n actif BOOLEAN DEFAULT TRUE NOT NULL,\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS rappelsEnvoyes (\n id INT AUTO_INCREMENT PRIMARY KEY,\n rappelId INT NOT NULL,\n inscriptionId INT NOT NULL,\n dateEnvoi TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n INDEX idx_rappel_inscription (rappelId, inscriptionId)\n);", - "rows": [], - "messages": [], - "stdout": "", - "stderr": "", - "execution_time_ms": 354 -} \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx index 1aa1b7d..eeb8c86 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -9,13 +9,11 @@ import AdminRapportPublicCible from "./pages/AdminRapportPublicCible"; import Admin from "./pages/Admin"; import AdminFormations from "./pages/AdminFormations"; import AdminSequences from "./pages/AdminSequences"; -import AdminCalendrier from "./pages/AdminCalendrier"; import AdminApprenants from "./pages/AdminApprenants"; import AdminSequenceInscrits from "./pages/AdminSequenceInscrits"; import AdminUsers from "./pages/AdminUsers"; import AdminEmailTemplates from "./pages/AdminEmailTemplates"; import AdminEmailConfig from "./pages/AdminEmailConfig"; -import AdminRappels from "./pages/AdminRappels"; import Inscription from "./pages/Inscription"; function Router() { @@ -27,13 +25,11 @@ function Router() { - - {/* Final fallback route */} diff --git a/client/src/components/CapacityProgressBar.tsx b/client/src/components/CapacityProgressBar.tsx deleted file mode 100644 index d21e23d..0000000 --- a/client/src/components/CapacityProgressBar.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Progress } from "@/components/ui/progress"; -import { cn } from "@/lib/utils"; - -interface CapacityProgressBarProps { - current: number; - max: number; - className?: string; -} - -export function CapacityProgressBar({ current, max, className }: CapacityProgressBarProps) { - const percentage = max > 0 ? (current / max) * 100 : 0; - - // Définir la couleur en fonction du taux de remplissage - const getColorClass = () => { - if (percentage >= 90) return "bg-red-500"; - if (percentage >= 70) return "bg-orange-500"; - return "bg-green-500"; - }; - - const getTextColorClass = () => { - if (percentage >= 90) return "text-red-700"; - if (percentage >= 70) return "text-orange-700"; - return "text-green-700"; - }; - - return ( -
-
- - {current} / {max} - - - {Math.round(percentage)}% - -
- -
- ); -} diff --git a/client/src/components/DashboardLayout.tsx b/client/src/components/DashboardLayout.tsx index 9c37712..c88a2a6 100644 --- a/client/src/components/DashboardLayout.tsx +++ b/client/src/components/DashboardLayout.tsx @@ -21,7 +21,7 @@ import { } from "@/components/ui/sidebar"; import { APP_LOGO, APP_TITLE, getLoginUrl } from "@/const"; import { useIsMobile } from "@/hooks/useMobile"; -import { LayoutDashboard, LogOut, PanelLeft, Users, GraduationCap, Calendar, CalendarDays, BarChart3, UserCog, Mail, Settings, Bell } from "lucide-react"; +import { LayoutDashboard, LogOut, PanelLeft, Users, GraduationCap, Calendar, BarChart3, UserCog, Mail, Settings } from "lucide-react"; import { CSSProperties, useEffect, useRef, useState } from "react"; import { useLocation } from "wouter"; import { DashboardLayoutSkeleton } from './DashboardLayoutSkeleton'; @@ -31,12 +31,10 @@ const menuItems = [ { icon: LayoutDashboard, label: "Tableau de bord", path: "/admin" }, { icon: GraduationCap, label: "Formations", path: "/admin/formations" }, { icon: Calendar, label: "Séquences", path: "/admin/sequences" }, - { icon: CalendarDays, label: "Calendrier", path: "/admin/calendrier" }, { icon: Users, label: "Apprenants", path: "/admin/apprenants" }, { icon: UserCog, label: "Utilisateurs", path: "/admin/users" }, { icon: Mail, label: "Templates d'emails", path: "/admin/email-templates" }, { icon: Settings, label: "Configuration SMTP", path: "/admin/email-config" }, - { icon: Bell, label: "Rappels automatiques", path: "/admin/rappels" }, { icon: BarChart3, label: "Rapport Public Cible", path: "/admin/rapport-public-cible" }, ]; diff --git a/client/src/components/FormateurCombobox.tsx b/client/src/components/FormateurCombobox.tsx deleted file mode 100644 index c8ca604..0000000 --- a/client/src/components/FormateurCombobox.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { useState } from "react"; -import { Check, ChevronsUpDown, Plus } from "lucide-react"; -import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, -} from "@/components/ui/command"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { trpc } from "@/lib/trpc"; -import { toast } from "sonner"; - -interface FormateurComboboxProps { - value: string; - onChange: (value: string) => void; - placeholder?: string; -} - -export function FormateurCombobox({ value, onChange, placeholder = "Sélectionner un formateur..." }: FormateurComboboxProps) { - const [open, setOpen] = useState(false); - const [searchValue, setSearchValue] = useState(""); - - const { data: formateurs = [], refetch } = trpc.formateurs.list.useQuery(); - const createMutation = trpc.formateurs.create.useMutation({ - onSuccess: () => { - toast.success("Formateur ajouté"); - refetch(); - }, - onError: (error) => { - toast.error(error.message || "Erreur lors de l'ajout du formateur"); - }, - }); - - const handleAddNew = () => { - if (!searchValue.trim()) { - toast.error("Veuillez entrer un nom de formateur"); - return; - } - - // Vérifier si le formateur existe déjà - const exists = formateurs.some(f => f.nom.toLowerCase() === searchValue.toLowerCase()); - if (exists) { - toast.error("Ce formateur existe déjà"); - return; - } - - createMutation.mutate({ nom: searchValue.trim() }); - onChange(searchValue.trim()); - setSearchValue(""); - setOpen(false); - }; - - return ( - - - - - - - - - -
-

Aucun formateur trouvé

- {searchValue && ( - - )} -
-
- - {formateurs.map((formateur) => ( - { - onChange(currentValue === value ? "" : currentValue); - setOpen(false); - setSearchValue(""); - }} - > - - {formateur.nom} - - ))} - - {searchValue && !formateurs.some(f => f.nom.toLowerCase() === searchValue.toLowerCase()) && ( - - - - Ajouter "{searchValue}" - - - )} -
-
-
-
- ); -} diff --git a/client/src/components/ui/progress.tsx b/client/src/components/ui/progress.tsx index b92a163..4c9f4ab 100644 --- a/client/src/components/ui/progress.tsx +++ b/client/src/components/ui/progress.tsx @@ -3,16 +3,11 @@ import * as ProgressPrimitive from "@radix-ui/react-progress"; import { cn } from "@/lib/utils"; -interface ProgressProps extends React.ComponentProps { - indicatorClassName?: string; -} - function Progress({ className, value, - indicatorClassName, ...props -}: ProgressProps) { +}: React.ComponentProps) { return ( diff --git a/client/src/pages/AdminCalendrier.tsx b/client/src/pages/AdminCalendrier.tsx deleted file mode 100644 index 504bc85..0000000 --- a/client/src/pages/AdminCalendrier.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import { useState } from "react"; -import DashboardLayout from "@/components/DashboardLayout"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { trpc } from "@/lib/trpc"; -import { ChevronLeft, ChevronRight, Calendar as CalendarIcon } from "lucide-react"; -import { format, startOfMonth, endOfMonth, eachDayOfInterval, isSameMonth, isSameDay, addMonths, subMonths, startOfWeek, endOfWeek } from "date-fns"; -import { fr } from "date-fns/locale"; -import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; - -export default function AdminCalendrier() { - const [currentDate, setCurrentDate] = useState(new Date()); - const [selectedSequence, setSelectedSequence] = useState(null); - const [isDialogOpen, setIsDialogOpen] = useState(false); - - const { data: sequences = [], isLoading } = trpc.sequences.list.useQuery(); - const { data: formations = [] } = trpc.formations.list.useQuery(); - - const getFormationName = (formationId: number) => { - const formation = formations.find(f => f.id === formationId); - return formation?.nom || "Formation inconnue"; - }; - - // Générer les jours du calendrier (incluant les jours du mois précédent/suivant pour remplir la grille) - const monthStart = startOfMonth(currentDate); - const monthEnd = endOfMonth(currentDate); - const calendarStart = startOfWeek(monthStart, { weekStartsOn: 1 }); // Commence le lundi - const calendarEnd = endOfWeek(monthEnd, { weekStartsOn: 1 }); - const calendarDays = eachDayOfInterval({ start: calendarStart, end: calendarEnd }); - - // Obtenir les séquences pour un jour donné - const getSequencesForDay = (day: Date) => { - return sequences.filter(sequence => { - return sequence.dates.some((date: any) => { - const dateDebut = new Date(date.dateDebut); - return isSameDay(dateDebut, day); - }); - }); - }; - - const handlePreviousMonth = () => { - setCurrentDate(subMonths(currentDate, 1)); - }; - - const handleNextMonth = () => { - setCurrentDate(addMonths(currentDate, 1)); - }; - - const handleToday = () => { - setCurrentDate(new Date()); - }; - - const handleSequenceClick = (sequence: any) => { - setSelectedSequence(sequence); - setIsDialogOpen(true); - }; - - const getPublicCibleLabel = (publicCible: string) => { - switch (publicCible) { - case "directeur": return "Directeur"; - case "chef_service": return "Chef de service"; - case "tous": return "Tous"; - case "autre": return "Autre"; - default: return publicCible; - } - }; - - const getStatutBadge = (statut: string) => { - switch (statut) { - case "ouverte": return "bg-green-100 text-green-800"; - case "bloquee": return "bg-orange-100 text-orange-800"; - case "terminee": return "bg-gray-100 text-gray-800"; - default: return "bg-gray-100 text-gray-800"; - } - }; - - return ( - -
-
-

Calendrier des séquences

-

- Vue mensuelle de toutes les séquences de formation planifiées -

-
- - - -
-
- - {format(currentDate, "MMMM yyyy", { locale: fr })} - - - {sequences.length} séquence(s) au total - -
-
- - - -
-
-
- - {isLoading ? ( -
Chargement...
- ) : ( -
- {/* En-tête des jours de la semaine */} -
- {["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"].map(day => ( -
- {day} -
- ))} -
- - {/* Grille du calendrier */} -
- {calendarDays.map((day, index) => { - const daySequences = getSequencesForDay(day); - const isCurrentMonth = isSameMonth(day, currentDate); - const isToday = isSameDay(day, new Date()); - - return ( -
-
- {format(day, "d")} -
-
- {daySequences.map(sequence => ( - - ))} -
-
- ); - })} -
-
- )} -
-
- - {/* Dialog de détails de la séquence */} - - - - {selectedSequence?.nom} - - {selectedSequence && getFormationName(selectedSequence.formationId)} - - - {selectedSequence && ( -
-
-
-

Lieu

-

{selectedSequence.lieu}

-
-
-

Public cible

-

{getPublicCibleLabel(selectedSequence.publicCible)}

-
-
-

Formateur

-

{selectedSequence.formateur || "-"}

-
-
-

Capacité

-

{selectedSequence.nbInscrits || 0} / {selectedSequence.capaciteMax}

-
-
-

Statut

- - {selectedSequence.statut} - -
-
- -
-

Dates de formation

-
- {selectedSequence.dates.map((date: any) => ( -
-

Date {date.ordre}

-

- Du {format(new Date(date.dateDebut), "PPP 'à' HH:mm", { locale: fr })} -

-

- au {format(new Date(date.dateFin), "PPP 'à' HH:mm", { locale: fr })} -

-
- ))} -
-
-
- )} -
-
-
-
- ); -} diff --git a/client/src/pages/AdminRappels.tsx b/client/src/pages/AdminRappels.tsx deleted file mode 100644 index 18c1538..0000000 --- a/client/src/pages/AdminRappels.tsx +++ /dev/null @@ -1,318 +0,0 @@ -import { useState } from "react"; -import DashboardLayout from "@/components/DashboardLayout"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import { Textarea } from "@/components/ui/textarea"; -import { Switch } from "@/components/ui/switch"; -import { trpc } from "@/lib/trpc"; -import { Plus, Pencil, Trash2, Bell, BellOff } from "lucide-react"; -import { toast } from "sonner"; - -export default function AdminRappels() { - const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); - const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); - const [formData, setFormData] = useState({ - nom: "", - joursAvant: 15, - emailTemplate: "", - actif: true, - }); - const [editingId, setEditingId] = useState(null); - - const { data: rappels = [], isLoading, refetch } = trpc.rappels.list.useQuery(); - const createMutation = trpc.rappels.create.useMutation(); - const updateMutation = trpc.rappels.update.useMutation(); - const deleteMutation = trpc.rappels.delete.useMutation(); - - const resetForm = () => { - setFormData({ - nom: "", - joursAvant: 15, - emailTemplate: "", - actif: true, - }); - setEditingId(null); - }; - - const handleCreate = async () => { - try { - await createMutation.mutateAsync(formData); - toast.success("Rappel créé avec succès"); - setIsCreateDialogOpen(false); - resetForm(); - refetch(); - } catch (error: any) { - toast.error(error.message || "Erreur lors de la création du rappel"); - } - }; - - const handleEdit = (rappel: any) => { - setFormData({ - nom: rappel.nom, - joursAvant: rappel.joursAvant, - emailTemplate: rappel.emailTemplate, - actif: rappel.actif, - }); - setEditingId(rappel.id); - setIsEditDialogOpen(true); - }; - - const handleUpdate = async () => { - if (!editingId) return; - - try { - await updateMutation.mutateAsync({ id: editingId, ...formData }); - toast.success("Rappel mis à jour avec succès"); - setIsEditDialogOpen(false); - resetForm(); - refetch(); - } catch (error: any) { - toast.error(error.message || "Erreur lors de la mise à jour du rappel"); - } - }; - - const handleDelete = async (id: number) => { - if (!confirm("Êtes-vous sûr de vouloir supprimer ce rappel ?")) return; - - try { - await deleteMutation.mutateAsync({ id }); - toast.success("Rappel supprimé avec succès"); - refetch(); - } catch (error: any) { - toast.error(error.message || "Erreur lors de la suppression du rappel"); - } - }; - - const templateExemple = `Bonjour {{prenom}} {{nom}}, - -Nous vous rappelons que votre formation "{{formationNom}}" - {{sequenceNom}} aura lieu dans {{joursAvant}} jours. - -📅 Date : {{dateDebut}} -📍 Lieu : {{lieu}} -👨‍🏫 Formateur : {{formateur}} - -Cordialement, -L'équipe Formation Manager Itinova`; - - return ( - -
-
-
-

Rappels automatiques

-

- Configurez les rappels envoyés automatiquement avant les formations -

-
- - - - - - - Créer un rappel - - Configurez un nouveau rappel automatique à envoyer avant les formations - - -
-
- - setFormData({ ...formData, nom: e.target.value })} - /> -
-
- - setFormData({ ...formData, joursAvant: parseInt(e.target.value) || 0 })} - /> -

- Nombre de jours avant la première date de formation -

-
-
- -