Skip to content

feat(shop): collections, search, policies, PDP gallery, qty, cart drawer, discounts#833

Merged
tannerlinsley merged 1 commit intomainfrom
feat/shop-phase-2
Apr 15, 2026
Merged

feat(shop): collections, search, policies, PDP gallery, qty, cart drawer, discounts#833
tannerlinsley merged 1 commit intomainfrom
feat/shop-phase-2

Conversation

@tannerlinsley
Copy link
Copy Markdown
Member

@tannerlinsley tannerlinsley commented Apr 15, 2026

Summary

Brings the shop to Shopify-theme parity. Everything on the "standard storefront" checklist that was missing after the initial ship is now in.

New routes

  • /shop/collections/$handle — collection listings with sort + Load More pagination, SEO meta, breadcrumbs
  • /shop/pages/$handle — renders Shopify-admin-managed pages (policies, about, etc.)
  • /shop/search — Storefront API search with paginated results

Listings

  • Sort dropdown on /shop and each collection (URL-driven; default sort uses a clean URL)
  • Load More cursor pagination — SSR'd first page, client-accumulated pages after
  • Responsive images via a shared ProductImage primitive (srcset 1x/1.5x/2x/3x via Shopify CDN transforms, correct sizes hint, lazy past the fold)

PDP

  • Image gallery with thumbnails + active state; selected variant auto-focuses its own image
  • Quantity stepper wired to Add to cart
  • Variant availability awareness — unavailable option combos show a line-through + dim treatment
  • JSON-LD Product / AggregateOffer schema for rich search results
  • Per-product OG image via Shopify CDN (1200×630 jpg, center crop)
  • Breadcrumbs

