// listpage.jsx — 商品一覧ページ const { useState: useStateL, useMemo: useMemoL } = React; function ListPage({ initialFilters, onOpen, query }) { const [filters, setFilters] = useStateL(initialFilters || { variety: [], origin: [], shape: [], hardness: [], maker: [], tag: [], price: null, minRating: null, }); const [sort, setSort] = useStateL("rank"); const [view, setView] = useStateL("list"); const [drawer, setDrawer] = useStateL(false); const PRICE_TEST = { a: (p) => p.price < 1000, b: (p) => p.price >= 1000 && p.price < 1500, c: (p) => p.price >= 1500 && p.price < 2000, d: (p) => p.price >= 2000, }; // 絞り込み適用 const filtered = useMemoL(() => { return PRODUCTS.filter((p) => { if (filters.variety.length && !filters.variety.includes(p.variety)) return false; if ((filters.origin || []).length && !filters.origin.includes(p.origin)) return false; if (filters.shape.length && !filters.shape.includes(p.shape)) return false; if (filters.hardness.length && !filters.hardness.includes(p.hardness)) return false; if (filters.maker.length && !filters.maker.includes(p.maker)) return false; if (filters.tag.length && !filters.tag.every((t) => p.tags.includes(t))) return false; if (filters.price && !PRICE_TEST[filters.price](p)) return false; if (filters.minRating && p.rating < filters.minRating) return false; if (query) { const q = query.toLowerCase(); const hay = `${p.name}${makerName(p.maker)}${varietyName(p.variety)}${shapeName(p.shape)}${p.tags.join("")}`.toLowerCase(); if (!hay.includes(q)) return false; } return true; }); }, [filters, query]); // 並べ替え const sorted = useMemoL(() => { const a = [...filtered]; if (sort === "rank") a.sort((x, y) => x.rank - y.rank); if (sort === "rating") a.sort((x, y) => y.rating - x.rating); if (sort === "priceLow") a.sort((x, y) => x.price - y.price); if (sort === "priceHigh") a.sort((x, y) => y.price - x.price); if (sort === "cost") a.sort((x, y) => x.pricePer100 - y.pricePer100); return a; }, [filtered, sort]); // 各ファセットの件数(現在の絞り込みを尊重しつつ概算) const counts = useMemoL(() => { const c = { variety: {}, origin: {}, shape: {}, hardness: {}, maker: {} }; PRODUCTS.forEach((p) => { c.variety[p.variety] = (c.variety[p.variety] || 0) + 1; c.origin[p.origin] = (c.origin[p.origin] || 0) + 1; c.shape[p.shape] = (c.shape[p.shape] || 0) + 1; c.hardness[p.hardness] = (c.hardness[p.hardness] || 0) + 1; c.maker[p.maker] = (c.maker[p.maker] || 0) + 1; }); return c; }, []); const SORTS = [ { id: "rank", label: "人気順" }, { id: "rating", label: "評価順" }, { id: "priceLow", label: "価格が安い" }, { id: "cost", label: "コスパ" }, ]; const activeCount = filters.variety.length + (filters.origin || []).length + filters.shape.length + filters.hardness.length + filters.maker.length + filters.tag.length + (filters.price ? 1 : 0) + (filters.minRating ? 1 : 0); return (
ホーム / 商品一覧

干し芋 商品一覧 {query &&  「{query}」の検索結果}

{/* モバイル用 絞り込みバー */}
{SORTS.slice(0, 2).map((s) => ( ))}
{/* サイドの絞り込み */} {drawer &&
setDrawer(false)} />} {/* 一覧本体 */}
{sorted.length} 件の商品
{SORTS.map((s) => ( ))}
{sorted.length === 0 ? (
🍠
条件に合う商品が見つかりませんでした
絞り込み条件をゆるめてお試しください。
) : view === "list" ? (
{sorted.map((p) => )}
) : (
{sorted.map((p) => )}
)}
); } Object.assign(window, { ListPage });