import { useState } from "react"; import { Page } from "@/components/layout/app-shell"; import { PageHeader } from "@/components/layout/page-header"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { EmptyState } from "@/components/empty-state"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; 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"; import { handleUnauthorized } from "@/lib/queryClient"; interface AudioTrack { id: number; userId: number; title: string; url: string; duration: number | null; createdAt: string; } export default function AudioAdmin() { const [isUploading, setIsUploading] = useState(false); const [playingTrackId, setPlayingTrackId] = useState(null); const [audioElement, setAudioElement] = useState(null); const [trackToDelete, setTrackToDelete] = 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, credentials: "include", }); if (!res.ok) { if (res.status === 401) handleUnauthorized("/api/audio-tracks"); 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: "Import 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", credentials: "include", }); if (!res.ok) { if (res.status === 401) handleUnauthorized(`/api/audio-tracks/${id}`); 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 ( } /> {isLoading ? (
{[1, 2, 3].map((i) => (
))}
) : tracks.length === 0 ? ( } /> ) : ( <>

{tracks.length} piste(s)

{tracks.map((track) => { const playing = playingTrackId === track.id; return (

{track.title}

Ajoutée le {format(new Date(track.createdAt), "d MMM yyyy", { locale: fr })}

); })}
)} !open && setTrackToDelete(null)}> Supprimer cette musique ? « {trackToDelete?.title} » ne sera plus proposée dans les nouveaux Reels. Annuler { if (trackToDelete) deleteMutation.mutate(trackToDelete.id); setTrackToDelete(null); }} > Supprimer ); }