diff --git a/webui/static/script.js b/webui/static/script.js index 71d9408b..925bce8b 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -4754,10 +4754,20 @@ async function openWishlistOverviewModal() { `; @@ -4773,11 +4783,118 @@ async function openWishlistOverviewModal() { } function closeWishlistOverviewModal() { + console.log('๐Ÿšช closeWishlistOverviewModal() called'); const modal = document.getElementById('wishlist-overview-modal'); + console.log('Modal element:', modal); if (modal) { modal.style.display = 'none'; + console.log('Modal display set to none'); + // Also remove from DOM to ensure clean state + modal.remove(); + console.log('Modal removed from DOM'); + } else { + console.warn('Modal element not found'); } window.selectedWishlistCategory = null; + console.log('โœ… Modal closed'); +} + +async function cleanupWishlistOverview() { + console.log('๐Ÿงน cleanupWishlistOverview() called'); + + if (!confirm('This will remove all tracks from the wishlist that already exist in your library. Continue?')) { + return; + } + + try { + showLoadingOverlay('Cleaning up wishlist...'); + + const response = await fetch('/api/wishlist/cleanup', { + method: 'POST' + }); + + const result = await response.json(); + + if (result.success) { + const removedCount = result.removed_count || 0; + + if (removedCount > 0) { + showToast(`Cleanup complete! Removed ${removedCount} tracks that already exist in your library`, 'success'); + } else { + showToast('No tracks needed to be removed', 'info'); + } + + // Check if wishlist is now empty + const statsResponse = await fetch('/api/wishlist/stats'); + const statsData = await statsResponse.json(); + + if (statsData.total === 0) { + // Wishlist is empty, just close the modal + closeWishlistOverviewModal(); + await updateWishlistCount(); + } else { + // Wishlist still has items, refresh the modal to show updated counts + closeWishlistOverviewModal(); + await openWishlistOverviewModal(); + } + } else { + showToast(`Failed to cleanup wishlist: ${result.error || 'Unknown error'}`, 'error'); + } + + hideLoadingOverlay(); + + } catch (error) { + console.error('Error cleaning up wishlist:', error); + showToast(`Failed to cleanup wishlist: ${error.message}`, 'error'); + hideLoadingOverlay(); + } +} + +async function clearEntireWishlist() { + console.log('๐Ÿ—‘๏ธ clearEntireWishlist() called'); + + if (!confirm('โš ๏ธ WARNING: This will permanently delete ALL tracks from your wishlist.\n\nThis action cannot be undone.\n\nAre you sure you want to continue?')) { + console.log('User cancelled confirmation'); + return; + } + + console.log('User confirmed, proceeding with clear...'); + + try { + showLoadingOverlay('Clearing wishlist...'); + console.log('Loading overlay shown'); + + const response = await fetch('/api/wishlist/clear', { + method: 'POST' + }); + console.log('API response received:', response.status); + + const result = await response.json(); + console.log('Clear wishlist response:', result); + + hideLoadingOverlay(); + console.log('Loading overlay hidden'); + + if (result.success) { + console.log('Clear was successful, showing toast...'); + showToast('Wishlist cleared successfully', 'success'); + + console.log('Updating wishlist button count...'); + await updateWishlistCount(); + + console.log('Closing modal...'); + closeWishlistOverviewModal(); + console.log('Modal should be closed now'); + } else { + console.error('Clear failed:', result.error); + showToast(`Failed to clear wishlist: ${result.error || 'Unknown error'}`, 'error'); + } + + } catch (error) { + console.error('Error clearing wishlist:', error); + hideLoadingOverlay(); + showToast(`Failed to clear wishlist: ${error.message}`, 'error'); + } } async function selectWishlistCategory(category) { diff --git a/webui/static/style.css b/webui/static/style.css index 0f506963..6acceb0a 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -7425,7 +7425,18 @@ body { border-top: 1px solid rgba(255, 255, 255, 0.08); display: flex; gap: 12px; - justify-content: flex-end; + justify-content: space-between; + align-items: center; +} + +.playlist-modal-footer-left { + display: flex; + gap: 12px; +} + +.playlist-modal-footer-right { + display: flex; + gap: 12px; } .playlist-modal-btn { @@ -7475,6 +7486,32 @@ body { transform: translateY(-1px); } +.playlist-modal-btn-danger { + background: linear-gradient(135deg, #dc2626, #ef4444); + color: #ffffff; + font-weight: 700; + box-shadow: 0 4px 16px rgba(220, 38, 38, 0.3); +} + +.playlist-modal-btn-danger:hover { + background: linear-gradient(135deg, #b91c1c, #dc2626); + transform: translateY(-1px); + box-shadow: 0 6px 20px rgba(220, 38, 38, 0.4); +} + +.playlist-modal-btn-warning { + background: linear-gradient(135deg, #f59e0b, #fbbf24); + color: #000000; + font-weight: 700; + box-shadow: 0 4px 16px rgba(245, 158, 11, 0.3); +} + +.playlist-modal-btn-warning:hover { + background: linear-gradient(135deg, #d97706, #f59e0b); + transform: translateY(-1px); + box-shadow: 0 6px 20px rgba(245, 158, 11, 0.4); +} + /* Watchlist Modal Styles */ .watchlist-artists-list { max-height: 400px;