feat: add delete functionality for playlists with confirmation and error handling
Some checks failed
Frontend CI / lint (push) Failing after 18s
Frontend CI / build (push) Has been skipped

This commit is contained in:
JSC
2025-09-21 18:32:33 +02:00
parent d551223566
commit dc1124dff6
3 changed files with 68 additions and 6 deletions

View File

@@ -5,16 +5,17 @@ import type { Playlist } from '@/lib/api/services/playlists'
import { formatDateDistanceToNow } from '@/utils/format-date' import { formatDateDistanceToNow } from '@/utils/format-date'
import { formatDuration } from '@/utils/format-duration' import { formatDuration } from '@/utils/format-duration'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { Calendar, Clock, Edit, Heart, Music, Play, User } from 'lucide-react' import { Calendar, Clock, Edit, Heart, Music, Play, Trash2, User } from 'lucide-react'
interface PlaylistRowProps { interface PlaylistRowProps {
playlist: Playlist playlist: Playlist
onEdit: (playlist: Playlist) => void onEdit: (playlist: Playlist) => void
onSetCurrent: (playlist: Playlist) => void onSetCurrent: (playlist: Playlist) => void
onFavoriteToggle?: (playlistId: number, isFavorited: boolean) => void onFavoriteToggle?: (playlistId: number, isFavorited: boolean) => void
onDelete?: (playlist: Playlist) => void
} }
export function PlaylistRow({ playlist, onEdit, onSetCurrent, onFavoriteToggle }: PlaylistRowProps) { export function PlaylistRow({ playlist, onEdit, onSetCurrent, onFavoriteToggle, onDelete }: PlaylistRowProps) {
const handleFavoriteToggle = () => { const handleFavoriteToggle = () => {
if (onFavoriteToggle) { if (onFavoriteToggle) {
onFavoriteToggle(playlist.id, !playlist.is_favorited) onFavoriteToggle(playlist.id, !playlist.is_favorited)
@@ -121,6 +122,17 @@ export function PlaylistRow({ playlist, onEdit, onSetCurrent, onFavoriteToggle }
<Play className="h-4 w-4" /> <Play className="h-4 w-4" />
</Button> </Button>
)} )}
{onDelete && !playlist.is_main && playlist.is_deletable && (
<Button
size="sm"
variant="ghost"
onClick={() => onDelete(playlist)}
className="h-8 w-8 p-0 text-destructive hover:text-destructive"
title={`Delete "${playlist.name}"`}
>
<Trash2 className="h-4 w-4" />
</Button>
)}
</div> </div>
</TableCell> </TableCell>
</TableRow> </TableRow>

View File

@@ -13,9 +13,10 @@ interface PlaylistTableProps {
onEdit: (playlist: Playlist) => void onEdit: (playlist: Playlist) => void
onSetCurrent: (playlist: Playlist) => void onSetCurrent: (playlist: Playlist) => void
onFavoriteToggle?: (playlistId: number, isFavorited: boolean) => void onFavoriteToggle?: (playlistId: number, isFavorited: boolean) => void
onDelete?: (playlist: Playlist) => void
} }
export function PlaylistTable({ playlists, onEdit, onSetCurrent, onFavoriteToggle }: PlaylistTableProps) { export function PlaylistTable({ playlists, onEdit, onSetCurrent, onFavoriteToggle, onDelete }: PlaylistTableProps) {
return ( return (
<div className="rounded-md border"> <div className="rounded-md border">
<Table> <Table>
@@ -39,6 +40,7 @@ export function PlaylistTable({ playlists, onEdit, onSetCurrent, onFavoriteToggl
onEdit={onEdit} onEdit={onEdit}
onSetCurrent={onSetCurrent} onSetCurrent={onSetCurrent}
onFavoriteToggle={onFavoriteToggle} onFavoriteToggle={onFavoriteToggle}
onDelete={onDelete}
/> />
))} ))}
</TableBody> </TableBody>

View File

@@ -189,6 +189,53 @@ export function PlaylistsPage() {
} }
} }
const handleDeletePlaylist = async (playlist: Playlist) => {
// Protect main playlist from deletion
if (playlist.is_main) {
toast.error('The main playlist cannot be deleted')
return
}
// Check if playlist is deletable
if (!playlist.is_deletable) {
toast.error('This playlist cannot be deleted')
return
}
// Confirm deletion
const confirmMessage = `Are you sure you want to delete the playlist "${playlist.name}"?${
playlist.sound_count > 0
? `\n\nThis playlist contains ${playlist.sound_count} sound${playlist.sound_count !== 1 ? 's' : ''}. The sounds will not be deleted, only removed from this playlist.`
: ''
}\n\nThis action cannot be undone.`
if (!confirm(confirmMessage)) {
return
}
try {
await playlistsService.deletePlaylist(playlist.id)
toast.success(`Playlist "${playlist.name}" deleted successfully`)
// Remove the deleted playlist from the local state
setPlaylists(prevPlaylists =>
prevPlaylists.filter(p => p.id !== playlist.id)
)
// Update total count
setTotalCount(prev => prev - 1)
// If current page is now empty and not the first page, go to previous page
const remainingOnCurrentPage = playlists.length - 1
if (remainingOnCurrentPage === 0 && currentPage > 1) {
setCurrentPage(currentPage - 1)
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Failed to delete playlist'
toast.error(errorMessage)
}
}
const renderContent = () => { const renderContent = () => {
if (loading) { if (loading) {
return <PlaylistsLoading /> return <PlaylistsLoading />
@@ -209,6 +256,7 @@ export function PlaylistsPage() {
onEdit={handleEditPlaylist} onEdit={handleEditPlaylist}
onSetCurrent={handleSetCurrent} onSetCurrent={handleSetCurrent}
onFavoriteToggle={handleFavoriteToggle} onFavoriteToggle={handleFavoriteToggle}
onDelete={handleDeletePlaylist}
/> />
<AppPagination <AppPagination
currentPage={currentPage} currentPage={currentPage}