import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import Sidebar from "@/components/sidebar"; import TopBar from "@/components/topbar"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { useToast } from "@/hooks/use-toast"; import { Trash2, Music, Upload, Loader2, Play, Pause } from "lucide-react"; import { format } from "date-fns"; import { fr } from "date-fns/locale"; interface AudioTrack { id: number; userId: number; title: string; url: string; duration: number | null; createdAt: string; } export default function AudioAdmin() { const [sidebarOpen, setSidebarOpen] = useState(false); const [isUploading, setIsUploading] = useState(false); const [playingTrackId, setPlayingTrackId] = useState(null); const [audioElement, setAudioElement] = useState(null); const { toast } = useToast(); const queryClient = useQueryClient(); const { data: tracks = [], isLoading } = useQuery({ queryKey: ["/api/audio-tracks"], }); const uploadMutation = useMutation({ mutationFn: async (files: File[]) => { const formData = new FormData(); for (const file of files) { formData.append("files", file); } const res = await fetch("/api/audio-tracks", { method: "POST", body: formData, }); if (!res.ok) { const error = await res.json(); throw new Error(error.error || "Erreur lors de l'upload"); } return res.json(); }, onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: ["/api/audio-tracks"] }); const successCount = data.results?.filter((r: any) => r.success).length ?? 0; const failCount = data.results?.filter((r: any) => !r.success).length ?? 0; toast({ title: "Upload terminé", description: failCount > 0 ? `${successCount} fichier(s) ajouté(s), ${failCount} échec(s)` : `${successCount} fichier(s) ajouté(s) à la bibliothèque`, }); }, onError: (error: Error) => { toast({ title: "Erreur", description: error.message, variant: "destructive", }); }, onSettled: () => { setIsUploading(false); } }); const deleteMutation = useMutation({ mutationFn: async (id: number) => { const res = await fetch(`/api/audio-tracks/${id}`, { method: "DELETE", }); if (!res.ok) { throw new Error("Erreur lors de la suppression"); } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/audio-tracks"] }); toast({ title: "Succès", description: "La piste audio a été supprimée", }); }, onError: (error: Error) => { toast({ title: "Erreur", description: error.message, variant: "destructive", }); } }); const handleFileUpload = (e: React.ChangeEvent) => { const files = Array.from(e.target.files || []); if (files.length === 0) return; const invalidFiles = files.filter(f => !f.type.startsWith("audio/")); if (invalidFiles.length > 0) { toast({ title: "Format invalide", description: "Certains fichiers ne sont pas des fichiers audio (MP3, WAV, etc.)", variant: "destructive", }); return; } setIsUploading(true); uploadMutation.mutate(files); // Reset input if (e.target) { e.target.value = ""; } }; const togglePlay = (track: AudioTrack) => { if (playingTrackId === track.id) { audioElement?.pause(); setPlayingTrackId(null); } else { if (audioElement) { audioElement.pause(); } const newAudio = new Audio(track.url); newAudio.play(); newAudio.onended = () => { setPlayingTrackId(null); }; setAudioElement(newAudio); setPlayingTrackId(track.id); } }; return (
{sidebarOpen && (
setSidebarOpen(false)} /> )}
setSidebarOpen(false)} />
setSidebarOpen(!sidebarOpen)} />

Bibliothèque Audio

Gérez les musiques disponibles pour la création de Reels

Musiques ({tracks.length}) Ces pistes pourront être sélectionnées par les utilisateurs lors de la création d'un nouveau Reel. {isLoading ? (
) : tracks.length === 0 ? (

Aucune musique

Vous n'avez pas encore ajouté de piste audio. Les musiques ajoutées ici seront utilisables pour les Reels.

) : (
{tracks.map((track) => (

{track.title}

{format(new Date(track.createdAt), "dd MMM yyyy", { locale: fr })}

))}
)}
); }