@lukoweb/apitogo-plugin-dev-portal-billing 0.2.53 → 0.2.56
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/{AccountPlansPage-DvRFe3di.mjs → AccountPlansPage-BuM7fe82.mjs} +14 -10
- package/dist/{CheckoutPage-CwSElFUk.mjs → CheckoutPage-BSiADcI6.mjs} +32 -15
- package/dist/{ContactSalesPage-q7Dxxtx6.mjs → ContactSalesPage-BqqDmorF.mjs} +4 -11
- package/dist/{CredentialsPage-B2jPo6Go.mjs → CredentialsPage-DjNvBBLb.mjs} +28 -19
- package/dist/{PricingCard-CKdq1oWn.mjs → PricingCard-DFuQEw7Y.mjs} +10 -4
- package/dist/{PricingPage-DnQQfy9L.mjs → PricingPage-SpL81vpd.mjs} +14 -13
- package/dist/SubscriptionsPage-CwsBtNld.mjs +274 -0
- package/dist/{UsagePage-BF4QgrTc.mjs → UsagePage-Dw5Uepg3.mjs} +61 -19
- package/dist/{account-links-D_vS0GJn.mjs → account-links-Drofs-f-.mjs} +1 -1
- package/dist/{billing-state-DbU5Lpoz.mjs → billing-state-DBQR2tad.mjs} +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +25 -23
- package/dist/{key-plan-note-DTWeFhn2.mjs → page-state-BLL2JJBc.mjs} +22 -2
- package/dist/paths-DaVyTIDJ.mjs +14 -0
- package/dist/pending-checkout-DpVaNnTu.mjs +45 -0
- package/dist/problem-details-n20-dy3w.mjs +18 -0
- package/dist/{useApiKeys-CVgXfUop.mjs → useApiKeys-BOY3vIOr.mjs} +3 -9
- package/dist/{useDevPortalApiBaseUrl-BstWzITX.mjs → useDevPortalApiBaseUrl-BiI2jFjU.mjs} +14 -14
- package/dist/{useMySubscriptions-BtxAXA1m.mjs → useMySubscriptions-BYVIIWbe.mjs} +2 -2
- package/dist/{usePlans-DPGFWcVo.mjs → usePlans-HyhIIuJZ.mjs} +1 -1
- package/dist/{useUsage--5sZub3M.mjs → useUsage-B5x9YuKa.mjs} +1 -1
- package/package.json +3 -3
- package/dist/SubscriptionsPage-msO31jv-.mjs +0 -223
- package/dist/paths-ujy9wjVK.mjs +0 -12
- /package/dist/{demo-session-rN2Gj4lM.mjs → demo-session-yK9qEqV-.mjs} +0 -0
- /package/dist/{pricing-config-02m4dyFf.mjs → pricing-config-Bc6eWFUO.mjs} +0 -0
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { i as CREDENTIALS_PATH, t as ACCOUNT_PLANS_PATH } from "./paths-ujy9wjVK.mjs";
|
|
2
|
-
import { a as formatPlanPrice, p as parseMonthlyQuotaCalls, s as isActiveSubscription, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BstWzITX.mjs";
|
|
3
|
-
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
4
|
-
import { t as useMySubscriptions } from "./useMySubscriptions-BtxAXA1m.mjs";
|
|
5
|
-
import { t as usePlans } from "./usePlans-DPGFWcVo.mjs";
|
|
6
|
-
import { n as useApiKeys } from "./useApiKeys-CVgXfUop.mjs";
|
|
7
|
-
import { t as useUsage } from "./useUsage--5sZub3M.mjs";
|
|
8
|
-
import { i as hasPaymentProvider, r as checkoutConfirmingText } from "./billing-state-DbU5Lpoz.mjs";
|
|
9
|
-
import { n as ChoosePlanNotice, t as keyPlanNote } from "./key-plan-note-DTWeFhn2.mjs";
|
|
10
|
-
import { Head, Spinner } from "@lukoweb/apitogo/components";
|
|
11
|
-
import { Link as Link$1, useSearchParams } from "@lukoweb/apitogo/router";
|
|
12
|
-
import { useEffect } from "react";
|
|
13
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
-
import { useMutation } from "@lukoweb/apitogo/react-query";
|
|
15
|
-
import { useAuth } from "@lukoweb/apitogo/hooks";
|
|
16
|
-
import { Button as Button$1 } from "@lukoweb/apitogo/ui/Button.js";
|
|
17
|
-
|
|
18
|
-
//#region src/hooks/useBillingPortal.ts
|
|
19
|
-
function useBillingPortal() {
|
|
20
|
-
const apiBaseUrl = useDevPortalApiBaseUrl();
|
|
21
|
-
return useMutation({ mutationFn: async (returnUrl) => {
|
|
22
|
-
if (!apiBaseUrl) throw new Error("Dev portal API is not configured.");
|
|
23
|
-
const response = await fetch(`${apiBaseUrl}/api/v1/subscriptions/billing-portal`, {
|
|
24
|
-
method: "POST",
|
|
25
|
-
headers: {
|
|
26
|
-
Accept: "application/json",
|
|
27
|
-
"Content-Type": "application/json"
|
|
28
|
-
},
|
|
29
|
-
credentials: "include",
|
|
30
|
-
body: JSON.stringify({ returnUrl: returnUrl ?? `${window.location.origin}/account/subscriptions` })
|
|
31
|
-
});
|
|
32
|
-
if (!response.ok) throw new Error("Unable to open billing portal.");
|
|
33
|
-
const body = await response.json();
|
|
34
|
-
if (!body.url) throw new Error("Billing portal URL was not returned.");
|
|
35
|
-
window.location.assign(body.url);
|
|
36
|
-
} });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/pages/SubscriptionsPage.tsx
|
|
41
|
-
const SubscriptionsPage = () => {
|
|
42
|
-
const { billing } = useDevPortalBillingConfig();
|
|
43
|
-
const auth = useAuth();
|
|
44
|
-
const [searchParams] = useSearchParams();
|
|
45
|
-
const checkoutSuccess = searchParams.get("checkout") === "success";
|
|
46
|
-
const checkoutPaid = searchParams.get("paid") !== "0";
|
|
47
|
-
const { data: me, isLoading, refetch } = useMySubscriptions();
|
|
48
|
-
const { data: catalog } = usePlans();
|
|
49
|
-
const billingPortal = useBillingPortal();
|
|
50
|
-
const { data: usage } = useUsage("30d");
|
|
51
|
-
const { data: apiKeys } = useApiKeys();
|
|
52
|
-
const planNote = keyPlanNote(apiKeys?.plans ?? []);
|
|
53
|
-
const planBySku = new Map((catalog?.plans ?? []).map((plan) => [plan.sku, plan]));
|
|
54
|
-
const subscriptions = me?.subscriptions ?? [];
|
|
55
|
-
const activeSubscription = subscriptions.find((sub) => isActiveSubscription(sub.status));
|
|
56
|
-
const activePlan = activeSubscription ? planBySku.get(activeSubscription.planSku) : void 0;
|
|
57
|
-
const confirmingPayment = checkoutSuccess && !isLoading && !activeSubscription;
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (!confirmingPayment) return;
|
|
60
|
-
let attempts = 0;
|
|
61
|
-
const timer = setInterval(() => {
|
|
62
|
-
attempts += 1;
|
|
63
|
-
refetch();
|
|
64
|
-
if (attempts >= 30) clearInterval(timer);
|
|
65
|
-
}, 2e3);
|
|
66
|
-
return () => clearInterval(timer);
|
|
67
|
-
}, [confirmingPayment, refetch]);
|
|
68
|
-
const monthlyQuota = activePlan ? parseMonthlyQuotaCalls(activePlan.limitsJson) : null;
|
|
69
|
-
const usedRequests = usage?.requestCount ?? 0;
|
|
70
|
-
const quotaPct = monthlyQuota && monthlyQuota > 0 ? Math.min(100, Math.round(usedRequests / monthlyQuota * 100)) : null;
|
|
71
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
72
|
-
className: "px-8 py-7",
|
|
73
|
-
children: [
|
|
74
|
-
/* @__PURE__ */ jsx(Head, { children: /* @__PURE__ */ jsx("title", { children: "Billing" }) }),
|
|
75
|
-
/* @__PURE__ */ jsx("h1", {
|
|
76
|
-
className: "mb-2 text-[1.6rem] font-bold tracking-[-0.01em]",
|
|
77
|
-
children: "Billing"
|
|
78
|
-
}),
|
|
79
|
-
/* @__PURE__ */ jsx("p", {
|
|
80
|
-
className: "mb-8 text-muted-foreground",
|
|
81
|
-
children: "Manage your plan, payment method, and invoices."
|
|
82
|
-
}),
|
|
83
|
-
confirmingPayment ? /* @__PURE__ */ jsx("div", {
|
|
84
|
-
className: "mb-6 rounded-xl border border-border bg-card p-4 text-sm",
|
|
85
|
-
children: checkoutConfirmingText(checkoutPaid)
|
|
86
|
-
}) : null,
|
|
87
|
-
checkoutSuccess && activeSubscription ? /* @__PURE__ */ jsx("div", {
|
|
88
|
-
className: "mb-6 rounded-xl border border-green-500/30 bg-green-500/10 p-4 text-sm",
|
|
89
|
-
children: planNote ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
90
|
-
planNote.text,
|
|
91
|
-
" ",
|
|
92
|
-
/* @__PURE__ */ jsx(Link$1, {
|
|
93
|
-
to: CREDENTIALS_PATH,
|
|
94
|
-
className: "font-medium underline",
|
|
95
|
-
children: "Create the key"
|
|
96
|
-
}),
|
|
97
|
-
"."
|
|
98
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
|
-
"Your subscription is active.",
|
|
100
|
-
" ",
|
|
101
|
-
/* @__PURE__ */ jsx(Link$1, {
|
|
102
|
-
to: CREDENTIALS_PATH,
|
|
103
|
-
className: "font-medium underline",
|
|
104
|
-
children: "View your API credentials"
|
|
105
|
-
}),
|
|
106
|
-
"."
|
|
107
|
-
] })
|
|
108
|
-
}) : null,
|
|
109
|
-
isLoading ? /* @__PURE__ */ jsx("p", {
|
|
110
|
-
className: "text-muted-foreground",
|
|
111
|
-
children: "Loading billing details…"
|
|
112
|
-
}) : null,
|
|
113
|
-
!isLoading && activeSubscription ? /* @__PURE__ */ jsxs("div", {
|
|
114
|
-
className: "mb-8 rounded-xl border border-border bg-card p-6",
|
|
115
|
-
children: [
|
|
116
|
-
/* @__PURE__ */ jsx("p", {
|
|
117
|
-
className: "text-xs font-medium uppercase tracking-[0.05em] text-muted-foreground",
|
|
118
|
-
children: "Current plan"
|
|
119
|
-
}),
|
|
120
|
-
/* @__PURE__ */ jsx("h2", {
|
|
121
|
-
className: "mt-2 text-2xl font-bold",
|
|
122
|
-
children: activePlan?.displayName ?? activeSubscription.planSku
|
|
123
|
-
}),
|
|
124
|
-
activePlan ? /* @__PURE__ */ jsx("p", {
|
|
125
|
-
className: "mt-1 text-sm text-muted-foreground",
|
|
126
|
-
children: formatPlanPrice(activePlan)
|
|
127
|
-
}) : /* @__PURE__ */ jsx("p", {
|
|
128
|
-
className: "mt-1 text-sm text-muted-foreground",
|
|
129
|
-
children: "This plan is no longer offered. Your access continues until you cancel or change plan."
|
|
130
|
-
}),
|
|
131
|
-
activeSubscription.currentPeriodEnd ? /* @__PURE__ */ jsxs("p", {
|
|
132
|
-
className: "mt-3 text-sm text-muted-foreground",
|
|
133
|
-
children: [
|
|
134
|
-
"Renews",
|
|
135
|
-
" ",
|
|
136
|
-
new Date(activeSubscription.currentPeriodEnd).toLocaleDateString()
|
|
137
|
-
]
|
|
138
|
-
}) : null,
|
|
139
|
-
quotaPct != null && monthlyQuota != null ? /* @__PURE__ */ jsxs("div", {
|
|
140
|
-
className: "mt-5",
|
|
141
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
142
|
-
className: "mb-1.5 flex justify-between text-xs text-muted-foreground",
|
|
143
|
-
children: [/* @__PURE__ */ jsx("span", { children: "Monthly requests" }), /* @__PURE__ */ jsxs("span", { children: [
|
|
144
|
-
usedRequests.toLocaleString(),
|
|
145
|
-
" /",
|
|
146
|
-
" ",
|
|
147
|
-
monthlyQuota.toLocaleString()
|
|
148
|
-
] })]
|
|
149
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
150
|
-
className: "h-2 rounded-full bg-muted",
|
|
151
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
152
|
-
className: "h-full rounded-full bg-primary transition-[width]",
|
|
153
|
-
style: { width: `${quotaPct}%` }
|
|
154
|
-
})
|
|
155
|
-
})]
|
|
156
|
-
}) : null
|
|
157
|
-
]
|
|
158
|
-
}) : null,
|
|
159
|
-
!isLoading && subscriptions.length === 0 ? /* @__PURE__ */ jsx(ChoosePlanNotice, {
|
|
160
|
-
className: "mb-8 rounded-xl border border-dashed p-8 text-center",
|
|
161
|
-
body: "You do not have a plan yet. Choose one to start using the API; your billing details appear here afterwards."
|
|
162
|
-
}) : null,
|
|
163
|
-
!isLoading && subscriptions.length > 1 ? /* @__PURE__ */ jsx("div", {
|
|
164
|
-
className: "mb-8 space-y-4",
|
|
165
|
-
children: subscriptions.map((subscription) => {
|
|
166
|
-
const plan = planBySku.get(subscription.planSku);
|
|
167
|
-
return /* @__PURE__ */ jsx("article", {
|
|
168
|
-
className: "rounded-xl border bg-card p-5",
|
|
169
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
170
|
-
className: "flex flex-wrap items-start justify-between gap-4",
|
|
171
|
-
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
|
|
172
|
-
className: "font-semibold",
|
|
173
|
-
children: plan?.displayName ?? subscription.planSku
|
|
174
|
-
}), plan ? /* @__PURE__ */ jsx("p", {
|
|
175
|
-
className: "mt-1 text-sm text-muted-foreground",
|
|
176
|
-
children: formatPlanPrice(plan)
|
|
177
|
-
}) : null] }), /* @__PURE__ */ jsx("span", {
|
|
178
|
-
className: "rounded-full bg-muted px-3 py-1 text-xs font-medium text-muted-foreground",
|
|
179
|
-
children: subscription.status
|
|
180
|
-
})]
|
|
181
|
-
})
|
|
182
|
-
}, `${subscription.planSku}-${subscription.status}`);
|
|
183
|
-
})
|
|
184
|
-
}) : null,
|
|
185
|
-
/* @__PURE__ */ jsxs("div", {
|
|
186
|
-
className: "flex flex-wrap gap-3",
|
|
187
|
-
children: [
|
|
188
|
-
/* @__PURE__ */ jsx(Button$1, {
|
|
189
|
-
variant: "outline",
|
|
190
|
-
asChild: true,
|
|
191
|
-
children: /* @__PURE__ */ jsx(Link$1, {
|
|
192
|
-
to: ACCOUNT_PLANS_PATH,
|
|
193
|
-
children: "Change plan"
|
|
194
|
-
})
|
|
195
|
-
}),
|
|
196
|
-
auth.isAuthenticated && hasPaymentProvider(billing) ? /* @__PURE__ */ jsx(Button$1, {
|
|
197
|
-
variant: "default",
|
|
198
|
-
disabled: billingPortal.isPending,
|
|
199
|
-
onClick: () => {
|
|
200
|
-
billingPortal.mutate();
|
|
201
|
-
},
|
|
202
|
-
children: billingPortal.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : "Manage payment & invoices"
|
|
203
|
-
}) : null,
|
|
204
|
-
auth.isAuthenticated ? /* @__PURE__ */ jsx(Button$1, {
|
|
205
|
-
variant: "secondary",
|
|
206
|
-
asChild: true,
|
|
207
|
-
children: /* @__PURE__ */ jsx(Link$1, {
|
|
208
|
-
to: CREDENTIALS_PATH,
|
|
209
|
-
children: "API credentials"
|
|
210
|
-
})
|
|
211
|
-
}) : null
|
|
212
|
-
]
|
|
213
|
-
}),
|
|
214
|
-
billingPortal.isError ? /* @__PURE__ */ jsx("p", {
|
|
215
|
-
className: "mt-4 text-sm text-destructive",
|
|
216
|
-
children: billingPortal.error instanceof Error ? billingPortal.error.message : "Unable to open billing portal."
|
|
217
|
-
}) : null
|
|
218
|
-
]
|
|
219
|
-
});
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
//#endregion
|
|
223
|
-
export { SubscriptionsPage as default };
|
package/dist/paths-ujy9wjVK.mjs
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
//#region src/paths.ts
|
|
2
|
-
const PRICING_PATH = "/pricing";
|
|
3
|
-
const ACCOUNT_PLANS_PATH = "/account/plans";
|
|
4
|
-
const CHECKOUT_PATH = "/checkout";
|
|
5
|
-
const CONTACT_SALES_PATH = "/contact-sales";
|
|
6
|
-
const SUBSCRIPTIONS_PATH = "/account/subscriptions";
|
|
7
|
-
const CREDENTIALS_PATH = "/account/credentials";
|
|
8
|
-
const USAGE_PATH = "/account/usage";
|
|
9
|
-
const LOGIN_NAV_PATH = "/signin";
|
|
10
|
-
|
|
11
|
-
//#endregion
|
|
12
|
-
export { LOGIN_NAV_PATH as a, USAGE_PATH as c, CREDENTIALS_PATH as i, CHECKOUT_PATH as n, PRICING_PATH as o, CONTACT_SALES_PATH as r, SUBSCRIPTIONS_PATH as s, ACCOUNT_PLANS_PATH as t };
|
|
File without changes
|
|
File without changes
|