feat(mall): read the store directory from the API
Wave 5: the store directory, store home and product-page store card stop reading
MOCK_STORES, and the payment and order surfaces name their shop.
- a `shop_profiles` table beside `shops`, so the identity model both consoles
consume is untouched, with a public `GET /api/shops` and `GET /api/shops/{slug}`
and an admin `PUT /api/admin/shops/{id}/profile`
- a shop with no profile is still listed, with the fields absent rather than
invented; the pages guard every block, and a missing logo renders an
initial-letter placeholder
- `scripts/seed-demo.mjs` upserts a profile per demo shop, since profiles hang
off shops that script creates
- payment and order pages resolve shop ids to names from one cached shop read,
retiring the generic "Shop" label
- three things went rather than being faked, following the wave-1 precedent:
`distanceKm` and its sort (no geo model), the store home's sales/comments
sorts, and its "best sellers" rail (no sales model)
- `lowestSku` moved out of the fixed-data module into `apps/mall/utils/product.ts`
and re-exported, so live pages stop importing the mock module for a pure
helper
Verified: 28 backend tests green including five new shop tests; all three
frontends build; the directory, store home, store card and order cards all render
real data with no distance or sales claims; the fixed-data rollback still renders
the store surfaces with the backend stopped.
Note: `nuxt build` does not typecheck in this repo (no `typescript.typeCheck`,
no `vue-tsc`), which AGENTS.md implies it does. A re-export used here created no
local binding and broke internal callers at runtime while the build stayed green;
`docs/TBD-migrate-wave.md` records the gap.
OpenSpec change: openspec/changes/replace-mock-api-wave-5
This commit is contained in:
@@ -491,15 +491,10 @@ export function storeById(idOrSlug: string): MockStore | null {
|
||||
return MOCK_STORES.find((s) => s.id === idOrSlug || s.slug === idOrSlug) ?? null;
|
||||
}
|
||||
|
||||
export function lowestSku(product: Product): Sku | null {
|
||||
const active = (product.skus ?? []).filter((s) => s.active && s.stock > 0);
|
||||
return (
|
||||
active.reduce<Sku | null>(
|
||||
(low, s) => (low === null || s.price_minor < low.price_minor ? s : low),
|
||||
null,
|
||||
) ?? (product.skus ?? []).find((s) => s.active) ?? null
|
||||
);
|
||||
}
|
||||
import { lowestSku } from "~/utils/product";
|
||||
|
||||
/** Kept for the mock-era pages; live pages import it from `~/utils/product`. */
|
||||
export { lowestSku };
|
||||
|
||||
export interface MockSearchQuery {
|
||||
q?: string;
|
||||
|
||||
Reference in New Issue
Block a user