|
1 | | -import { useState } from 'react'; |
| 1 | +import { useState, useCallback } from 'react'; |
2 | 2 | import type { CardImage } from '../lib/types'; |
3 | 3 | import { API_ENDPOINT } from '../lib/constants'; |
4 | 4 |
|
| 5 | +const PAGE_SIZE_INITIAL = 30; |
| 6 | +const PAGE_SIZE_MORE = 20; |
| 7 | + |
5 | 8 | export const useCardSearch = () => { |
6 | 9 | const [images, setImages] = useState<CardImage[]>([]); |
7 | 10 | const [loading, setLoading] = useState(false); |
| 11 | + const [loadingMore, setLoadingMore] = useState(false); |
| 12 | + const [page, setPage] = useState(1); |
| 13 | + const [hasMore, setHasMore] = useState(false); |
| 14 | + const [currentQuery, setCurrentQuery] = useState({}); |
8 | 15 |
|
9 | | - const handleSearch = async ( |
10 | | - query: string, |
11 | | - isCameo: boolean, |
12 | | - isTrainer: boolean, |
13 | | - isIllustrator: boolean, |
14 | | - sortOrder: 'asc' | 'desc', |
15 | | - isSet: boolean |
16 | | - ) => { |
17 | | - if (!query.trim()) return; |
18 | | - setLoading(true); |
19 | | - setImages([]); |
20 | | - const processedQuery = query.split(',').map(part => part.trim().toLowerCase().replace(/\s+/g, '-')).join(','); |
21 | | - const params = new URLSearchParams({ q: processedQuery }); |
22 | | - if (isCameo) params.append('cameo', '1'); |
23 | | - if (isTrainer) params.append('trainer', '1'); |
24 | | - if (isIllustrator) params.append('illustrator', '1'); |
25 | | - if (sortOrder === 'desc') params.append('descending', '1'); |
26 | | - if (isSet) params.append('set', '1'); |
| 16 | + const fetchImages = useCallback(async (searchParams: any, isNewSearch: boolean) => { |
| 17 | + if (isNewSearch) { |
| 18 | + setLoading(true); |
| 19 | + setImages([]); |
| 20 | + } else { |
| 21 | + setLoadingMore(true); |
| 22 | + } |
| 23 | + |
| 24 | + const params = new URLSearchParams(searchParams); |
27 | 25 | try { |
28 | 26 | const response = await fetch(`${API_ENDPOINT}?${params.toString()}`); |
29 | 27 | if (!response.ok) throw new Error(`Network response was not ok: ${response.statusText}`); |
30 | 28 | const data = await response.json(); |
31 | | - setImages(data.image_rows || []); |
| 29 | + const newImages = data.image_rows || []; |
| 30 | + |
| 31 | + setImages(prev => isNewSearch ? newImages : [...prev, ...newImages]); |
| 32 | + setHasMore(newImages.length === (isNewSearch ? PAGE_SIZE_INITIAL : PAGE_SIZE_MORE)); |
32 | 33 | } catch (error) { |
33 | 34 | console.error("Error fetching images:", error); |
34 | 35 | alert("Failed to fetch images. Check console for details."); |
35 | 36 | } finally { |
36 | 37 | setLoading(false); |
| 38 | + setLoadingMore(false); |
37 | 39 | } |
38 | | - }; |
| 40 | + }, []); |
| 41 | + |
| 42 | + const handleSearch = useCallback((query: string, isCameo: boolean, isTrainer: boolean, isIllustrator: boolean, sortOrder: 'asc' | 'desc', isSet: boolean) => { |
| 43 | + if (!query.trim()) return; |
| 44 | + |
| 45 | + const newQuery = { |
| 46 | + q: query.split(',').map(part => part.trim().toLowerCase().replace(/\s+/g, '-')).join(','), |
| 47 | + limit: PAGE_SIZE_INITIAL, |
| 48 | + offset: 0, |
| 49 | + ...(isCameo && { cameo: '1' }), |
| 50 | + ...(isTrainer && { trainer: '1' }), |
| 51 | + ...(isIllustrator && { illustrator: '1' }), |
| 52 | + ...(sortOrder === 'desc' && { descending: '1' }), |
| 53 | + ...(isSet && { set: '1' }), |
| 54 | + }; |
| 55 | + |
| 56 | + setCurrentQuery(newQuery); |
| 57 | + setPage(1); |
| 58 | + fetchImages(newQuery, true); |
| 59 | + }, [fetchImages]); |
| 60 | + |
| 61 | + const loadMore = useCallback(() => { |
| 62 | + if (loadingMore || !hasMore) return; |
| 63 | + |
| 64 | + const nextPage = page + 1; |
| 65 | + const newOffset = (page * PAGE_SIZE_MORE) + (PAGE_SIZE_INITIAL - PAGE_SIZE_MORE); |
| 66 | + |
| 67 | + const newQuery = { |
| 68 | + ...currentQuery, |
| 69 | + limit: PAGE_SIZE_MORE, |
| 70 | + offset: newOffset, |
| 71 | + }; |
| 72 | + |
| 73 | + setPage(nextPage); |
| 74 | + fetchImages(newQuery, false); |
| 75 | + }, [loadingMore, hasMore, page, currentQuery, fetchImages]); |
39 | 76 |
|
40 | | - return { images, setImages, loading, handleSearch }; |
| 77 | + return { images, setImages, loading, loadingMore, hasMore, handleSearch, loadMore }; |
41 | 78 | }; |
0 commit comments