'use client'; import { useState, useEffect } from 'react'; import { collectionApi, tagApi } from '../../lib/api'; import { Collection, Tag } from '../../types/api'; import AppLayout from '../../components/layout/AppLayout'; import { Input } from '../../components/ui/Input'; import Button from '../../components/ui/Button'; import CollectionGrid from '../../components/collections/CollectionGrid'; import TagFilter from '../../components/stories/TagFilter'; import LoadingSpinner from '../../components/ui/LoadingSpinner'; type ViewMode = 'grid' | 'list'; export default function CollectionsPage() { const [collections, setCollections] = useState([]); const [tags, setTags] = useState([]); const [loading, setLoading] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [selectedTags, setSelectedTags] = useState([]); const [viewMode, setViewMode] = useState('grid'); const [showArchived, setShowArchived] = useState(false); const [page, setPage] = useState(0); const [pageSize, setPageSize] = useState(20); const [totalPages, setTotalPages] = useState(1); const [totalCollections, setTotalCollections] = useState(0); const [refreshTrigger, setRefreshTrigger] = useState(0); // Extract tags from current collection results with counts const extractTagsFromResults = (collections: Collection[]): Tag[] => { const tagCounts: { [key: string]: number } = {}; collections.forEach(collection => { collection.tagNames?.forEach(tagName => { if (tagCounts[tagName]) { tagCounts[tagName]++; } else { tagCounts[tagName] = 1; } }); }); return Object.entries(tagCounts).map(([tagName, count]) => ({ id: tagName, // Use tag name as ID since we don't have actual IDs from search results name: tagName, collectionCount: count })); }; // Load collections with search and filters useEffect(() => { const debounceTimer = setTimeout(() => { const loadCollections = async () => { try { setLoading(true); const result = await collectionApi.getCollections({ page: page, limit: pageSize, search: searchQuery.trim() || undefined, tags: selectedTags.length > 0 ? selectedTags : undefined, archived: showArchived, }); const currentCollections = result?.results || []; setCollections(currentCollections); setTotalPages(Math.ceil((result?.totalHits || 0) / pageSize)); setTotalCollections(result?.totalHits || 0); // Always update tags based on current search results (including initial wildcard search) const resultTags = extractTagsFromResults(currentCollections); setTags(resultTags); } catch (error) { console.error('Failed to load collections:', error); setCollections([]); } finally { setLoading(false); } }; loadCollections(); }, searchQuery ? 300 : 0); // Debounce search, but not other changes return () => clearTimeout(debounceTimer); }, [searchQuery, selectedTags, page, pageSize, showArchived, refreshTrigger]); // Reset page when search or filters change const resetPage = () => { if (page !== 0) { setPage(0); } }; const handleTagToggle = (tagName: string) => { setSelectedTags(prev => { const newTags = prev.includes(tagName) ? prev.filter(t => t !== tagName) : [...prev, tagName]; resetPage(); return newTags; }); }; const handleSearchChange = (e: React.ChangeEvent) => { setSearchQuery(e.target.value); resetPage(); }; const handlePageSizeChange = (newSize: number) => { setPageSize(newSize); resetPage(); }; const clearFilters = () => { setSearchQuery(''); setSelectedTags([]); setShowArchived(false); resetPage(); }; const handleCollectionUpdate = () => { // Trigger reload by incrementing refresh trigger setRefreshTrigger(prev => prev + 1); }; if (loading && collections.length === 0) { return (
); } return (
{/* Header */}

Collections

{totalCollections} {totalCollections === 1 ? 'collection' : 'collections'} {searchQuery || selectedTags.length > 0 || showArchived ? ` found` : ` total`}

{/* Search and Filters */}
{/* Search Bar */}
{/* View Mode Toggle */}
{/* Filters and Controls */}
{/* Page Size Selector */}
{/* Archive Toggle */} {/* Clear Filters */} {(searchQuery || selectedTags.length > 0 || showArchived) && ( )}
{/* Tag Filter */}
{/* Collections Display */} {/* Pagination */} {totalPages > 1 && (
Page { const newPage = Math.max(0, Math.min(totalPages - 1, parseInt(e.target.value) - 1)); if (!isNaN(newPage)) { setPage(newPage); } }} className="w-16 px-2 py-1 text-center rounded theme-card theme-text theme-border border focus:outline-none focus:ring-2 focus:ring-theme-accent" /> of {totalPages}
)} {/* Loading Overlay */} {loading && collections.length > 0 && (
)}
); }