/** * Composant pour les actions batch sur les playlists * T0506: Create Playlist Batch Operations */ import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Dialog } from '@/components/ui/dialog'; import { Trash2, Share2, Download, X, Loader2 } from 'lucide-react'; import { useDeletePlaylist, useCreateShareLink } from '../hooks/usePlaylist'; import { useToast } from '@/hooks/useToast'; import { cn } from '@/lib/utils'; import type { Playlist } from '../types'; interface PlaylistBatchActionsProps { selectedPlaylists: Playlist[]; onSelectionClear: () => void; onPlaylistsDeleted?: () => void; className?: string; } /** * Exporte les playlists sélectionnées au format JSON */ function exportPlaylistsToJSON(playlists: Playlist[]): void { const dataStr = JSON.stringify(playlists, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `playlists-${new Date().toISOString().split('T')[0]}.json`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } /** * Exporte les playlists sélectionnées au format CSV */ function exportPlaylistsToCSV(playlists: Playlist[]): void { const headers = [ 'ID', 'Titre', 'Description', 'Publique', 'Nombre de tracks', 'Créée le', ]; const rows = playlists.map((p) => [ p.id.toString(), p.title, p.description || '', p.is_public ? 'Oui' : 'Non', p.track_count.toString(), new Date(p.created_at).toLocaleDateString('fr-FR'), ]); const csvContent = [ headers.join(','), ...rows.map((row) => row.map((cell) => `"${cell.replace(/"/g, '""')}"`).join(','), ), ].join('\n'); const dataBlob = new Blob([`\ufeff${csvContent}`], { type: 'text/csv;charset=utf-8;', }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `playlists-${new Date().toISOString().split('T')[0]}.csv`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } export function PlaylistBatchActions({ selectedPlaylists, onSelectionClear, onPlaylistsDeleted, className, }: PlaylistBatchActionsProps) { const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [isSharing, setIsSharing] = useState(false); const { success: showSuccess, error: showError } = useToast(); const deleteMutation = useDeletePlaylist(); const createShareLinkMutation = useCreateShareLink(); const selectedCount = selectedPlaylists.length; if (selectedCount === 0) { return null; } const handleDelete = async () => { setIsDeleting(true); let successCount = 0; let errorCount = 0; try { for (const playlist of selectedPlaylists) { try { await deleteMutation.mutateAsync(playlist.id); successCount++; } catch (error) { errorCount++; console.error(`Failed to delete playlist ${playlist.id}:`, error); } } if (successCount > 0) { showSuccess( `${successCount} playlist${successCount > 1 ? 's' : ''} supprimée${successCount > 1 ? 's' : ''} avec succès.`, ); onSelectionClear(); onPlaylistsDeleted?.(); } if (errorCount > 0) { showError( `${errorCount} playlist${errorCount > 1 ? 's' : ''} n'a${errorCount > 1 ? 'ont' : ''} pas pu être supprimée${errorCount > 1 ? 's' : ''}.`, ); } } finally { setIsDeleting(false); setShowDeleteDialog(false); } }; const handleShare = async () => { setIsSharing(true); const shareLinks: string[] = []; try { for (const playlist of selectedPlaylists) { try { const result = await createShareLinkMutation.mutateAsync(playlist.id); // Le résultat est un PlaylistShareLink avec share_token if (result && typeof result === 'object' && 'share_token' in result) { const shareUrl = `${window.location.origin}/playlists/shared/${result.share_token}`; shareLinks.push(shareUrl); } } catch (error) { console.error( `Failed to create share link for playlist ${playlist.id}:`, error, ); } } if (shareLinks.length > 0) { // Copier les liens dans le presse-papiers const linksText = shareLinks.join('\n'); await navigator.clipboard.writeText(linksText); showSuccess( `${shareLinks.length} lien${shareLinks.length > 1 ? 's' : ''} copié${shareLinks.length > 1 ? 's' : ''} dans le presse-papiers.`, ); onSelectionClear(); } else { showError('Impossible de créer les liens de partage.'); } } finally { setIsSharing(false); } }; const handleExportJSON = () => { try { exportPlaylistsToJSON(selectedPlaylists); showSuccess( `${selectedCount} playlist${selectedCount > 1 ? 's' : ''} exportée${selectedCount > 1 ? 's' : ''} en JSON.`, ); onSelectionClear(); } catch (error) { showError("Impossible d'exporter les playlists."); } }; const handleExportCSV = () => { try { exportPlaylistsToCSV(selectedPlaylists); showSuccess( `${selectedCount} playlist${selectedCount > 1 ? 's' : ''} exportée${selectedCount > 1 ? 's' : ''} en CSV.`, ); onSelectionClear(); } catch (error) { showError("Impossible d'exporter les playlists."); } }; return (