Checkpoint: Ajout d'un système complet de filtres et de recherche : filtres par date, lieu, statut et capacité pour les sessions ; recherche par nom/description pour les formations ; recherche multi-critères pour les apprenants. Compteurs de résultats inclus.
This commit is contained in:
@@ -6,14 +6,15 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { trpc } from "@/lib/trpc";
|
||||
import { Plus, Pencil, Trash2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Plus, Pencil, Trash2, Search, SlidersHorizontal } from "lucide-react";
|
||||
import { useState, useMemo } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
export default function AdminApprenants() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [editingId, setEditingId] = useState<number | null>(null);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [formData, setFormData] = useState({
|
||||
nom: "",
|
||||
prenom: "",
|
||||
@@ -89,6 +90,21 @@ export default function AdminApprenants() {
|
||||
}
|
||||
};
|
||||
|
||||
// Filtrer les apprenants
|
||||
const filteredApprenants = useMemo(() => {
|
||||
if (!apprenants) return [];
|
||||
|
||||
return apprenants.filter(apprenant => {
|
||||
const matchesSearch = searchTerm === "" ||
|
||||
apprenant.nom.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
apprenant.prenom.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
apprenant.email.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
apprenant.codeEtablissement.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
|
||||
return matchesSearch;
|
||||
});
|
||||
}, [apprenants, searchTerm]);
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
@@ -177,6 +193,36 @@ export default function AdminApprenants() {
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
{/* Filtres et recherche */}
|
||||
<Card className="mb-6">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<SlidersHorizontal className="w-5 h-5" />
|
||||
Recherche
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="search">Rechercher un apprenant</Label>
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
id="search"
|
||||
placeholder="Nom, prénom, email ou code établissement..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="pl-8"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Compteur de résultats */}
|
||||
<div className="mt-4 text-sm text-muted-foreground">
|
||||
{filteredApprenants.length} apprenant(s) trouvé(s)
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Liste des apprenants</CardTitle>
|
||||
@@ -191,7 +237,7 @@ export default function AdminApprenants() {
|
||||
<Skeleton className="h-10 w-full" />
|
||||
<Skeleton className="h-10 w-full" />
|
||||
</div>
|
||||
) : apprenants && apprenants.length > 0 ? (
|
||||
) : filteredApprenants && filteredApprenants.length > 0 ? (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
@@ -203,7 +249,7 @@ export default function AdminApprenants() {
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{apprenants.map((apprenant) => (
|
||||
{filteredApprenants.map((apprenant) => (
|
||||
<TableRow key={apprenant.id}>
|
||||
<TableCell className="font-medium">{apprenant.nom}</TableCell>
|
||||
<TableCell>{apprenant.prenom}</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user