🔄 Enhanced Cards Page Authentication & Bulk Actions

 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! 🃏
This commit is contained in:
Randall Stillwell 2025-07-26 00:35:49 -05:00
parent f36fea8e58
commit 3aeed51448

View file

@ -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 // Initial load
useEffect(() => { useEffect(() => {
setPagination(prev => ({ ...prev, page: 1 })); setPagination(prev => ({ ...prev, page: 1 }));
@ -112,6 +134,7 @@ export default function Cards() {
setHasMore(true); setHasMore(true);
hasMoreRef.current = true; hasMoreRef.current = true;
fetchCards(false); fetchCards(false);
loadFavoritedCards(); // Load user's favorites
}, [selectedTCG, selectedRarity, selectedSet, selectedValueRange]); }, [selectedTCG, selectedRarity, selectedSet, selectedValueRange]);
// Handle search with debounce // Handle search with debounce
@ -369,14 +392,88 @@ export default function Cards() {
alert(`Adding ${cards.length} cards to deck (functionality coming soon)`); alert(`Adding ${cards.length} cards to deck (functionality coming soon)`);
}; };
const handleBulkMarkAsOwned = (cards) => { const handleBulkMarkAsOwned = async (cards) => {
console.log('Marking as owned:', cards); try {
alert(`Marking ${cards.length} cards as owned (functionality coming soon)`); 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) => { const handleBulkRemoveFromOwned = async (cards) => {
console.log('Removing from owned:', cards); try {
alert(`Removing ${cards.length} cards from owned (functionality coming soon)`); 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) => { const handleBulkFavorite = async (cards) => {