feat: instant UI update after manual track mapping

- Backend now returns mapped track details after saving
- Frontend updates track in-place without requiring page refresh
- Track status changes from External to Local immediately
- Map button is removed after successful mapping
- Playlist counts refresh in background
- Improved UX: no more 'refresh the playlist' message

All 225 tests pass.
This commit is contained in:
2026-02-04 17:44:57 -05:00
parent 7bb7c6a40e
commit 506f39d606
2 changed files with 69 additions and 4 deletions

View File

@@ -1760,7 +1760,7 @@
}
return `
<div class="track-item">
<div class="track-item" data-position="${t.position}">
<span class="track-position">${t.position + 1}</span>
<div class="track-info">
<h4>${escapeHtml(t.title)}${statusBadge}${mapButton}</h4>
@@ -2021,6 +2021,7 @@
const playlistName = document.getElementById('map-playlist-name').value;
const spotifyId = document.getElementById('map-spotify-id').value;
const jellyfinId = document.getElementById('map-selected-jellyfin-id').value;
const position = parseInt(document.getElementById('map-position').textContent) - 1; // Convert back to 0-indexed
if (!jellyfinId) {
showToast('Please select a track', 'error');
@@ -2037,10 +2038,43 @@
const data = await res.json();
if (res.ok) {
showToast('Track mapped successfully! Refresh the playlist to see changes.', 'success');
showToast('Track mapped successfully', 'success');
closeModal('manual-map-modal');
// Refresh the tracks view
viewTracks(playlistName);
// Update the track in the UI without refreshing
if (data.track) {
const trackItem = document.querySelector(`.track-item[data-position="${position}"]`);
if (trackItem) {
// Update the track info
const titleEl = trackItem.querySelector('.track-info h4');
const artistEl = trackItem.querySelector('.track-info .artists');
const statusBadge = trackItem.querySelector('.status-badge');
const mapButton = trackItem.querySelector('.map-track-btn');
const searchLink = trackItem.querySelector('.track-meta a');
if (titleEl) {
// Remove the old status badge and map button, add new content
const titleText = data.track.title;
const newStatusBadge = '<span class="status-badge success" style="font-size:0.75rem;padding:2px 8px;margin-left:8px;"><span class="status-dot"></span>Local</span>';
titleEl.innerHTML = escapeHtml(titleText) + newStatusBadge;
}
if (artistEl) artistEl.textContent = data.track.artist;
// Remove the search link since it's now local
if (searchLink) {
const metaEl = trackItem.querySelector('.track-meta');
if (metaEl) {
// Keep album and ISRC, remove search link
const albumText = data.track.album ? escapeHtml(data.track.album) : '';
metaEl.innerHTML = albumText;
}
}
}
}
// Also refresh the playlist counts in the background
fetchPlaylists();
} else {
showToast(data.error || 'Failed to save mapping', 'error');
}