From 3aeed514480c03d14bc1361fe82d941014db0420 Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Sat, 26 Jul 2025 00:35:49 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=84=20Enhanced=20Cards=20Page=20Authen?= =?UTF-8?q?tication=20&=20Bulk=20Actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ User Favorites Integration: - Added loadFavoritedCards() function to fetch user's favorited cards on page load - Favorites now properly display across page refreshes - Authentication headers included for favorites API calls 🔧 Bulk Actions Implementation: - Implemented handleBulkMarkAsOwned() with proper API calls - Implemented handleBulkRemoveFromOwned() with ownership removal - Added authentication checks and error handling - Success/failure feedback with clear user messaging - Auto-clear selection after successful operations 🛡️ Authentication Enhancements: - All user-specific operations now require valid JWT tokens - Graceful handling when user is not authenticated - Proper error messaging for auth failures - Individual card actions properly connected to bulk handlers 🎯 User Experience Improvements: - Real-time favorite state management - Bulk operations provide detailed success feedback - Error handling with user-friendly messages - Selection clearing after successful operations The cards page now properly integrates with the secured API system and provides full user-specific functionality! 🃏✨ --- pages/cards.js | 109 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/pages/cards.js b/pages/cards.js index a8478ea..d485bda 100644 --- a/pages/cards.js +++ b/pages/cards.js @@ -105,6 +105,28 @@ export default function Cards() { } }; + // Load user's favorited cards + const loadFavoritedCards = async () => { + try { + const token = localStorage.getItem('auth_token'); + if (!token) return; + + const response = await fetch('/api/favorites?type=card', { + headers: { + 'Authorization': `Bearer ${token}` + } + }); + + if (response.ok) { + const data = await response.json(); + const favoriteIds = new Set(data.favorites.map(fav => parseInt(fav.item_id))); + setFavoritedCards(favoriteIds); + } + } catch (error) { + console.error('Error loading favorited cards:', error); + } + }; + // Initial load useEffect(() => { setPagination(prev => ({ ...prev, page: 1 })); @@ -112,6 +134,7 @@ export default function Cards() { setHasMore(true); hasMoreRef.current = true; fetchCards(false); + loadFavoritedCards(); // Load user's favorites }, [selectedTCG, selectedRarity, selectedSet, selectedValueRange]); // Handle search with debounce @@ -369,14 +392,88 @@ export default function Cards() { alert(`Adding ${cards.length} cards to deck (functionality coming soon)`); }; - const handleBulkMarkAsOwned = (cards) => { - console.log('Marking as owned:', cards); - alert(`Marking ${cards.length} cards as owned (functionality coming soon)`); + const handleBulkMarkAsOwned = async (cards) => { + try { + const token = localStorage.getItem('auth_token'); + if (!token) { + alert('Please log in to mark cards as owned'); + return; + } + + let successCount = 0; + for (const card of cards) { + try { + const response = await fetch(`/api/cards/${card.id}/ownership`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify({ quantity: 1 }) + }); + + if (response.ok) { + successCount++; + } + } catch (error) { + console.error(`Error marking card ${card.id} as owned:`, error); + } + } + + if (successCount === cards.length) { + alert(`Successfully marked ${cards.length} cards as owned!`); + } else { + alert(`Marked ${successCount} out of ${cards.length} cards as owned. Some operations may have failed.`); + } + + // Clear selection after successful operation + setSelectedCards([]); + } catch (error) { + console.error('Error in bulk mark as owned:', error); + alert('Failed to mark cards as owned. Please try again.'); + } }; - const handleBulkRemoveFromOwned = (cards) => { - console.log('Removing from owned:', cards); - alert(`Removing ${cards.length} cards from owned (functionality coming soon)`); + const handleBulkRemoveFromOwned = async (cards) => { + try { + const token = localStorage.getItem('auth_token'); + if (!token) { + alert('Please log in to remove cards from owned'); + return; + } + + let successCount = 0; + for (const card of cards) { + try { + const response = await fetch(`/api/cards/${card.id}/ownership`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify({ quantity: 0 }) + }); + + if (response.ok) { + successCount++; + } + } catch (error) { + console.error(`Error removing card ${card.id} from owned:`, error); + } + } + + if (successCount === cards.length) { + alert(`Successfully removed ${cards.length} cards from owned!`); + } else { + alert(`Removed ${successCount} out of ${cards.length} cards from owned. Some operations may have failed.`); + } + + // Clear selection after successful operation + setSelectedCards([]); + } catch (error) { + console.error('Error in bulk remove from owned:', error); + alert('Failed to remove cards from owned. Please try again.'); + } }; const handleBulkFavorite = async (cards) => {