The 'Delivered' tab on /orders was broken \u2014 4,326 of 4,514 orders
(96%) have at least one delivered item. The old tab tried to
build a WHERE id IN (...) filter with 4,326 ids (~120 KB),
blowing past PB's ~4 KB filter cap and 400ing. This commit
moves historical orders to a dedicated page so:
- The main /orders view is fast (22-28 active orders, not 4.5k
historical)
- The archive can be honest about its pagination ('Page 1 of
217' is expected when looking for something from last month)
- The badge counts on the main page stop being dominated by
'Delivered (4,326)' / 'Cancelled (111)'
# Measured against the live PB
/api/v1/orders/archive?page=1&perPage=2 \u2014 15.2s cold, 6.5 KB
response. The 15s is the order_items.getFullList over 13,256
items (the bottleneck; PB paginates over many round-trips).
Per-row payload is the standard 5-6 KB for orders with deep
expand. Subsequent pages within the same minute would be much
faster since PB caches the order_items query.
# Service layer
- getOrdersArchiveData(params) in src/lib/server/orders-service.ts
- Returns paginated list of orders with \u22651 item in
(delivered, cancelled) status, plus per-status distinct
counts for the header totals
- Strategy: getFullList on order_items (ids + status only),
dedupe + per-status counts in one pass, chunk the order ids
by 100 (PB's URL/filter cap is between 4.5-6.7 KB) and fire
parallel getFullList queries on orders with deep expand
- Search hits order_number, company, customer, contact_name
- Sort defaults to -created, override via the sort param
- /api/v1/orders/archive thin route: page, perPage, search, sort
(no tab, no nocache \u2014 archive is one bucket, not a tab split)
# Page
- /orders/archive/page.tsx: card list with header counts
(delivered / cancelled badges), search input, pagination
footer. Click an order to open /orders/[id] in detail.
# Main /orders updates
- Delivered + Cancelled removed from the tab strip (passed
tabKeys=['new','processing','collection_pool','collected'] to
ItemStatusTabs)
- Counts on the main page now exclude delivered + cancelled
- 'Archive' button in the page header takes the operator to
/orders/archive
- Safety useEffect: if activeTab is delivered/cancelled (e.g.
stale URL or local state), reset to 'new'
# Tests
4 new tests in orders-service.test.ts:
- Returns orders with \u22651 delivered/cancelled item, plus counts
- Dedupe: one order with multiple matching items counts as 1
- Search by order_number and contact_name
- Empty result when no orders match
Full suite: 1321/1321 pass.
Co-authored-by: Orca <help@stably.ai>
57 lines
No EOL
1.5 KiB
TypeScript
57 lines
No EOL
1.5 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
TAB_GROUP_ORDER,
|
|
TAB_GROUP_VISUAL,
|
|
type TabGroup,
|
|
} from "@/lib/item-status-ui";
|
|
import { FilterTabs, type FilterTab } from "@/components/filter-tabs";
|
|
|
|
type Counts = Record<TabGroup, number>;
|
|
|
|
interface ItemStatusTabsProps {
|
|
active: TabGroup;
|
|
onChange: (next: TabGroup) => void;
|
|
counts: Counts;
|
|
/**
|
|
* Optional subset of tab keys to render. Defaults to the full
|
|
* `TAB_GROUP_ORDER`. The /orders page passes the active-workflow
|
|
* subset (`new`, `processing`, `collection_pool`, `collected`)
|
|
* so delivered + cancelled don't appear as zero-count tabs —
|
|
* they live on /orders/archive.
|
|
*/
|
|
tabKeys?: readonly TabGroup[];
|
|
}
|
|
|
|
/**
|
|
* /orders filter pill bar — thin wrapper around the generic
|
|
* `<FilterTabs>` that maps the `TabGroup` enum + its colour map into
|
|
* the `FilterTab` shape.
|
|
*
|
|
* Kept as a separate export so /orders callers don't have to know
|
|
* about FilterTabs. The sprint page will use FilterTabs directly with
|
|
* category data.
|
|
*/
|
|
export function ItemStatusTabs({
|
|
active,
|
|
onChange,
|
|
counts,
|
|
tabKeys,
|
|
}: ItemStatusTabsProps) {
|
|
const keys = tabKeys ?? TAB_GROUP_ORDER;
|
|
const tabs: FilterTab[] = keys.map((key) => ({
|
|
key,
|
|
label: TAB_GROUP_VISUAL[key].label,
|
|
color: TAB_GROUP_VISUAL[key].hex,
|
|
count: counts[key] ?? 0,
|
|
}));
|
|
|
|
return (
|
|
<FilterTabs
|
|
tabs={tabs}
|
|
active={active}
|
|
onChange={(k) => onChange(k as TabGroup)}
|
|
ariaLabel="Filter orders by item status"
|
|
/>
|
|
);
|
|
} |