@lukoweb/apitogo-plugin-dev-portal-billing 0.1.137 → 0.1.139

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import { UseQueryResult } from "@lukoweb/apitogo/react-query";
2
3
  import * as _lukoweb_apitogo0 from "@lukoweb/apitogo";
3
4
  import * as _tanstack_react_query0 from "@tanstack/react-query";
4
5
 
@@ -9,6 +10,23 @@ declare const AccountPlansPage: () => react_jsx_runtime0.JSX.Element;
9
10
  declare const OverviewDashboardPage: () => react_jsx_runtime0.JSX.Element;
10
11
  //#endregion
11
12
  //#region src/types.d.ts
13
+ type DevPortalPlan = {
14
+ sku: string;
15
+ displayName: string;
16
+ limitsJson: string | null;
17
+ priceAmount: number; /** `custom` plans are sold via a contact-sales form instead of checkout. Absent means `fixed`. */
18
+ pricingModel?: string; /** Text shown instead of the price (custom plans), e.g. "Let's talk". */
19
+ priceLabel?: string | null;
20
+ priceCurrency: string;
21
+ billingPeriod: string;
22
+ syncedAtUtc?: string;
23
+ includedActionKeys?: string[]; /** Optional marketing bullets for pricing cards (preview / local catalog). */
24
+ features?: string[];
25
+ };
26
+ type DevPortalPlanCatalog = {
27
+ plans: DevPortalPlan[];
28
+ lastSyncedAtUtc?: string | null;
29
+ };
12
30
  type DevPortalPricingCompareRow = {
13
31
  label: string;
14
32
  values: string[];
@@ -207,4 +225,26 @@ declare function useCreateApiKey(): _tanstack_react_query0.UseMutationResult<Dev
207
225
  }, unknown>;
208
226
  declare function useRevokeApiKey(): _tanstack_react_query0.UseMutationResult<void, Error, string, unknown>;
209
227
  //#endregion
210
- export { ACCOUNT_PLANS_PATH, API_KEY_CAP_REACHED, AccountPlansPage, ApiKeysPanel, CHECKOUT_PATH, CONTACT_SALES_PATH, CREDENTIALS_PATH, OverviewDashboardPage, PRICING_PATH, SUBSCRIPTIONS_PATH, USAGE_PATH, devPortalBillingPlugin, useApiKeys, useCreateApiKey, useRevokeApiKey };
228
+ //#region src/hooks/usePlans.d.ts
229
+ declare function usePlans(): UseQueryResult<DevPortalPlanCatalog>;
230
+ //#endregion
231
+ //#region src/hooks/usePlansPreview.d.ts
232
+ /** Matches `PlansPreviewPlan` from `@lukoweb/apitogo-module-landing`. */
233
+ type PlansPreviewItem = {
234
+ name: string;
235
+ price: string;
236
+ unit: string;
237
+ blurb: string;
238
+ featured?: boolean;
239
+ };
240
+ /** Maps plans to landing `PlansPreviewSection` cards, highlighting the same plan as /pricing. */
241
+ declare const toPlansPreviewItems: (plans: DevPortalPlan[]) => PlansPreviewItem[];
242
+ /**
243
+ * Plan cards for the landing `PlansPreviewSection`, sourced like the /pricing page: the dev
244
+ * portal backend when live, `modules.userPanel.plans.items` from `apitogo.config.json` in
245
+ * preview/demo mode. Falls back to the config catalog while the live one is loading or
246
+ * unavailable, so prerendered pages still show plans.
247
+ */
248
+ declare const usePlansPreview: () => PlansPreviewItem[];
249
+ //#endregion
250
+ export { ACCOUNT_PLANS_PATH, API_KEY_CAP_REACHED, AccountPlansPage, ApiKeysPanel, CHECKOUT_PATH, CONTACT_SALES_PATH, CREDENTIALS_PATH, type DevPortalPlan, type DevPortalPlanCatalog, OverviewDashboardPage, PRICING_PATH, type PlansPreviewItem, SUBSCRIPTIONS_PATH, USAGE_PATH, devPortalBillingPlugin, toPlansPreviewItems, useApiKeys, useCreateApiKey, usePlans, usePlansPreview, useRevokeApiKey };
package/dist/index.mjs CHANGED
@@ -136,6 +136,21 @@ function formatBillingPeriod(period) {
136
136
  if (normalized === "custom") return "talk to us";
137
137
  return period;
138
138
  }
