missions
This commit is contained in:
parent
cefc9fd072
commit
a1cb75a1ec
@ -18,22 +18,25 @@ import {
|
|||||||
} from "../ui/card";
|
} from "../ui/card";
|
||||||
import { Badge } from "../ui/badge";
|
import { Badge } from "../ui/badge";
|
||||||
import { X, Search, UserPlus, Users } from "lucide-react";
|
import { X, Search, UserPlus, Users } from "lucide-react";
|
||||||
|
import { toast } from "../ui/use-toast";
|
||||||
|
|
||||||
// Mock user data - in a real app, this would come from an API
|
// Define interfaces for user and group data
|
||||||
const mockUsers = [
|
interface User {
|
||||||
{ id: '1', username: 'user1', firstName: 'John', lastName: 'Doe', email: 'john@example.com' },
|
id: string;
|
||||||
{ id: '2', username: 'user2', firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com' },
|
username: string;
|
||||||
{ id: '3', username: 'user3', firstName: 'Alice', lastName: 'Johnson', email: 'alice@example.com' },
|
firstName: string;
|
||||||
{ id: '4', username: 'user4', firstName: 'Bob', lastName: 'Brown', email: 'bob@example.com' },
|
lastName: string;
|
||||||
{ id: '5', username: 'user5', firstName: 'Eva', lastName: 'Martinez', email: 'eva@example.com' },
|
email: string;
|
||||||
];
|
roles?: string[];
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
// Mock group data
|
interface Group {
|
||||||
const mockGroups = [
|
id: string;
|
||||||
{ id: '1', name: 'Group A', path: '/group-a', membersCount: 3 },
|
name: string;
|
||||||
{ id: '2', name: 'Group B', path: '/group-b', membersCount: 5 },
|
path: string;
|
||||||
{ id: '3', name: 'Group C', path: '/group-c', membersCount: 2 },
|
membersCount: number;
|
||||||
];
|
}
|
||||||
|
|
||||||
export function MissionsAdminPanel() {
|
export function MissionsAdminPanel() {
|
||||||
const [selectedServices, setSelectedServices] = useState<string[]>([]);
|
const [selectedServices, setSelectedServices] = useState<string[]>([]);
|
||||||
@ -44,20 +47,100 @@ export function MissionsAdminPanel() {
|
|||||||
const [gardienDeLaParole, setGardienDeLaParole] = useState<string | null>(null);
|
const [gardienDeLaParole, setGardienDeLaParole] = useState<string | null>(null);
|
||||||
const [gardienDeLaMemoire, setGardienDeLaMemoire] = useState<string | null>(null);
|
const [gardienDeLaMemoire, setGardienDeLaMemoire] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// State for storing fetched data
|
||||||
|
const [users, setUsers] = useState<User[]>([]);
|
||||||
|
const [groups, setGroups] = useState<Group[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
// 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
|
// Filtered users based on search term
|
||||||
const filteredUsers = mockUsers.filter(user =>
|
const filteredUsers = users.filter(user =>
|
||||||
user.username.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
(user.username?.toLowerCase() || "").includes(searchTerm.toLowerCase()) ||
|
||||||
user.email.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
(user.email?.toLowerCase() || "").includes(searchTerm.toLowerCase()) ||
|
||||||
user.firstName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
(user.firstName?.toLowerCase() || "").includes(searchTerm.toLowerCase()) ||
|
||||||
user.lastName.toLowerCase().includes(searchTerm.toLowerCase())
|
(user.lastName?.toLowerCase() || "").includes(searchTerm.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
// Filtered groups based on search term
|
// Filtered groups based on search term
|
||||||
const filteredGroups = mockGroups.filter(group =>
|
const filteredGroups = groups.filter(group =>
|
||||||
group.name.toLowerCase().includes(searchTerm.toLowerCase())
|
(group.name?.toLowerCase() || "").includes(searchTerm.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
// Function to check if a user is already selected for a role
|
// Function to check if a user is already assigned for a role
|
||||||
const isUserAssigned = (userId: string) => {
|
const isUserAssigned = (userId: string) => {
|
||||||
return gardienDuTemps === userId ||
|
return gardienDuTemps === userId ||
|
||||||
gardienDeLaParole === userId ||
|
gardienDeLaParole === userId ||
|
||||||
@ -94,6 +177,44 @@ export function MissionsAdminPanel() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
// Here you would typically open a dialog to show members
|
||||||
|
// For this implementation, we'll just show a toast with the count
|
||||||
|
toast({
|
||||||
|
title: `Membres de ${groupName}`,
|
||||||
|
description: `${members.length} membres trouvés dans ce groupe`,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error handling group members:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Card className="border shadow-sm bg-white">
|
<Card className="border shadow-sm bg-white">
|
||||||
@ -524,20 +645,32 @@ export function MissionsAdminPanel() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => removeUserRole('temps')}
|
onClick={() => removeUserRole('temps')}
|
||||||
className="text-red-600 hover:bg-red-50 border-red-200 h-8"
|
className="text-red-600 hover:bg-red-50 border-red-200 h-8"
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<X size={16} className="mr-1" />
|
<X size={16} className="mr-1" />
|
||||||
Supprimer
|
Supprimer
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{gardienDuTemps ? (
|
{loading ? (
|
||||||
|
<div className="flex items-center py-2 px-3 bg-gray-50 border border-gray-200 rounded-md">
|
||||||
|
<div className="animate-pulse w-full flex items-center">
|
||||||
|
<div className="h-10 w-10 bg-gray-300 rounded-full mr-3"></div>
|
||||||
|
<div className="flex-1 space-y-2">
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/3"></div>
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
gardienDuTemps ? (
|
||||||
<div className="bg-blue-50 border border-blue-100 rounded-md p-3">
|
<div className="bg-blue-50 border border-blue-100 rounded-md p-3">
|
||||||
{(() => {
|
{(() => {
|
||||||
const user = mockUsers.find(u => u.id === gardienDuTemps);
|
const user = users.find(u => u.id === gardienDuTemps);
|
||||||
return user ? (
|
return user ? (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-medium mr-3">
|
<div className="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-medium mr-3">
|
||||||
{user.firstName[0]}{user.lastName[0]}
|
{user.firstName?.[0] || ""}{user.lastName?.[0] || ""}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
||||||
@ -554,6 +687,7 @@ export function MissionsAdminPanel() {
|
|||||||
</div>
|
</div>
|
||||||
<span className="text-sm">Aucun utilisateur sélectionné</span>
|
<span className="text-sm">Aucun utilisateur sélectionné</span>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -567,20 +701,32 @@ export function MissionsAdminPanel() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => removeUserRole('parole')}
|
onClick={() => removeUserRole('parole')}
|
||||||
className="text-red-600 hover:bg-red-50 border-red-200 h-8"
|
className="text-red-600 hover:bg-red-50 border-red-200 h-8"
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<X size={16} className="mr-1" />
|
<X size={16} className="mr-1" />
|
||||||
Supprimer
|
Supprimer
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{gardienDeLaParole ? (
|
{loading ? (
|
||||||
|
<div className="flex items-center py-2 px-3 bg-gray-50 border border-gray-200 rounded-md">
|
||||||
|
<div className="animate-pulse w-full flex items-center">
|
||||||
|
<div className="h-10 w-10 bg-gray-300 rounded-full mr-3"></div>
|
||||||
|
<div className="flex-1 space-y-2">
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/3"></div>
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
gardienDeLaParole ? (
|
||||||
<div className="bg-blue-50 border border-blue-100 rounded-md p-3">
|
<div className="bg-blue-50 border border-blue-100 rounded-md p-3">
|
||||||
{(() => {
|
{(() => {
|
||||||
const user = mockUsers.find(u => u.id === gardienDeLaParole);
|
const user = users.find(u => u.id === gardienDeLaParole);
|
||||||
return user ? (
|
return user ? (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-medium mr-3">
|
<div className="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-medium mr-3">
|
||||||
{user.firstName[0]}{user.lastName[0]}
|
{user.firstName?.[0] || ""}{user.lastName?.[0] || ""}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
||||||
@ -597,6 +743,7 @@ export function MissionsAdminPanel() {
|
|||||||
</div>
|
</div>
|
||||||
<span className="text-sm">Aucun utilisateur sélectionné</span>
|
<span className="text-sm">Aucun utilisateur sélectionné</span>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -610,20 +757,32 @@ export function MissionsAdminPanel() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => removeUserRole('memoire')}
|
onClick={() => removeUserRole('memoire')}
|
||||||
className="text-red-600 hover:bg-red-50 border-red-200 h-8"
|
className="text-red-600 hover:bg-red-50 border-red-200 h-8"
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<X size={16} className="mr-1" />
|
<X size={16} className="mr-1" />
|
||||||
Supprimer
|
Supprimer
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{gardienDeLaMemoire ? (
|
{loading ? (
|
||||||
|
<div className="flex items-center py-2 px-3 bg-gray-50 border border-gray-200 rounded-md">
|
||||||
|
<div className="animate-pulse w-full flex items-center">
|
||||||
|
<div className="h-10 w-10 bg-gray-300 rounded-full mr-3"></div>
|
||||||
|
<div className="flex-1 space-y-2">
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/3"></div>
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
gardienDeLaMemoire ? (
|
||||||
<div className="bg-blue-50 border border-blue-100 rounded-md p-3">
|
<div className="bg-blue-50 border border-blue-100 rounded-md p-3">
|
||||||
{(() => {
|
{(() => {
|
||||||
const user = mockUsers.find(u => u.id === gardienDeLaMemoire);
|
const user = users.find(u => u.id === gardienDeLaMemoire);
|
||||||
return user ? (
|
return user ? (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-medium mr-3">
|
<div className="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-medium mr-3">
|
||||||
{user.firstName[0]}{user.lastName[0]}
|
{user.firstName?.[0] || ""}{user.lastName?.[0] || ""}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
||||||
@ -640,6 +799,7 @@ export function MissionsAdminPanel() {
|
|||||||
</div>
|
</div>
|
||||||
<span className="text-sm">Aucun utilisateur sélectionné</span>
|
<span className="text-sm">Aucun utilisateur sélectionné</span>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -655,6 +815,7 @@ export function MissionsAdminPanel() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setSelectedTab('users')}
|
onClick={() => setSelectedTab('users')}
|
||||||
className={selectedTab === 'users' ? 'bg-blue-600 text-white' : 'text-gray-700'}
|
className={selectedTab === 'users' ? 'bg-blue-600 text-white' : 'text-gray-700'}
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<Users size={16} className="mr-1" />
|
<Users size={16} className="mr-1" />
|
||||||
Utilisateurs
|
Utilisateurs
|
||||||
@ -664,6 +825,7 @@ export function MissionsAdminPanel() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setSelectedTab('groups')}
|
onClick={() => setSelectedTab('groups')}
|
||||||
className={selectedTab === 'groups' ? 'bg-blue-600 text-white' : 'text-gray-700'}
|
className={selectedTab === 'groups' ? 'bg-blue-600 text-white' : 'text-gray-700'}
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<Users size={16} className="mr-1" />
|
<Users size={16} className="mr-1" />
|
||||||
Groupes
|
Groupes
|
||||||
@ -679,9 +841,26 @@ export function MissionsAdminPanel() {
|
|||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
className="pl-9 bg-white text-gray-900 border-gray-300"
|
className="pl-9 bg-white text-gray-900 border-gray-300"
|
||||||
|
disabled={loading}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{loading ? (
|
||||||
|
<div className="border rounded-md p-6 flex flex-col items-center justify-center text-gray-500">
|
||||||
|
<div className="animate-pulse space-y-4 w-full">
|
||||||
|
{[1, 2, 3].map((i) => (
|
||||||
|
<div key={i} className="flex items-center py-3 px-4">
|
||||||
|
<div className="h-10 w-10 bg-gray-300 rounded-full mr-3"></div>
|
||||||
|
<div className="flex-1 space-y-2">
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/3"></div>
|
||||||
|
<div className="h-3 bg-gray-300 rounded w-1/2"></div>
|
||||||
|
</div>
|
||||||
|
<div className="h-7 w-16 bg-gray-300 rounded"></div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<div className="border rounded-md max-h-[300px] overflow-y-auto">
|
<div className="border rounded-md max-h-[300px] overflow-y-auto">
|
||||||
{selectedTab === 'users' ? (
|
{selectedTab === 'users' ? (
|
||||||
filteredUsers.length > 0 ? (
|
filteredUsers.length > 0 ? (
|
||||||
@ -690,7 +869,7 @@ export function MissionsAdminPanel() {
|
|||||||
<div key={user.id} className="p-3 hover:bg-gray-50 flex items-center justify-between">
|
<div key={user.id} className="p-3 hover:bg-gray-50 flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="h-10 w-10 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 font-medium mr-3">
|
<div className="h-10 w-10 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 font-medium mr-3">
|
||||||
{user.firstName[0]}{user.lastName[0]}
|
{user.firstName?.[0] || ""}{user.lastName?.[0] || ""}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
<div className="font-medium text-gray-900">{user.firstName} {user.lastName}</div>
|
||||||
@ -711,6 +890,7 @@ export function MissionsAdminPanel() {
|
|||||||
if (gardienDeLaMemoire === user.id) removeUserRole('memoire');
|
if (gardienDeLaMemoire === user.id) removeUserRole('memoire');
|
||||||
}}
|
}}
|
||||||
className="text-red-600 hover:bg-red-50 border-red-200 h-7 px-2"
|
className="text-red-600 hover:bg-red-50 border-red-200 h-7 px-2"
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<X size={14} />
|
<X size={14} />
|
||||||
</Button>
|
</Button>
|
||||||
@ -725,7 +905,7 @@ export function MissionsAdminPanel() {
|
|||||||
else if (!gardienDeLaParole) assignUserRole(user.id, 'parole');
|
else if (!gardienDeLaParole) assignUserRole(user.id, 'parole');
|
||||||
else if (!gardienDeLaMemoire) assignUserRole(user.id, 'memoire');
|
else if (!gardienDeLaMemoire) assignUserRole(user.id, 'memoire');
|
||||||
}}
|
}}
|
||||||
disabled={gardienDuTemps !== null && gardienDeLaParole !== null && gardienDeLaMemoire !== null}
|
disabled={(gardienDuTemps !== null && gardienDeLaParole !== null && gardienDeLaMemoire !== null) || loading}
|
||||||
className="text-blue-600 hover:bg-blue-50 border-blue-200 h-8"
|
className="text-blue-600 hover:bg-blue-50 border-blue-200 h-8"
|
||||||
>
|
>
|
||||||
<UserPlus size={16} className="mr-1" />
|
<UserPlus size={16} className="mr-1" />
|
||||||
@ -758,7 +938,9 @@ export function MissionsAdminPanel() {
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
onClick={() => handleViewGroupMembers(group.id, group.name)}
|
||||||
className="text-blue-600 hover:bg-blue-50 border-blue-200 h-8"
|
className="text-blue-600 hover:bg-blue-50 border-blue-200 h-8"
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<Users size={16} className="mr-1" />
|
<Users size={16} className="mr-1" />
|
||||||
Voir membres
|
Voir membres
|
||||||
@ -773,6 +955,7 @@ export function MissionsAdminPanel() {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user