feat: optimize sound addition and removal in PlaylistEditPage with optimistic updates
This commit is contained in:
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user