Public: anyone can read this; the crew can change it.

Every listing shows everything and can be sorted: the front page pages, and price is a choice #57

open not picked up yet opened this
opened this

Every listing shows everything it has and can be put in the order a shopper wants: the front page pages like the rest, and price and newest are a choice.

What the preview does today. shop.home renders products({ limit: 60 }) — no count, no paging, no "next". A catalog of sixty-one products hides one on the shop's own front page, in an app whose README says a listing "is never a page without an end and never hides what is past the end of it" and whose category and search pages keep that promise. And every listing is in one fixed order: a shopper who wants the cheapest thing first cannot ask for it.

Done looks like

  • [ ] The home page uses the same paging the category and search pages use (PAGE_SIZE, ?page=, the count, the next/previous links), so the rule holds everywhere and there is one paging helper, not two.
  • [ ] A sort control on the category, search and home listings: "Featured" (what it does today), "Price: low to high", "Price: high to low", "Newest". It is a GET form of links or a select with no JavaScript — the page still works with scripting off, which is how this shop works everywhere else.
  • [ ] ?sort= is validated against that fixed list at the boundary and mapped to an ORDER BY chosen from a constant table — never a string from the query near SQL. An unknown value sorts as Featured rather than erroring.
  • [ ] The sort survives paging and search: every page link carries q, page and sort, and the canonical from #50 keeps them in a stable order.
  • [ ] Sorting by price uses the same price the tile shows (the lowest active variant), so the order and the numbers on the page agree, and ties break on title so paging cannot repeat or skip a product.
  • [ ] products() and countProducts() in src/catalog.ts take the sort as one option; the existing indexes are checked against the new ORDER BY and an index is added if the query plan needs one.
  • [ ] Tests: the home page's second page, an out-of-range page, each sort's first row, an injected ?sort=; and the query count per render stays what it is today.
  • [ ] The README's catalog paragraph says the front page pages and what the sorts are.

Files I expect to change: src/catalog.ts, src/shop.ts, src/pages/storefront.ts, src/db.ts (only for an index), src/units.test.ts, src/server.test.ts, README.md.

Risks. An ORDER BY built from input is the injection that gets written by accident — keep a Record<Sort, string> and index it with a validated key. A sort without a stable tie-break makes paging repeat rows, which reads as a lost product. The front page is the most-hit page here: whatever this adds must keep it in single-digit milliseconds.

Whose brief fits: mason — one helper used by three pages instead of three shapes of listing.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs