feat: Updated plans and catalogue pages

This commit is contained in:
2026-08-25 14:35:47 +00:00
parent 270d55e6a6
commit 3e4865884c
18 changed files with 825 additions and 390 deletions
+9 -3
View File
@@ -8,6 +8,9 @@
* customer-facing and should be shown verbatim).
*/
/* catalogue.ts imports only types from here, so this is not a cycle. */
import { rowsForPlan } from "@/lib/catalogue";
export const API_BASE = (process.env.NEXT_PUBLIC_ADMIN_API_URL ?? "").replace(/\/$/, "");
export class NotConnected extends Error {
@@ -176,6 +179,11 @@ export interface Plan {
export interface CatalogueRow {
kind: "base" | "limit" | "feature";
/* "plan" rows carry a deployment and tier and belong to that plan alone.
* "shared" rows leave both empty and are sold by every paid plan, which is
* why a price ID is typed once rather than four times. Read them through
* rowsForPlan in lib/catalogue, never by filtering on deployment. */
scope: "plan" | "shared";
deployment: Deployment;
tier: Tier;
limit_key?: string;
@@ -213,9 +221,7 @@ export function lineItemsFor(
const env = opts.env;
const plan = opts.plans.find((p) => p.deployment === deployment && p.tier === choice.tier);
if (!plan) return [];
const rows = opts.catalogue.filter(
(r) => r.deployment === deployment && r.tier === choice.tier,
);
const rows = rowsForPlan(opts.catalogue, deployment, choice.tier);
const priceOf = (r: CatalogueRow) => r.price_ids?.[env]?.[choice.term] ?? "";
const base = plan.base_limits.max_servers;
const items: { priceId: string; quantity: number }[] = [];