"use client"; import React, { useState, useEffect } from "react"; import { logger } from '@/lib/logger'; import { Input } from "../ui/input"; import { Button } from "../ui/button"; 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"; // Define interfaces for user and group data export interface User { id: string; username: string; firstName: string; lastName: string; email: string; roles?: string[]; enabled?: boolean; } export interface Group { id: string; name: string; path: string; membersCount: number; } // User role types in mission export type GuardienRole = 'temps' | 'parole' | 'memoire'; export type UserRole = GuardienRole | 'volontaire'; interface MissionMembersPanelProps { gardienDuTemps: string | null; gardienDeLaParole: string | null; gardienDeLaMemoire: string | null; volontaires: string[]; onGardienDuTempsChange: (userId: string | null) => void; onGardienDeLaParoleChange: (userId: string | null) => void; onGardienDeLaMemoireChange: (userId: string | null) => void; onVolontairesChange: (userIds: string[]) => void; } export function MissionMembersPanel({ gardienDuTemps, gardienDeLaParole, gardienDeLaMemoire, volontaires, onGardienDuTempsChange, onGardienDeLaParoleChange, onGardienDeLaMemoireChange, onVolontairesChange, }: MissionMembersPanelProps) { const [searchTerm, setSearchTerm] = useState(""); const [selectedTab, setSelectedTab] = useState<'users' | 'groups'>('users'); 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) { logger.error("Error fetching data", { error: error instanceof Error ? error.message : String(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) { logger.error("Error fetching users", { error: error instanceof Error ? error.message : String(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) { logger.error(`Error fetching members for group ${group.id}`, { error: error instanceof Error ? error.message : String(error) }); return {...group, membersCount: 0}; } }) ); setGroups(groupsWithCounts); } catch (error) { logger.error("Error fetching groups", { error: error instanceof Error ? error.message : String(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; }; // 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)) { onVolontairesChange(volontaires.filter(id => id !== userId)); } // Assign to new role if (role === 'temps') { onGardienDuTempsChange(userId); } else if (role === 'parole') { onGardienDeLaParoleChange(userId); } else if (role === 'memoire') { onGardienDeLaMemoireChange(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 onVolontairesChange([...volontaires, 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) onGardienDuTempsChange(null); if (gardienDeLaParole === userId) onGardienDeLaParoleChange(null); if (gardienDeLaMemoire === userId) onGardienDeLaMemoireChange(null); if (volontaires.includes(userId)) { onVolontairesChange(volontaires.filter(id => id !== userId)); } }; // 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) { logger.error(`Error fetching members for group ${groupId}`, { error: error instanceof Error ? error.message : String(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) { logger.error("Error handling group members", { error: error instanceof Error ? error.message : String(error) }); toast({ title: "Erreur", description: "Erreur lors de l'affichage des membres du groupe", variant: "destructive", }); } finally { setLoading(false); } }; // Helper component for Guardian card const GuardianCard = ({ title, userId, onRemove }: { title: string; userId: string | null; onRemove: () => void; }) => { const user = userId ? users.find(u => u.id === userId) : null; return (

{title}

{userId && ( )}
{loading ? (
) : user ? (
{user.firstName?.[0] || ""}{user.lastName?.[0] || ""}
{user.firstName} {user.lastName}
{user.email}
) : (
Aucun utilisateur sélectionné
)}
); }; return (

Les Gardiens de l'Intention

{!isMissionValid && (
Les 3 gardiens doivent être assignés
)} {isMissionValid && (
Tous les gardiens sont assignés
)}
removeUserFromAllRoles(gardienDuTemps!)} /> removeUserFromAllRoles(gardienDeLaParole!)} /> removeUserFromAllRoles(gardienDeLaMemoire!)} />

Sélectionner des membres

Volontaires ({volontaires.length})
{volontaires.length > 0 ? (
{volontaires.map(userId => { const user = users.find(u => u.id === userId); if (!user) return null; return ( {user.firstName} {user.lastName} ); })}
) : (
Aucun volontaire assigné
)}
setSearchTerm(e.target.value)} className="pl-9 bg-white text-gray-900 border-gray-300" disabled={loading} />
{loading ? (
{[1, 2, 3].map((i) => (
))}
) : (
{selectedTab === 'users' ? ( filteredUsers.length > 0 ? (
{filteredUsers.map(user => { const displayName = (user.firstName && user.lastName) ? `${user.firstName} ${user.lastName}` : user.firstName || user.lastName || user.username || user.email || 'Utilisateur'; const initials = (user.firstName?.[0] || "") + (user.lastName?.[0] || "") || user.username?.[0]?.toUpperCase() || user.email?.[0]?.toUpperCase() || "?"; return (
{initials}
{displayName}
{user.email || user.username || ''}
{isUserAssigned(user.id) && (
{getUserRoles(user.id).map((role) => ( {getRoleDisplayName(role)} ))}
)}
{/* User role controls always show dropdown */}
assignGuardienRole(user.id, 'temps')} className="cursor-pointer" > Gardien du Temps assignGuardienRole(user.id, 'parole')} className="cursor-pointer" > Gardien de la Parole assignGuardienRole(user.id, 'memoire')} className="cursor-pointer" > Gardien de la Mémoire {isUserAssigned(user.id) && ( )}
); })}
) : (
Aucun utilisateur trouvé
) ) : ( filteredGroups.length > 0 ? (
{filteredGroups.map(group => (
{group.name}
{group.membersCount} membres
))}
) : (
Aucun groupe trouvé
) )}
)}
); }