"use client"; import React, { useState, useEffect } from "react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; import { Input } from "../ui/input"; import { Button } from "../ui/button"; import { Textarea } from "../ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"; import { Checkbox } from "../ui/checkbox"; import { Card, CardContent } from "../ui/card"; import { Badge } from "../ui/badge"; import { X, Search, UserPlus, Users, PlusCircle, AlertCircle, Check } from "lucide-react"; import { toast } from "../ui/use-toast"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu"; import { FileUpload } from "./file-upload"; import { AttachmentsList } from "./attachments-list"; import { useRouter } from "next/navigation"; // Define interfaces for user and group data interface User { id: string; username: string; firstName: string; lastName: string; email: string; roles?: string[]; enabled?: boolean; } interface Group { id: string; name: string; path: string; membersCount: number; } // User role types in mission type GuardienRole = 'temps' | 'parole' | 'memoire'; type UserRole = GuardienRole | 'volontaire'; export function MissionsAdminPanel() { const router = useRouter(); const [selectedServices, setSelectedServices] = useState([]); const [selectedProfils, setSelectedProfils] = useState([]); const [searchTerm, setSearchTerm] = useState(""); const [selectedTab, setSelectedTab] = useState<'users' | 'groups'>('users'); const [gardienDuTemps, setGardienDuTemps] = useState(null); const [gardienDeLaParole, setGardienDeLaParole] = useState(null); const [gardienDeLaMemoire, setGardienDeLaMemoire] = useState(null); const [volontaires, setVolontaires] = useState([]); const [missionId, setMissionId] = useState(""); const [activeTab, setActiveTab] = useState("general"); const [isSubmitting, setIsSubmitting] = useState(false); const [missionData, setMissionData] = useState<{ name?: string; logo?: string; oddScope?: string[]; niveau?: string; intention?: string; missionType?: string; donneurDOrdre?: string; projection?: string; services?: string[]; participation?: string; profils?: string[]; }>({}); // State for storing fetched data const [users, setUsers] = useState([]); const [groups, setGroups] = useState([]); const [loading, setLoading] = useState(true); // Check if mission is valid (has all required guardiens) const isMissionValid = gardienDuTemps !== null && gardienDeLaParole !== null && gardienDeLaMemoire !== null; // Fetch users and groups on component mount useEffect(() => { const fetchData = async () => { setLoading(true); try { await Promise.all([fetchUsers(), fetchGroups()]); } catch (error) { console.error("Error fetching data:", error); } finally { setLoading(false); } }; fetchData(); }, []); // Function to fetch users from API const fetchUsers = async () => { try { const response = await fetch("/api/users"); if (!response.ok) { throw new Error("Failed to fetch users"); } const data = await response.json(); setUsers(data); } catch (error) { console.error("Error fetching users:", error); toast({ title: "Erreur", description: "Erreur lors de la récupération des utilisateurs", variant: "destructive", }); } }; // Function to fetch groups from API const fetchGroups = async () => { try { const response = await fetch("/api/groups"); if (!response.ok) { throw new Error("Failed to fetch groups"); } const data = await response.json(); // Fetch member counts for groups const groupsWithCounts = await Promise.all( (Array.isArray(data) ? data : []).map(async (group) => { try { const membersResponse = await fetch(`/api/groups/${group.id}/members`); if (membersResponse.ok) { const members = await membersResponse.json(); return { ...group, membersCount: Array.isArray(members) ? members.length : 0 }; } return {...group, membersCount: 0}; } catch (error) { console.error(`Error fetching members for group ${group.id}:`, error); return {...group, membersCount: 0}; } }) ); setGroups(groupsWithCounts); } catch (error) { console.error("Error fetching groups:", error); toast({ title: "Erreur", description: "Erreur lors de la récupération des groupes", variant: "destructive", }); } }; // Filtered users based on search term const filteredUsers = users.filter(user => (user.username?.toLowerCase() || "").includes(searchTerm.toLowerCase()) || (user.email?.toLowerCase() || "").includes(searchTerm.toLowerCase()) || (user.firstName?.toLowerCase() || "").includes(searchTerm.toLowerCase()) || (user.lastName?.toLowerCase() || "").includes(searchTerm.toLowerCase()) ); // Filtered groups based on search term const filteredGroups = groups.filter(group => (group.name?.toLowerCase() || "").includes(searchTerm.toLowerCase()) ); // Function to check if a user is already assigned to any role const isUserAssigned = (userId: string) => { return gardienDuTemps === userId || gardienDeLaParole === userId || gardienDeLaMemoire === userId || volontaires.includes(userId); }; // Function to get user's roles (can now have multiple) const getUserRoles = (userId: string): UserRole[] => { const roles: UserRole[] = []; if (gardienDuTemps === userId) roles.push('temps'); if (gardienDeLaParole === userId) roles.push('parole'); if (gardienDeLaMemoire === userId) roles.push('memoire'); if (volontaires.includes(userId)) roles.push('volontaire'); return roles; }; // For backwards compatibility with existing code const getUserRole = (userId: string): UserRole | null => { const roles = getUserRoles(userId); return roles.length > 0 ? roles[0] : null; }; // Function to get role display name const getRoleDisplayName = (role: UserRole | null): string => { switch(role) { case 'temps': return "Gardien du Temps"; case 'parole': return "Gardien de la Parole"; case 'memoire': return "Gardien de la Mémoire"; case 'volontaire': return "Volontaire"; default: return ""; } }; // Function to assign a user to a specific guardian role const assignGuardienRole = (userId: string, role: GuardienRole) => { // Only remove from volunteers if they're currently a volunteer if (volontaires.includes(userId)) { setVolontaires(prev => prev.filter(id => id !== userId)); } // Assign to new role if (role === 'temps') { setGardienDuTemps(userId); } else if (role === 'parole') { setGardienDeLaParole(userId); } else if (role === 'memoire') { setGardienDeLaMemoire(userId); } toast({ title: "Rôle assigné", description: `L'utilisateur a été assigné comme ${getRoleDisplayName(role)}`, }); }; // Function to assign a user as volunteer const assignVolontaire = (userId: string) => { // Remove from any existing role first removeUserFromAllRoles(userId); // Add to volunteers setVolontaires(prev => [...prev, userId]); toast({ title: "Rôle assigné", description: "L'utilisateur a été assigné comme Volontaire", }); }; // Function to remove a user from all roles const removeUserFromAllRoles = (userId: string) => { if (gardienDuTemps === userId) setGardienDuTemps(null); if (gardienDeLaParole === userId) setGardienDeLaParole(null); if (gardienDeLaMemoire === userId) setGardienDeLaMemoire(null); if (volontaires.includes(userId)) { setVolontaires(prev => prev.filter(id => id !== userId)); } }; // Check if all guardian roles are filled const areAllGuardiensFilled = (): boolean => { return gardienDuTemps !== null && gardienDeLaParole !== null && gardienDeLaMemoire !== null; }; // Function to fetch group members const fetchGroupMembers = async (groupId: string) => { try { const response = await fetch(`/api/groups/${groupId}/members`); if (!response.ok) { throw new Error("Failed to fetch group members"); } const data = await response.json(); return data; } catch (error) { console.error(`Error fetching members for group ${groupId}:`, error); toast({ title: "Erreur", description: "Erreur lors de la récupération des membres du groupe", variant: "destructive", }); return []; } }; // Handler for viewing group members const handleViewGroupMembers = async (groupId: string, groupName: string) => { try { setLoading(true); const members = await fetchGroupMembers(groupId); // Update the users list with the group members and switch to users tab if (Array.isArray(members) && members.length > 0) { setUsers(members); setSelectedTab('users'); setSearchTerm(''); // Clear any existing search toast({ title: `Membres de ${groupName}`, description: `${members.length} membres trouvés et affichés ci-dessous`, }); } else { toast({ title: `Membres de ${groupName}`, description: "Aucun membre trouvé dans ce groupe", }); } } catch (error) { console.error("Error handling group members:", error); toast({ title: "Erreur", description: "Erreur lors de l'affichage des membres du groupe", variant: "destructive", }); } finally { setLoading(false); } }; // Function to navigate to the next tab const goToNextTab = () => { const tabOrder = ["general", "details", "attachments", "skills", "membres"]; const currentIndex = tabOrder.indexOf(activeTab); if (currentIndex < tabOrder.length - 1) { const nextTab = tabOrder[currentIndex + 1]; setActiveTab(nextTab); } }; // Function to navigate to the previous tab const goToPreviousTab = () => { const tabOrder = ["general", "details", "attachments", "skills", "membres"]; const currentIndex = tabOrder.indexOf(activeTab); if (currentIndex > 0) { const prevTab = tabOrder[currentIndex - 1]; setActiveTab(prevTab); } }; // Check if we're on the last tab const isLastTab = () => { return activeTab === "membres"; }; // Check if we're on the first tab const isFirstTab = () => { return activeTab === "general"; }; // Validate all required fields const validateMission = () => { const requiredFields = { name: !!missionData.name, oddScope: Array.isArray(missionData.oddScope) && missionData.oddScope.length > 0, niveau: !!missionData.niveau, intention: !!missionData.intention, missionType: !!missionData.missionType, donneurDOrdre: !!missionData.donneurDOrdre, projection: !!missionData.projection, participation: !!missionData.participation, gardiens: gardienDuTemps !== null && gardienDeLaParole !== null && gardienDeLaMemoire !== null }; const isValid = Object.values(requiredFields).every(field => field === true); if (!isValid) { const missingFields = Object.entries(requiredFields) .filter(([_, value]) => value === false) .map(([key, _]) => key); toast({ title: "Champs obligatoires manquants", description: `Veuillez remplir tous les champs obligatoires: ${missingFields.join(", ")}`, variant: "destructive", }); } return isValid; }; // Handle mission submission const handleSubmitMission = async () => { if (!validateMission()) { return; } setIsSubmitting(true); try { // Prepare the mission data const guardians = { "gardien-temps": gardienDuTemps, "gardien-parole": gardienDeLaParole, "gardien-memoire": gardienDeLaMemoire }; const missionSubmitData = { ...missionData, services: selectedServices, profils: selectedProfils, guardians, volunteers: volontaires }; // Send to API const response = await fetch('/api/missions', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(missionSubmitData), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to create mission'); } const data = await response.json(); toast({ title: "Mission créée avec succès", description: "Tous les gardiens ont été assignés et la mission a été enregistrée.", }); // Redirect to missions list router.push('/missions'); } catch (error) { console.error('Error creating mission:', error); toast({ title: "Erreur", description: error instanceof Error ? error.message : "Une erreur est survenue lors de la création de la mission", variant: "destructive", }); } finally { setIsSubmitting(false); } }; // Function to handle input changes const handleInputChange = (field: string, value: any) => { setMissionData(prev => ({ ...prev, [field]: value })); }; return (
General Details Attachments Skills Membres
handleInputChange('name', e.target.value)} />
{ // Handle logo upload complete if (data?.filePath) { setMissionData(prev => ({ ...prev, logo: data.filePath })); } }} />
Paragraphe