Skip to content

fix(dashboard): apply sorting in the by-product view (fixes #241) - #247

Merged
mikeknight85 merged 1 commit into
mainfrom
fix/by-product-sorting
Oct 11, 2026
Merged

mikeknight85 merged 1 commit into
mainfrom
fix/by-product-sorting

Conversation

@mikeknight85

Copy link
Copy Markdown
Owner

Fixes #241. Thanks @GeilerGelber — the report was precise and the cause was exactly where it pointed.

Root cause

ItemList was called as <ItemList searchQuery={searchQuery} activeTag={activeTag} />. Its props interface had only those two fields and the component had no sort step at all — it filtered itemsQuery.data and mapped straight to <ItemCard>. So sortBy / sortOrder lived in useProductFilters, still persisted to localStorage, and still re-sorted the flat view — but nothing in the grouped view ever read them. The dropdown changed, the state changed, and there was no consumer. Hence no reorder and no error, which is why it looked like nothing happened rather than like a failure.

What each option means for an item

New itemSort.ts. Everything anchors to the store the card is already pointing at: bestPriceListing() returns the first listing whose id is in best_price_listing_ids — the green-marked store the user can see — rather than inventing a second ranking they cannot observe.

Option Item meaning
Price item.best_price — already converted to the user's currency, and already what the card prints
Price Change (%) the 7-day move on the best-price listing
Price Change ($) derived against the converted best price, so cross-currency items stay comparable
Product Name item.name
Tags item.category ?? '' — untagged is a real answer
Stock Status any_in_stock first, matching the flat view's ordering
Date Added earliest listing — attaching a store yesterday must not make a year-old item look new
Last Checked latest listing — the freshest store is what the item knows about itself
Website host of the best-price store

Raw current_price would have ranked 15 000 JPY above 140 GBP, which is why price sorts go through the converted value.

Two cross-cutting rules, both tested:

  • Unanswerable sorts last in both directions. An item with no convertible price shows "No price yet"; leading the cheapest-first list with a column of those, then leading the dearest-first list with the same column, is the silence this was reported for. Note the flat view coerces a missing price to 0, which puts unpriced listings ahead of a genuinely cheap one — that behaviour was deliberately not copied.
  • Ties break on name then id, always ascending, not reversed with the arrow. The list polls on an interval, and a grouped view that reshuffles equal rows on every poll reads as broken.

Nothing was disabled

website was the judgement call. It stays working: today every item has exactly one listing, so it is identical to the flat view's answer for essentially all real data; for a multi-store item it resolves to the store the card already highlights; and disabling it would have meant either leaving the user's saved sortBy selected-but-dead — the same silence with a greyed control — or mutating their persisted preference behind their back, which would also change the flat view.

Deliberately out of scope

The pause filter and the count badge also ignore the grouped view — the filter does nothing there, and "Showing N products" counts listings rather than items. Those are filtering and counting rather than sorting, and the filter row is where #246 is about to land, so they want their own issue.

DashboardControls.tsx is untouched, so this has zero conflict surface with #246.

Verification

Lint clean, build and typecheck clean, 60 frontend tests (33 on main plus 27 new). Playwright 20 passed on port 4401, launched from its own worktree with reuseExistingServer: false and --strictPort; temp config deleted.

Bundle ownership proved against the chunk the preview actually served, including ({searchQuery:e,activeTag:t,sortBy:n,sortOrder:r}) — ItemList receiving the sort props, which is the fix and cannot be produced by pre-change source.

The grouped view was handed only the search query and active tag, so every
option in the sort dropdown changed state that nothing in that view read.
Selecting one did nothing and said nothing.

Sorting listings and sorting items are different questions: an item has no
price, currency, schedule or check history of its own, only the stores
selling it. Each option is therefore given an item-level meaning anchored to
what the card already shows -- the best price across the item's comparable
stores, in the user's own currency. Items that cannot answer an option sort
last in both directions, and ties break on name then id so a polling list
holds still.

Closes #241
@mikeknight85
mikeknight85 merged commit c1c60aa into main Oct 11, 2026
5 checks passed
@mikeknight85
mikeknight85 deleted the fix/by-product-sorting branch October 11, 2026 15:17
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.

[BUG] Sorting has no effect in the 'By Product' view

1 participant