diff --git a/app/central/[missionId]/edit/page.tsx b/app/central/[missionId]/edit/page.tsx new file mode 100644 index 00000000..6429d08e --- /dev/null +++ b/app/central/[missionId]/edit/page.tsx @@ -0,0 +1,32 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { useParams } from "next/navigation"; +import { Button } from "@/components/ui/button"; + +export default function EditMissionPage() { + const router = useRouter(); + const params = useParams(); + const { missionId } = params; + + // Redirect to the original mission edit page + useEffect(() => { + if (missionId) { + router.push(`/missions/${missionId}/edit`); + } + }, [router, missionId]); + + return ( +
+
+

Redirection vers le formulaire d'édition de la mission...

+ +
+ ); +} \ No newline at end of file diff --git a/app/central/[missionId]/page.tsx b/app/central/[missionId]/page.tsx new file mode 100644 index 00000000..470ade41 --- /dev/null +++ b/app/central/[missionId]/page.tsx @@ -0,0 +1,32 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { useParams } from "next/navigation"; +import { Button } from "@/components/ui/button"; + +export default function MissionDetailsPage() { + const router = useRouter(); + const params = useParams(); + const { missionId } = params; + + // Redirect to the original mission details page + useEffect(() => { + if (missionId) { + router.push(`/missions/${missionId}`); + } + }, [router, missionId]); + + return ( +
+
+

Redirection vers les détails de la mission...

+ +
+ ); +} \ No newline at end of file diff --git a/app/central/layout.tsx b/app/central/layout.tsx new file mode 100644 index 00000000..4fd49bd2 --- /dev/null +++ b/app/central/layout.tsx @@ -0,0 +1,47 @@ +"use client"; + +import React from "react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +export default function CentralLayout({ + children, +}: { + children: React.ReactNode; +}) { + const pathname = usePathname(); + + return ( +
+
+ {/* Sidebar with light pink background */} +
+ {/* Title section */} +
+

Central

+

Centre d'Administration et de Pilotage

+
+ + {/* Navigation links */} + +
+ + {/* Main content - white background */} +
+ {children} +
+
+
+ ); +} \ No newline at end of file diff --git a/app/central/new/page.tsx b/app/central/new/page.tsx new file mode 100644 index 00000000..30e37c5c --- /dev/null +++ b/app/central/new/page.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { Button } from "@/components/ui/button"; + +export default function NewMissionPage() { + const router = useRouter(); + + // Redirect to new mission form + useEffect(() => { + router.push("/missions/new"); + }, [router]); + + return ( +
+
+

Redirection vers le formulaire de création de mission...

+ +
+ ); +} \ No newline at end of file diff --git a/app/central/page.tsx b/app/central/page.tsx new file mode 100644 index 00000000..ac2fe8fc --- /dev/null +++ b/app/central/page.tsx @@ -0,0 +1,304 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { Search } from "lucide-react"; +import { Input } from "@/components/ui/input"; +import Link from "next/link"; +import { Button } from "@/components/ui/button"; +import { useToast } from "@/components/ui/use-toast"; +import { getPublicUrl } from "@/lib/s3"; + +// Define Mission interface +interface User { + id: string; + email: string; +} + +interface MissionUser { + id: string; + role: string; + user: User; +} + +interface Mission { + id: string; + name: string; + logo?: string; + oddScope: string[]; + niveau: string; + missionType: string; + projection: string; + participation?: string; + services?: string[]; + createdAt: string; + creator: User; + missionUsers: MissionUser[]; + intention?: string; +} + +export default function CentralPage() { + const [searchTerm, setSearchTerm] = useState(""); + const [missions, setMissions] = useState([]); + const [loading, setLoading] = useState(true); + const { toast } = useToast(); + + // Fetch missions from API + useEffect(() => { + const fetchMissions = async () => { + try { + setLoading(true); + const response = await fetch('/api/missions'); + if (!response.ok) { + throw new Error('Failed to fetch missions'); + } + const data = await response.json(); + // Debug log to check mission data structure including intention + console.log("Mission data with intention:", data.missions); + setMissions(data.missions || []); + } catch (error) { + console.error('Error fetching missions:', error); + toast({ + title: "Erreur", + description: "Impossible de charger les missions", + variant: "destructive", + }); + } finally { + setLoading(false); + } + }; + + fetchMissions(); + }, []); + + // Filter missions based on search term + const filteredMissions = missions.filter(mission => + mission.name.toLowerCase().includes(searchTerm.toLowerCase()) || + mission.niveau.toLowerCase().includes(searchTerm.toLowerCase()) || + mission.missionType.toLowerCase().includes(searchTerm.toLowerCase()) || + mission.oddScope.some(scope => scope.toLowerCase().includes(searchTerm.toLowerCase())) + ); + + // Function to format date + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleDateString('fr-FR', { + day: '2-digit', + month: '2-digit', + year: 'numeric' + }); + }; + + // Function to get mission category and icon + const getODDInfo = (mission: Mission) => { + const oddCode = mission.oddScope && mission.oddScope.length > 0 + ? mission.oddScope[0] + : null; + + // Extract number from odd code (e.g., "odd-3" -> "3") + const oddNumber = oddCode ? oddCode.replace('odd-', '') : null; + + return { + number: oddNumber, + label: oddNumber ? `ODD ${oddNumber}` : "Non catégorisé", + iconPath: oddNumber ? `/F SDG Icons 2019 WEB/F-WEB-Goal-${oddNumber.padStart(2, '0')}.png` : "" + }; + }; + + // Function to get appropriate badge color based on niveau + const getNiveauBadgeColor = (niveau: string) => { + switch(niveau) { + case 'a': return 'bg-green-100 text-green-800'; + case 'b': return 'bg-blue-100 text-blue-800'; + case 'c': return 'bg-purple-100 text-purple-800'; + case 's': return 'bg-amber-100 text-amber-800'; + default: return 'bg-gray-100 text-gray-800'; + } + }; + + // Function to get full niveau label + const getNiveauLabel = (niveau: string) => { + switch(niveau) { + case 'a': return 'A'; + case 'b': return 'B'; + case 'c': return 'C'; + case 's': return 'S'; + default: return niveau.toUpperCase(); + } + }; + + // Function to get mission type label + const getMissionTypeLabel = (type: string) => { + switch(type) { + case 'remote': return 'À distance'; + case 'onsite': return 'Sur site'; + case 'hybrid': return 'Hybride'; + default: return type; + } + }; + + // Function to get participation label + const getParticipationLabel = (participation: string | null | undefined) => { + console.log("Participation value:", participation); // Debug log + if (!participation) return 'Non spécifié'; + switch(participation) { + case 'volontaire': return 'Volontaire'; + case 'cooptation': return 'Cooptation'; + default: return participation; + } + }; + + // Function to get mission duration + const getDuration = (projection: string) => { + switch(projection) { + case 'short': return '< 1 mois'; + case 'medium': return '1-3 mois'; + case 'long': return '> 3 mois'; + default: return projection; + } + }; + + return ( +
+
+
+