Cart

  • Discount code apply/remove with invalid-code detection (Shopify silently drops unknown codes, so the server fn re-checks applicable and surfaces a user-facing error)
  • Slide-in cart drawer (Radix Dialog) controlled by a zustand store. "Add to cart" on the PDP opens the drawer instead of redirecting, so the user can keep browsing
  • Navbar cart button now opens the drawer instead of navigating — visibility rules unchanged (always on /shop/*, site-wide when cart has items)
  • Cart page gains breadcrumbs + discount UI

Sidebar

  • Search link, Info section with Shipping / Returns / Privacy / Terms
  • Shopify Collections still rendered live from the parent /shop loader

New shared components under src/components/shop/

  • ProductCard (handles "from $X" ranges + compare-at strike-through)
  • ProductImage (srcset, no hydrogen-react Provider needed)
  • Breadcrumbs
  • CartDrawer
  • cartDrawerStore (zustand)

Queries

  • Shared ProductCard GraphQL fragment for products/collection/search
  • New: COLLECTION_QUERY, PAGE_QUERY, SEARCH_QUERY, CART_DISCOUNT_CODES_UPDATE_MUTATION
  • Cart fragment now includes discountCodes
  • Products query gained cursor + sort args

Env / infra

  • No new env vars.
  • Policy pages will render whatever the Shopify admin has configured under Online Store > Pages. Create pages with handles shipping-policy, refund-policy, privacy-policy, terms-of-service to populate the sidebar Info links — missing pages fall through to the existing 404.

Test plan

  • /shop?sort=PRICE orders products ascending by price; default URL stays clean
  • "Load more" appends a new page without resetting the first page or page scroll
  • /shop/collections/<handle> renders with the collection's products and sort works
  • PDP: click a thumbnail and the hero swaps; select a different variant with its own image and the gallery follows
  • PDP: select an unavailable variant combination — the offending option value gets a strike-through style, Add to cart flips to Sold out
  • PDP: adjust quantity, click Add to cart — drawer slides in, badge updates, subtotal reflects the quantity
  • /shop/search?q=... returns results; empty query shows the prompt, no matches shows the "No products match" state
  • Apply an invalid discount code — inline error message appears (no silent acceptance)
  • Apply a valid discount — code chip shows with an X to remove
  • Drawer works on every /shop/* route from the navbar cart button, and from non-shop routes when the cart has items
  • View page source on a PDP → <script type="application/ld+json"> present with valid schema.org Product
  • Social-share preview on a PDP uses the product's first image (via Shopify CDN transform)
  • Shop policies pages (/shop/pages/shipping-policy etc.) 404 gracefully until pages are created in Shopify admin

Summary by CodeRabbit

  • New Features
    • Added product search functionality to discover items quickly.
    • Introduced collections browsing with sorting and pagination support.
    • Enabled discount code application and removal in cart.
    • Implemented cart drawer for quick access without page navigation.
    • Enhanced product pages with image galleries, variant selectors, and quantity controls.
    • Added breadcrumb navigation for better orientation.
    • Added policy and info pages accessible from navigation.

…t drawer, discount codes

Brings the shop up to parity with a standard Shopify storefront:

**New routes**
- /shop/collections/$handle: collection listings with sort + cursor
  pagination, SSR, SEO meta, breadcrumbs
- /shop/pages/$handle: renders Shopify admin-managed pages (shipping,
  returns, privacy, terms, about, etc.). Sidebar now links to the four
  standard policies out of the box.
- /shop/search: Storefront API search with cursor pagination, URL-driven
  query param, accessible search form

**Listing enhancements**
- Sort dropdown on /shop and /shop/collections/* wired to URL search
  params (SSR-correct, shareable, back/forward friendly)
- Load More cursor-based pagination on all listings (first page always
  comes from the loader; subsequent pages accumulate client-side)
- Responsive images via a shared ProductImage primitive: srcset with
  1x / 1.5x / 2x / 3x widths bounded by the image's intrinsic width,
  correct sizes hint, lazy-loaded past the fold, eager for the first
  row

**PDP**
- Image gallery with thumbnails; click swaps the active image, selected
  variant auto-focuses its own image
- Quantity stepper integrated into Add to cart
- Variant availability awareness: option buttons for combinations that
  don't resolve to an available variant get a line-through + dimmed
  treatment (clicks still allowed to surface the sold-out state)
- JSON-LD schema.org Product block for rich search results (single
  offer or AggregateOffer based on variant count)
- Per-product OG image via Shopify CDN transforms (1200x630 jpg, center
  crop) so social shares get the product photo, not the generic card
- Breadcrumbs: Shop > <product>

**Cart**
- Discount code form in the summary panel (applyDiscountCode /
  removeDiscountCode server fns with valibot validation + invalid-code
  detection, since Shopify silently drops unknown codes)
- Slide-in cart drawer (Radix Dialog) controlled by a zustand store so
  any component can trigger it. Add to cart on the PDP now opens the
  drawer on success for instant feedback without losing the PDP scroll
- Navbar cart button switched from Link to drawer trigger; visibility
  rules unchanged (always on /shop/*, site-wide when cart has items)
- Cart page gains breadcrumbs + discount code UI

**Shared components**
- src/components/shop/ProductCard (with compare-at-price strike-through
  and "from $X" when variants span a price range)
- src/components/shop/ProductImage (responsive srcset via Shopify CDN
  transforms, pure HTML — no hydrogen-react Provider needed)
- src/components/shop/Breadcrumbs (accessible nav with aria-current)
- src/components/shop/CartDrawer
- src/components/shop/cartDrawerStore (zustand)

**Queries**
- Shared ProductCard GraphQL fragment reused across products list,
  collection products, and search results
- New: COLLECTION_QUERY, PAGE_QUERY, SEARCH_QUERY,
  CART_DISCOUNT_CODES_UPDATE_MUTATION
- Cart fragment now includes discountCodes
- Products query now takes cursor + sort args

**Sidebar**
- Adds Search link, Info section (Shipping/Returns/Privacy/Terms)
- Sidebar renders Shopify Collections live via the parent /shop loader

Nothing here requires new env vars. Policy pages render whatever
Shopify's admin has configured under Online Store > Pages with
matching handles; a missing page falls through to the existing 404.
@netlify
Copy link
Copy Markdown

netlify bot commented Apr 15, 2026

Deploy Preview for tanstack ready!

Name Link
🔨 Latest commit 9642888
🔍 Latest deploy log https://app.netlify.com/projects/tanstack/deploys/69e001633230cf00081331eb
😎 Deploy Preview https://deploy-preview-833--tanstack.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 31 (🔴 down 29 from production)
Accessibility: 90 (no change from production)
Best Practices: 83 (🔴 down 9 from production)
SEO: 97 (no change from production)
PWA: 70 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 15, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR implements a comprehensive shopping experience overhaul, introducing search and collection browsing routes, a global cart drawer with discount code management, new product display components, API pagination and sorting support, and enhanced product detail pages with image galleries and variant selectors.

Changes

Cohort / File(s) Summary
Cart Drawer System
src/components/shop/cartDrawerStore.ts, src/components/shop/CartDrawer.tsx, src/components/NavbarCartButton.tsx
New Zustand store manages drawer visibility; CartDrawer component renders Radix UI slide-in with line items, quantity controls, and checkout actions; NavbarCartButton now triggers drawer open instead of navigating to cart route.
Product Display Components
src/components/shop/Breadcrumbs.tsx, src/components/shop/ProductCard.tsx, src/components/shop/ProductImage.tsx
New components for breadcrumb navigation, product tile cards with price ranges and discounts, and responsive Shopify image rendering with DPR-aware srcsets and WebP optimization.
Shop Layout & Navigation
src/components/shop/ShopLayout.tsx, src/routeTree.gen.ts
ShopLayout mounts global CartDrawer and adds sidebar search link plus policy page navigation; routeTree registers new routes for search, collections, and pages.
Product Listing Routes
src/routes/shop.index.tsx, src/routes/shop.search.tsx, src/routes/shop.collections.$handle.tsx
Refactored homepage with dynamic sort parameters and stateful pagination; added search route with query validation and load-more; added collection route with sort options and incremental product loading.
Shop Pages & Product Detail
src/routes/shop.pages.$handle.tsx, src/routes/shop.products.$handle.tsx
New pages route loads and renders static shop pages; product detail significantly refactored with new ProductGallery, VariantSelector, and QuantityStepper subcomponents, plus JSON-LD schema and OG image metadata.
Cart Discount & Cart Page
src/routes/shop.cart.tsx, src/hooks/useCart.ts
Cart page now displays Breadcrumbs and includes new DiscountCodeSection for applying/removing codes; added useApplyDiscountCode and useRemoveDiscountCode hooks with optimistic updates and error handling.
API & GraphQL Layer
src/utils/shop.functions.ts, src/utils/shopify-queries.ts
Refactored getProducts for pagination/sorting; added new endpoints (getCollection, getPage, searchProducts, discount mutations); extended GraphQL queries with pagination, sort options, discount codes, and new search/collection/page queries with sorting utilities and type definitions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes


🐰 Breadcrumbs laid, carts drawer-bound,
Product galleries spin all around,
Discounts applied with a hop and a click,
Search and variants—oh, so slick!
This shop's transformation—a rabbit's delight,
Ecommerce magic, polished just right!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title comprehensively and accurately summarizes all major changes in the PR: collections, search, policies, PDP gallery, quantity controls, cart drawer, and discounts.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/shop-phase-2

Comment @coderabbitai help to get the list of available commands and usage tips.

@tannerlinsley tannerlinsley merged commit d20c738 into main Apr 15, 2026
7 of 8 checks passed
@tannerlinsley tannerlinsley deleted the feat/shop-phase-2 branch April 15, 2026 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant