- Updated `AdminClientWrapper` to filter out teams with zero members in `getFilteredTeamStats`. - Modified `AdminFilters` to only include directions and teams with members in the options. - Enhanced `AdminService` to generate direction stats based on teams with members, improving data accuracy.
121 lines
3.7 KiB
TypeScript
121 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import { Users, Target, Building2, Filter } from "lucide-react";
|
|
import { Team } from "@/lib/types";
|
|
import { TeamStats } from "@/services/admin-service";
|
|
import { MultiSelectFilter } from "./multi-select-filter";
|
|
|
|
interface AdminFiltersProps {
|
|
teams: Team[];
|
|
teamStats: TeamStats[];
|
|
selectedDirections: string[];
|
|
selectedTeams: string[];
|
|
onDirectionsChange: (directions: string[]) => void;
|
|
onTeamsChange: (teams: string[]) => void;
|
|
getFilteredTeamStats: () => TeamStats[];
|
|
}
|
|
|
|
export function AdminFilters({
|
|
teams,
|
|
teamStats,
|
|
selectedDirections,
|
|
selectedTeams,
|
|
onDirectionsChange,
|
|
onTeamsChange,
|
|
getFilteredTeamStats,
|
|
}: AdminFiltersProps) {
|
|
const hasFilters = selectedDirections.length > 0 || selectedTeams.length > 0;
|
|
|
|
const directionOptions = Array.from(
|
|
new Set(
|
|
teamStats
|
|
.filter((team) => team.totalMembers > 0)
|
|
.map((team) => team.direction)
|
|
)
|
|
).map((direction) => ({
|
|
id: direction,
|
|
label: direction,
|
|
count: teamStats.filter(
|
|
(team) => team.direction === direction && team.totalMembers > 0
|
|
).length,
|
|
}));
|
|
|
|
const teamOptions = teams
|
|
.filter((team) => {
|
|
const teamStat = teamStats.find((stat) => stat.teamId === team.id);
|
|
return teamStat && teamStat.totalMembers > 0;
|
|
})
|
|
.map((team) => ({
|
|
id: team.id,
|
|
label: `${team.name} (${team.direction})`,
|
|
count:
|
|
teamStats.find((stat) => stat.teamId === team.id)?.totalMembers || 0,
|
|
}));
|
|
|
|
const handleReset = () => {
|
|
onDirectionsChange([]);
|
|
onTeamsChange([]);
|
|
};
|
|
|
|
return (
|
|
<div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-6">
|
|
<div className="flex items-center gap-2 mb-6">
|
|
<div className="p-2 bg-blue-500/20 border border-blue-500/30 rounded-xl">
|
|
<Filter className="h-4 w-4 text-blue-400" />
|
|
</div>
|
|
<h3 className="text-lg font-semibold text-white">Filtres avancés</h3>
|
|
</div>
|
|
|
|
<div className="flex flex-col lg:flex-row gap-4">
|
|
<div className="flex-1">
|
|
<MultiSelectFilter
|
|
title="Directions"
|
|
options={directionOptions}
|
|
selectedValues={selectedDirections}
|
|
onChange={onDirectionsChange}
|
|
placeholder="Toutes les directions"
|
|
icon={<Building2 className="h-4 w-4" />}
|
|
/>
|
|
</div>
|
|
<div className="flex-1">
|
|
<MultiSelectFilter
|
|
title="Équipes"
|
|
options={teamOptions}
|
|
selectedValues={selectedTeams}
|
|
onChange={onTeamsChange}
|
|
placeholder="Toutes les équipes"
|
|
icon={<Users className="h-4 w-4" />}
|
|
/>
|
|
</div>
|
|
|
|
{/* Résumé des filtres actifs */}
|
|
{hasFilters && (
|
|
<div className="flex flex-col lg:flex-row items-center gap-3">
|
|
<div className="bg-blue-500/20 border border-blue-500/30 rounded-xl px-3 py-2">
|
|
<div className="flex items-center gap-2">
|
|
<Target className="h-3 w-3 text-blue-400" />
|
|
<span className="text-sm text-blue-300 font-medium">
|
|
{getFilteredTeamStats().reduce(
|
|
(sum, t) => sum + t.totalMembers,
|
|
0
|
|
)}{" "}
|
|
membres
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={handleReset}
|
|
className="text-xs text-slate-400 hover:text-white hover:bg-white/10"
|
|
>
|
|
Réinitialiser
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|