Checkpoint: Correction du bug FormateurCombobox manquant

 **Problème résolu**
- Le fichier FormateurCombobox.tsx avait été perdu lors d'une manipulation précédente
- Fichier recréé avec toutes les fonctionnalités :
  * Autocomplétion avec recherche en temps réel
  * Ajout rapide de nouveaux formateurs depuis le composant
  * Intégration complète avec tRPC

 **Import corrigé**
- Import ajouté dans AdminSequences.tsx
- Serveur redémarré pour détecter le nouveau fichier

Le formulaire de modification des séquences fonctionne maintenant correctement avec le champ formateur.
This commit is contained in:
Manus Sandbox
2025-11-19 10:53:22 -05:00
parent 2283e84b54
commit b7cadc173b
3 changed files with 173 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
import { useState, useEffect } from "react";
import { Check, ChevronsUpDown, Plus } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { trpc } from "@/lib/trpc";
import { toast } from "sonner";
interface FormateurComboboxProps {
value?: string | null;
onChange: (value: string) => void;
placeholder?: string;
}
export default function FormateurCombobox({
value,
onChange,
placeholder = "Sélectionner un formateur",
}: FormateurComboboxProps) {
const [open, setOpen] = useState(false);
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
const [newFormateurNom, setNewFormateurNom] = useState("");
const { data: formateurs, refetch } = trpc.formateurs.list.useQuery();
const createMutation = trpc.formateurs.create.useMutation({
onSuccess: () => {
toast.success("Formateur ajouté avec succès");
refetch();
setIsAddDialogOpen(false);
setNewFormateurNom("");
},
onError: (error) => {
toast.error(`Erreur: ${error.message}`);
},
});
const handleAddFormateur = () => {
if (!newFormateurNom.trim()) {
toast.error("Le nom du formateur est requis");
return;
}
createMutation.mutate({ nom: newFormateurNom.trim() });
};
const selectedFormateur = formateurs?.find((f) => f.nom === value);
return (
<>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-full justify-between"
>
{selectedFormateur ? selectedFormateur.nom : placeholder}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-full p-0">
<Command>
<CommandInput placeholder="Rechercher un formateur..." />
<CommandList>
<CommandEmpty>Aucun formateur trouvé.</CommandEmpty>
<CommandGroup>
{formateurs?.map((formateur) => (
<CommandItem
key={formateur.id}
value={formateur.nom}
onSelect={(currentValue) => {
onChange(currentValue === value ? "" : currentValue);
setOpen(false);
}}
>
<Check
className={cn(
"mr-2 h-4 w-4",
value === formateur.nom ? "opacity-100" : "opacity-0"
)}
/>
{formateur.nom}
</CommandItem>
))}
</CommandGroup>
</CommandList>
<div className="border-t p-2">
<Button
variant="ghost"
className="w-full justify-start"
onClick={() => {
setOpen(false);
setIsAddDialogOpen(true);
}}
>
<Plus className="mr-2 h-4 w-4" />
Ajouter un nouveau formateur
</Button>
</div>
</Command>
</PopoverContent>
</Popover>
<Dialog open={isAddDialogOpen} onOpenChange={setIsAddDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Ajouter un nouveau formateur</DialogTitle>
<DialogDescription>
Entrez le nom du formateur à ajouter à la liste.
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="nom">Nom du formateur *</Label>
<Input
id="nom"
value={newFormateurNom}
onChange={(e) => setNewFormateurNom(e.target.value)}
placeholder="Ex: Jean Dupont"
/>
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => {
setIsAddDialogOpen(false);
setNewFormateurNom("");
}}
>
Annuler
</Button>
<Button
onClick={handleAddFormateur}
disabled={createMutation.isPending}
>
{createMutation.isPending ? "Ajout..." : "Ajouter"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}