deckhearth/lib/use-collections-page.js

273 lines
8 KiB
JavaScript
Raw Normal View History

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, authLoading }) {
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
};
}