139
+ /** Headline price for a plan card, without the period suffix (e.g. `$19`, `$0`, `Custom`). */
140
+ function formatPlanDisplayPrice(plan) {
141
+ if (isPlanCustomPriced(plan)) return formatCustomPriceLabel(plan);
142
+ if (isPlanFree(plan)) return "$0";
143
+ const priceLabel = formatPlanPrice(plan);
144
+ return priceLabel.replace(/\/mo$/, "").replace(/\/yr$/, "") || priceLabel;
145
+ }
146
+ /** Caption shown under the plan price (e.g. `per month`, `talk to us`). */
147
+ function formatPlanPriceUnit(plan) {
148
+ return isPlanCustomPriced(plan) ? "talk to us" : formatBillingPeriod(plan.billingPeriod);
149
+ }
150
+ /** SKU of the plan to highlight: `developer` if present, else the first low-priced paid plan. */
151
+ function pickFeaturedPlanSku(plans) {
152
+ return plans.find((p) => p.sku === "developer")?.sku ?? plans.find((p) => p.priceAmount > 0 && p.priceAmount < 50)?.sku ?? plans.find((p) => p.priceAmount > 0)?.sku;
153
+ }
139
154
  function formatRateLimit(rate) {
140
155
  if (!rate || typeof rate !== "object") return null;
141
156
  const { calls, renewalPeriodSeconds } = rate;
@@ -219,9 +234,7 @@ const planCtaPath = (plan) => `${isPlanCustomPriced(plan) ? CONTACT_SALES_PATH :
219
234
  const PricingCard = ({ plan, mode = "public", subscriptionStatus, isSubscribed = false, onUnsubscribe, isCanceling = false, cancelDisabled = false, featured = false }) => {
220
235
  const isActive = isSubscribed || isActiveSubscription(subscriptionStatus ?? "");
221
236
  const features = listPlanFeatureLines(plan);
222
- const priceLabel = formatPlanPrice(plan);
223
- const isCustom = isPlanCustomPriced(plan);
224
- const displayPrice = isCustom ? formatCustomPriceLabel(plan) : isPlanFree(plan) ? "$0" : priceLabel.replace(/\/mo$/, "").replace(/\/yr$/, "") || priceLabel;
237
+ const displayPrice = formatPlanDisplayPrice(plan);
225
238
  return /* @__PURE__ */ jsxs("article", {
226
239
  className: cn("flex h-full w-full flex-col rounded-xl border border-border bg-card p-7", featured && "border-primary/50 shadow-[0_10px_28px_rgba(13,148,136,0.28)] ring-1 ring-primary/25", isActive && mode === "account" && "border-primary/40 ring-1 ring-primary/20"),
227
240
  "data-testid": `pricing-card-${plan.sku}`,
@@ -250,7 +263,7 @@ const PricingCard = ({ plan, mode = "public", subscriptionStatus, isSubscribed =
250
263
  }),
251
264
  /* @__PURE__ */ jsx("p", {
252
265
  className: "mb-[18px] mt-0.5 text-[0.78125rem] text-muted-foreground",
253
- children: isCustom ? "talk to us" : formatBillingPeriod(plan.billingPeriod)
266
+ children: formatPlanPriceUnit(plan)
254
267
  }),
255
268
  /* @__PURE__ */ jsx("div", {
256
269
  className: "space-y-2",
@@ -1905,7 +1918,7 @@ const PricingPage = () => {
1905
1918
  const title = pricing?.title ?? "Pay for what you call";
1906
1919
  const subtitle = pricing?.subtitle ?? "Every plan includes the full endpoint catalog. Higher tiers raise your request quota, rate limit, and support level.";
1907
1920
  const plans = catalog?.plans ?? [];
1908
- const featuredSku = plans.find((p) => p.sku === "developer")?.sku ?? plans.find((p) => p.priceAmount > 0 && p.priceAmount < 50)?.sku ?? plans.find((p) => p.priceAmount > 0)?.sku;
1921
+ const featuredSku = pickFeaturedPlanSku(plans);
1909
1922
  const compareRows = pricing?.compareRows && pricing.compareRows.length > 0 ? pricing.compareRows : DEFAULT_COMPARE_ROWS;
1910
1923
  const faqs = pricing?.faqs && pricing.faqs.length > 0 ? pricing.faqs : DEFAULT_FAQS;
1911
1924
  const compareHeaders = plans.length > 0 ? plans.map((p) => p.displayName) : [
@@ -2593,4 +2606,28 @@ const devPortalBillingPlugin = createPlugin((options = {}) => ({
2593
2606
  }));
2594
2607
 
2595
2608
  //#endregion
2596
- export { ACCOUNT_PLANS_PATH, API_KEY_CAP_REACHED, AccountPlansPage, ApiKeysPanel, CHECKOUT_PATH, CONTACT_SALES_PATH, CREDENTIALS_PATH, OverviewDashboardPage, PRICING_PATH, SUBSCRIPTIONS_PATH, USAGE_PATH, devPortalBillingPlugin, useApiKeys, useCreateApiKey, useRevokeApiKey };
2609
+ //#region src/hooks/usePlansPreview.ts
2610
+ /** Maps plans to landing `PlansPreviewSection` cards, highlighting the same plan as /pricing. */
2611
+ const toPlansPreviewItems = (plans) => {
2612
+ const featuredSku = pickFeaturedPlanSku(plans);
2613
+ return plans.map((plan) => ({
2614
+ name: plan.displayName,
2615
+ price: formatPlanDisplayPrice(plan),
2616
+ unit: formatPlanPriceUnit(plan),
2617
+ blurb: listPlanFeatureLines(plan).slice(0, 2).join(" · "),
2618
+ featured: plan.sku === featuredSku
2619
+ }));
2620
+ };
2621
+ /**
2622
+ * Plan cards for the landing `PlansPreviewSection`, sourced like the /pricing page: the dev
2623
+ * portal backend when live, `modules.userPanel.plans.items` from `apitogo.config.json` in
2624
+ * preview/demo mode. Falls back to the config catalog while the live one is loading or
2625
+ * unavailable, so prerendered pages still show plans.
2626
+ */
2627
+ const usePlansPreview = () => {
2628
+ const { data } = usePlans();
2629
+ return toPlansPreviewItems(data?.plans ?? parseManifestPlans().plans);
2630
+ };
2631
+
2632
+ //#endregion
2633
+ export { ACCOUNT_PLANS_PATH, API_KEY_CAP_REACHED, AccountPlansPage, ApiKeysPanel, CHECKOUT_PATH, CONTACT_SALES_PATH, CREDENTIALS_PATH, OverviewDashboardPage, PRICING_PATH, SUBSCRIPTIONS_PATH, USAGE_PATH, devPortalBillingPlugin, toPlansPreviewItems, useApiKeys, useCreateApiKey, usePlans, usePlansPreview, useRevokeApiKey };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo-plugin-dev-portal-billing",
3
- "version": "0.1.137",
3
+ "version": "0.1.139",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/zuplo/zudoku",
@@ -46,8 +46,8 @@
46
46
  "react": "19.2.4",
47
47
  "react-dom": "19.2.4",
48
48
  "tsdown": "0.20.3",
49
- "@lukoweb/apitogo": "0.1.137",
50
- "@lukoweb/apitogo-module-user-panel": "0.1.137"
49
+ "@lukoweb/apitogo": "0.1.139",
50
+ "@lukoweb/apitogo-module-user-panel": "0.1.139"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "react": ">=19.2.0",