planmymeal/app/lib/pricing.ts

42 lines
1.5 KiB
TypeScript
Raw Normal View History

2026-10-31 20:44:29 -05:00
import type { ItemId, StoreItem } from "@/app/types";
import { CATALOG } from "./catalog";
// ---------------------------------------------------------------------------
// PriceProvider: the single seam between "where prices come from" and the
// rest of the app. The cost math only ever calls `getItem`.
//
// To use live retailer prices later:
// 1. Fetch prices on the SERVER (a Server Action or route handler) so the
// API key never reaches the browser.
// 2. Build a snapshot `StoreItem[]` from the response.
// 3. Pass `new SnapshotPriceProvider("Live grocery prices", snapshot)` into
// the grocery/planner functions instead of `averageGroceryProvider`.
// The math stays synchronous and testable because it works on a snapshot.
// ---------------------------------------------------------------------------
export interface PriceProvider {
/** Shown in the UI so users know where prices came from. */
readonly label: string;
getItem(id: ItemId): StoreItem | undefined;
}
export class SnapshotPriceProvider implements PriceProvider {
private readonly byId: Map<ItemId, StoreItem>;
constructor(
readonly label: string,
items: StoreItem[],
) {
this.byId = new Map(items.map((item) => [item.id, item]));
}
getItem(id: ItemId): StoreItem | undefined {
return this.byId.get(id);
}
}
export const averageGroceryProvider: PriceProvider = new SnapshotPriceProvider(
"Based on average grocery prices as of October 2026",
CATALOG,
);