feat: optimize sound addition and removal in PlaylistEditPage with optimistic updates

This commit is contained in:
JSC
2025-08-11 21:26:40 +02:00
parent 25fd92e0da
commit 53e5ec74d8

View File

@@ -560,14 +560,32 @@ export function PlaylistEditPage() {
await playlistsService.addSoundToPlaylist(playlistId, soundId, position) await playlistsService.addSoundToPlaylist(playlistId, soundId, position)
toast.success('Sound added to playlist') toast.success('Sound added to playlist')
// Refresh playlist sounds // Find the sound in available sounds to get its data
await fetchSounds() const soundToAdd = availableSounds.find(s => s.id === soundId)
if (soundToAdd) {
// Optimistically update the state without refetching
const newPlaylistSound = {
...soundToAdd,
// Add any missing properties that PlaylistSound has but Sound doesn't
}
setSounds(prev => [...prev, newPlaylistSound])
// Remove the added sound from available sounds // Remove from available sounds
setAvailableSounds(prev => prev.filter(s => s.id !== soundId)) setAvailableSounds(prev => prev.filter(s => s.id !== soundId))
// Refresh playlist data to update counts // Only update the playlist counter optimistically (avoid full refetch)
await fetchPlaylist() if (playlist) {
setPlaylist(prev => prev ? {
...prev,
sound_count: (prev.sound_count || 0) + 1,
total_duration: (prev.total_duration || 0) + (soundToAdd.duration || 0)
} : null)
}
} else {
// Fallback to refresh if we can't find the sound data
await fetchSounds()
await fetchPlaylist()
}
} catch (err) { } catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Failed to add sound to playlist' const errorMessage = err instanceof Error ? err.message : 'Failed to add sound to playlist'
toast.error(errorMessage) toast.error(errorMessage)
@@ -576,33 +594,53 @@ export function PlaylistEditPage() {
const handleRemoveSound = async (soundId: number) => { const handleRemoveSound = async (soundId: number) => {
try { try {
// Find the sound being removed to check if it's EXT type // Find the sound being removed
const removedSound = sounds.find(s => s.id === soundId) const removedSound = sounds.find(s => s.id === soundId)
if (!removedSound) return
await playlistsService.removeSoundFromPlaylist(playlistId, soundId) await playlistsService.removeSoundFromPlaylist(playlistId, soundId)
// Optimistically update the sounds list (backend reorders automatically)
setSounds(prev => prev.filter(sound => sound.id !== soundId)) setSounds(prev => prev.filter(sound => sound.id !== soundId))
toast.success('Sound removed from playlist') toast.success('Sound removed from playlist')
// If it's an EXT sound and we're in add mode, add it back to available sounds // If it's an EXT sound and we're in add mode, add it back to available sounds
if (isAddMode && removedSound && removedSound.type === 'EXT') { if (isAddMode && removedSound.type === 'EXT') {
// Get the full sound data from the API to add back to available sounds // Convert PlaylistSound back to Sound format for available list
try { const soundToAddBack = {
const allExtSounds = await soundsService.getSoundsByType('EXT') id: removedSound.id,
const soundToAddBack = allExtSounds.find(s => s.id === soundId) name: removedSound.name,
if (soundToAddBack) { filename: removedSound.filename,
setAvailableSounds(prev => [...prev, soundToAddBack].sort((a, b) => a.name.localeCompare(b.name))) duration: removedSound.duration,
} size: removedSound.size,
} catch { hash: removedSound.hash,
// If we can't fetch the sound data, just refresh the available sounds type: removedSound.type,
await fetchAvailableSounds() play_count: removedSound.play_count,
is_normalized: removedSound.is_normalized,
normalized_filename: removedSound.normalized_filename,
normalized_duration: removedSound.normalized_duration,
normalized_size: removedSound.normalized_size,
normalized_hash: removedSound.normalized_hash,
created_at: removedSound.created_at,
updated_at: removedSound.updated_at
} }
setAvailableSounds(prev => [...prev, soundToAddBack].sort((a, b) => a.name.localeCompare(b.name)))
} }
// Refresh playlist data to update counts // Optimistically update playlist stats
await fetchPlaylist() if (playlist) {
setPlaylist(prev => prev ? {
...prev,
sound_count: Math.max(0, (prev.sound_count || 0) - 1),
total_duration: Math.max(0, (prev.total_duration || 0) - (removedSound.duration || 0))
} : null)
}
} catch (err) { } catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Failed to remove sound' const errorMessage = err instanceof Error ? err.message : 'Failed to remove sound'
toast.error(errorMessage) toast.error(errorMessage)
// On error, refresh to get correct state
await fetchSounds()
await fetchPlaylist()
} }
} }