Add collections pagination and a search field on the search page

Paginate the collections grid with a "See more" button backed by a new
getCollectionsPage cursor API, add an editable search input to the
search-results block, and bump @shopify/hydrogen to 2026.10.0-preview.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DqFkSaLYRPZ18dsMbzjiP4
This commit is contained in:
Rami Bitar
2026-08-23 11:01:48 -04:00
co-authored by Claude Opus 5
parent 9ed1cc60de
commit 3bc61066f0
9 changed files with 166 additions and 19 deletions
+39 -3
View File
@@ -3,16 +3,19 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import {
getCollections,
getCollectionsPage,
getCollectionProducts,
} from '@/services/shopify/shop';
export {
getCollections,
getCollectionsPage,
getCollectionProducts,
getCollectionProductsPage,
} from '@/services/shopify/shop';
export type {
Collection,
CollectionsPage,
CollectionWithProducts,
CollectionSortKey,
CollectionProductsPage,
@@ -36,14 +39,19 @@ interface UseCollectionProductsOptions {
export function useCollections(first = 50) {
const [collections, setCollections] = useState<Collection[]>([]);
const [loading, setLoading] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
const [error, setError] = useState<string | null>(null);
const [cursor, setCursor] = useState<string | null>(null);
const [hasNextPage, setHasNextPage] = useState(false);
const fetchCollections = useCallback(async () => {
try {
setLoading(true);
setError(null);
const data = await getCollections(first);
setCollections(data);
const page = await getCollectionsPage(first);
setCollections(page.collections);
setCursor(page.endCursor);
setHasNextPage(page.hasNextPage);
} catch (err) {
console.error('Error fetching collections:', err);
setError(err instanceof Error ? err.message : 'Failed to load collections');
@@ -56,7 +64,35 @@ export function useCollections(first = 50) {
fetchCollections();
}, [fetchCollections]);
return { collections, loading, error, refetch: fetchCollections };
const loadMore = useCallback(async () => {
if (loadingMore || !hasNextPage) return;
try {
setLoadingMore(true);
const page = await getCollectionsPage(first, cursor);
setCollections((prev) => {
const seen = new Set(prev.map((collection) => collection.id));
return [...prev, ...page.collections.filter((c) => !seen.has(c.id))];
});
setCursor(page.endCursor);
setHasNextPage(page.hasNextPage);
} catch (err) {
console.error('Failed to load more collections:', err);
} finally {
setLoadingMore(false);
}
}, [first, cursor, hasNextPage, loadingMore]);
return {
collections,
loading,
loadingMore,
error,
hasNextPage,
loadMore,
refetch: fetchCollections,
};
}
// Fetch once on demand for menus that may never open.