← back to Homesonspec
HomesOnSpec search: make Table columns bidirectionally sortable (TK-10526)
d5513153a2288efac566a66ff44e2e1690014aa9 · 2026-08-13 08:41:34 -0700 · Steve Abrams
Stories & Garage column headers set both asc and desc to *_desc, so the
onColumnSort toggle could never reverse them (one-directional). City, State,
and Verified had the same defect (asc===desc key). Added the missing sort
keys (stories_asc, garage_asc, city_desc, state_desc, last_verified_asc) to
the SORT_KEYS whitelist + orderByFor, and gave each TABLE_COLS entry distinct
whitelisted asc/desc keys. Verified against the live 70k-home DB: every
asc/desc pair now returns a different first row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M apps/web/src/app/search/SearchClient.tsxM packages/search/src/index.ts
Diff
commit d5513153a2288efac566a66ff44e2e1690014aa9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Aug 13 08:41:34 2026 -0700
HomesOnSpec search: make Table columns bidirectionally sortable (TK-10526)
Stories & Garage column headers set both asc and desc to *_desc, so the
onColumnSort toggle could never reverse them (one-directional). City, State,
and Verified had the same defect (asc===desc key). Added the missing sort
keys (stories_asc, garage_asc, city_desc, state_desc, last_verified_asc) to
the SORT_KEYS whitelist + orderByFor, and gave each TABLE_COLS entry distinct
whitelisted asc/desc keys. Verified against the live 70k-home DB: every
asc/desc pair now returns a different first row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
apps/web/src/app/search/SearchClient.tsx | 10 +++++-----
packages/search/src/index.ts | 10 ++++++++++
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/apps/web/src/app/search/SearchClient.tsx b/apps/web/src/app/search/SearchClient.tsx
index 1b7686be..eb787c4d 100644
--- a/apps/web/src/app/search/SearchClient.tsx
+++ b/apps/web/src/app/search/SearchClient.tsx
@@ -137,19 +137,19 @@ type TableCol = {
};
const TABLE_COLS: TableCol[] = [
{ key: "address", label: "Address", asc: null, desc: null },
- { key: "city", label: "City", asc: "city_asc", desc: "city_asc" },
- { key: "state", label: "State", asc: "state_asc", desc: "state_asc" },
+ { key: "city", label: "City", asc: "city_asc", desc: "city_desc" },
+ { key: "state", label: "State", asc: "state_asc", desc: "state_desc" },
{ key: "price", label: "Price", asc: "price_asc", desc: "price_desc", align: "right" },
{ key: "beds", label: "Beds", asc: "beds_asc", desc: "beds_desc", align: "right" },
{ key: "baths", label: "Baths", asc: "baths_asc", desc: "baths_desc", align: "right" },
{ key: "sqft", label: "Sq Ft", asc: "sqft_asc", desc: "sqft_desc", align: "right" },
- { key: "stories", label: "Stories", asc: "stories_desc", desc: "stories_desc", align: "right" },
- { key: "garage", label: "Garage", asc: "garage_desc", desc: "garage_desc", align: "right" },
+ { key: "stories", label: "Stories", asc: "stories_asc", desc: "stories_desc", align: "right" },
+ { key: "garage", label: "Garage", asc: "garage_asc", desc: "garage_desc", align: "right" },
{ key: "homeType", label: "Type", asc: null, desc: null },
{ key: "status", label: "Status", asc: null, desc: null },
{ key: "completion", label: "Completion", asc: "completion_asc", desc: "completion_desc" },
{ key: "builder", label: "Builder", asc: null, desc: null },
- { key: "verified", label: "Verified", asc: "last_verified", desc: "last_verified" },
+ { key: "verified", label: "Verified", asc: "last_verified_asc", desc: "last_verified" },
];
const STATUS_LABELS: Record<string, string> = {
diff --git a/packages/search/src/index.ts b/packages/search/src/index.ts
index 1345ad60..e4588597 100644
--- a/packages/search/src/index.ts
+++ b/packages/search/src/index.ts
@@ -54,12 +54,17 @@ export const SORT_KEYS = [
"baths_desc",
"baths_asc",
"stories_desc",
+ "stories_asc",
"garage_desc",
+ "garage_asc",
"completion_asc",
"completion_desc",
"city_asc",
+ "city_desc",
"state_asc",
+ "state_desc",
"last_verified",
+ "last_verified_asc",
"closest",
] as const;
export type SortKey = (typeof SORT_KEYS)[number];
@@ -221,12 +226,17 @@ function orderByFor(sort?: SortKey): Prisma.InventoryHomeOrderByWithRelationInpu
case "baths_desc": return [{ bathsTotal: { sort: "desc", nulls: "last" } }, tie];
case "baths_asc": return [{ bathsTotal: { sort: "asc", nulls: "last" } }, tie];
case "stories_desc": return [{ stories: { sort: "desc", nulls: "last" } }, tie];
+ case "stories_asc": return [{ stories: { sort: "asc", nulls: "last" } }, tie];
case "garage_desc": return [{ garageSpaces: { sort: "desc", nulls: "last" } }, tie];
+ case "garage_asc": return [{ garageSpaces: { sort: "asc", nulls: "last" } }, tie];
case "completion_asc": return [{ estCompletionDate: { sort: "asc", nulls: "last" } }, tie];
case "completion_desc": return [{ estCompletionDate: { sort: "desc", nulls: "last" } }, tie];
case "city_asc": return [{ city: "asc" }, { state: "asc" }, tie];
+ case "city_desc": return [{ city: "desc" }, { state: "desc" }, tie];
case "state_asc": return [{ state: "asc" }, { city: "asc" }, tie];
+ case "state_desc": return [{ state: "desc" }, { city: "desc" }, tie];
case "last_verified": return [{ lastVerifiedAt: { sort: "desc", nulls: "last" } }, tie];
+ case "last_verified_asc": return [{ lastVerifiedAt: { sort: "asc", nulls: "last" } }, tie];
case "newest":
default:
return NEWEST; // organic default
← 1ee4dcd7 HomesOnSpec search: add Grid/List/Table view modes + broaden
·
back to Homesonspec
·
Add Summit Homes KC collector adapter (TK-10487 batch 2) e1d685cb →