Gérez vos missions et opportunités de bénévolat

+
+ + setSearchTerm(e.target.value)} + /> +
+
+
+ +
+ {loading ? ( +
+
+
+ ) : filteredMissions.length > 0 ? ( +
+ {filteredMissions.map((mission) => { + const oddInfo = getODDInfo(mission); + const niveauColor = getNiveauBadgeColor(mission.niveau); + + return ( +
+ {/* Card Header with Name and Level */} +
+

{mission.name}

+
+ {/* ODD scope icon moved next to level badge */} + {oddInfo.number && ( +
+ {oddInfo.label} { + // Fallback if image fails to load + (e.target as HTMLImageElement).style.display = 'none'; + }} + /> +
+ )} + + {getNiveauLabel(mission.niveau)} + +
+
+ + {/* Centered Logo */} +
+
+ {mission.logo ? ( + {mission.name} { + console.log("Logo failed to load:", mission.logo); + // If the image fails to load, show the fallback + (e.currentTarget as HTMLImageElement).style.display = 'none'; + // Show the fallback div + const fallbackDiv = e.currentTarget.parentElement?.querySelector('.logo-fallback'); + if (fallbackDiv) { + (fallbackDiv as HTMLElement).style.display = 'flex'; + } + }} + /> + ) : null} +
+ {mission.name.slice(0, 2).toUpperCase()} +
+
+
+ + {/* Mission details */} +
+ {/* Type and duration */} +
+
+ + {getMissionTypeLabel(mission.missionType)} +
+
+ + {getDuration(mission.projection)} +
+ {mission.participation && ( +
+ + {getParticipationLabel(mission.participation)} +
+ )} +
+ + {/* Optional services */} + {mission.services && mission.services.length > 0 && ( +
+ {mission.services.map(service => ( + + {service} + + ))} +
+ )} + + {/* Intent preview */} + {mission.intention && ( +
+

{mission.intention}

+
+ )} + + {/* View details button */} +
+ + + +
+
+
+ ); + })} +
+ ) : ( +
+

Aucune mission trouvée

+ + + +
+ )} +
+
+ ); +} \ No newline at end of file