import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { VOCAB, collectionDisplayName } from './collection-vocabulary.js'; /** * Card/collection page state and handlers (god-component split). */ export function useCollectionsPage({ user = null, authLoading = true } = {}) { const router = useRouter(); useEffect(() => { if (!authLoading && !user) { router.push('/login'); } }, [authLoading, user, router]); const [collections, setCollections] = useState([]); const [loading, setLoading] = useState(true); const [showCreateModal, setShowCreateModal] = useState(false); const [editingCollection, setEditingCollection] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [sortBy, setSortBy] = useState('name'); // name, value, cardCount, createdAt const [newCollection, setNewCollection] = useState({ name: '', description: '', isPublic: false, image: '', tags: [] }); const [showSuccessModal, setShowSuccessModal] = useState(false); const [createdCollection, setCreatedCollection] = useState(null); const [tagInput, setTagInput] = useState(''); // For creating new collections const [editTagInput, setEditTagInput] = useState(''); // For editing collections // Redirect to login if not authenticated useEffect(() => { if (!authLoading && !user) { router.push('/login'); } }, [authLoading, user, router]); const fetchCollections = async () => { try { const token = localStorage.getItem('auth_token'); const headers = { 'Content-Type': 'application/json', }; if (token) { headers.Authorization = `Bearer ${token}`; } const response = await fetch('/api/collections', { headers }); if (response.ok) { const data = await response.json(); // Fetch thumbnails for each collection const collectionsWithThumbnails = await Promise.all( data.map(async (collection) => { try { const identifier = collection.slug || collection.id; const thumbnailResponse = await fetch(`/api/collections/${identifier}/thumbnails`, { headers }); if (thumbnailResponse.ok) { const thumbnailData = await thumbnailResponse.json(); return { ...collection, thumbnails: thumbnailData.thumbnails }; } return { ...collection, thumbnails: [] }; } catch (error) { console.error(`Error fetching thumbnails for collection ${collection.id}:`, error); return { ...collection, thumbnails: [] }; } }) ); setCollections(collectionsWithThumbnails); } else { console.error('Failed to fetch collections'); } } catch (error) { console.error('Error fetching collections:', error); } finally { setLoading(false); } } useEffect(() => { if (user) { // eslint-disable-next-line react-hooks/set-state-in-effect -- load lists when user is available fetchCollections(); } }, [user]); ; const sortOptions = [ { value: 'name', label: 'Name (A-Z)' }, { value: 'value', label: 'Value (High to Low)' }, { value: 'cardCount', label: 'Card Count (High to Low)' }, { value: 'createdAt', label: 'Date Created (Newest)' } ]; const sortCollections = (collections, sortBy) => { return [...collections].sort((a, b) => { switch (sortBy) { case 'name': return a.name.localeCompare(b.name); case 'value': return b.value - a.value; case 'cardCount': return b.cardCount - a.cardCount; case 'createdAt': return new Date(b.createdAt) - new Date(a.createdAt); default: return 0; } }); }; const filteredCollections = collections.filter(collection => { const matchesSearch = collection.name.toLowerCase().includes(searchQuery.toLowerCase()) || collection.description.toLowerCase().includes(searchQuery.toLowerCase()); return matchesSearch; }); const sortedCollections = sortCollections(filteredCollections, sortBy); const handleCreateCollection = async () => { try { const response = await fetch('/api/collections', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newCollection.name, description: newCollection.description, isPublic: newCollection.isPublic, image: newCollection.image, tags: newCollection.tags }) }); if (response.ok) { const createdCollection = await response.json(); setCreatedCollection(createdCollection); setShowCreateModal(false); setShowSuccessModal(true); // Reset form setNewCollection({ name: '', description: '', isPublic: false, image: '', tags: [] }); setTagInput(''); // Clear tag input // Refresh collections list fetchCollections(); } else { const error = await response.json(); alert(error.error || 'Failed to create list'); } } catch (error) { console.error('Error creating collection:', error); alert('Network error. Please try again.'); } }; const handleUpdateCollection = async () => { try { const response = await fetch(`/api/collections/${editingCollection.slug || editingCollection.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: editingCollection.name, description: editingCollection.description, isPublic: editingCollection.isPublic, image: editingCollection.image, tags: editingCollection.tags }) }); if (response.ok) { // Refresh collections after update fetchCollections(); setEditingCollection(null); setEditTagInput(''); // Clear the tag input } else { const error = await response.json(); alert(error.error || 'Failed to update list'); } } catch (error) { console.error('Error updating collection:', error); alert('Network error. Please try again.'); } }; const handleDeleteCollection = async (collectionId) => { if (confirm('Are you sure you want to delete this list? This action cannot be undone.')) { try { const response = await fetch(`/api/collections/${collectionId}`, { method: 'DELETE' }); if (response.ok) { fetchCollections(); // Refresh the list } else { const error = await response.json(); alert(error.error || 'Failed to delete list'); } } catch (error) { console.error('Error deleting collection:', error); alert('Network error. Please try again.'); } } }; const formatCurrency = (amount) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount); }; const formatDate = (dateString) => { return new Date(dateString).toLocaleDateString(); }; const showInitialLoading = authLoading || loading; return { collections, createdCollection, editTagInput, editingCollection, filteredCollections, formatCurrency, formatDate, handleCreateCollection, handleDeleteCollection, handleUpdateCollection, loading, newCollection, router, searchQuery, setCollections, setCreatedCollection, setEditTagInput, setEditingCollection, setLoading, setNewCollection, setSearchQuery, setShowCreateModal, setShowSuccessModal, setSortBy, setTagInput, showCreateModal, showInitialLoading, showSuccessModal, sortBy, sortCollections, sortOptions, sortedCollections, tagInput }; }