@omnikit-js/ui 0.9.7 → 0.9.9
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/chunk-2SK6OTCD.js +1049 -0
- package/dist/chunk-2SK6OTCD.js.map +1 -0
- package/dist/{chunk-O6555PUL.js → chunk-JFXMNYII.js} +3 -3
- package/dist/{chunk-O6555PUL.js.map → chunk-JFXMNYII.js.map} +1 -1
- package/dist/components/client/index.d.ts +14 -2
- package/dist/components/client/index.js +5 -49
- package/dist/components/client/index.js.map +1 -1
- package/dist/components/server/index.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +18 -1
- package/dist/chunk-IKBW2JFX.js +0 -471
- package/dist/chunk-IKBW2JFX.js.map +0 -1
package/dist/chunk-IKBW2JFX.js
DELETED
|
@@ -1,471 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { Card, Button, Tabs } from '@marcoschwartz/lite-ui';
|
|
4
|
-
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
|
-
|
|
6
|
-
// src/components/client/BillingContent/index.tsx
|
|
7
|
-
|
|
8
|
-
// src/components/server/Billing/actions.ts
|
|
9
|
-
function createHeaders(config) {
|
|
10
|
-
const headers = {
|
|
11
|
-
"Content-Type": "application/json"
|
|
12
|
-
};
|
|
13
|
-
if (config.accessToken) {
|
|
14
|
-
headers["Authorization"] = `Bearer ${config.accessToken}`;
|
|
15
|
-
}
|
|
16
|
-
if (config.apiKey) {
|
|
17
|
-
headers["X-API-Key"] = config.apiKey;
|
|
18
|
-
}
|
|
19
|
-
return headers;
|
|
20
|
-
}
|
|
21
|
-
async function fetchAPI(config, url, options = {}) {
|
|
22
|
-
try {
|
|
23
|
-
const response = await fetch(url, {
|
|
24
|
-
...options,
|
|
25
|
-
headers: {
|
|
26
|
-
...createHeaders(config),
|
|
27
|
-
...options.headers
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
return await response.json();
|
|
31
|
-
} catch (error) {
|
|
32
|
-
return {
|
|
33
|
-
success: false,
|
|
34
|
-
error: error instanceof Error ? error.message : "API request failed"
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
async function removePaymentMethod(config, customerId, paymentMethodId) {
|
|
39
|
-
const { baseUrl, projectId } = config;
|
|
40
|
-
const isStripeId = paymentMethodId.startsWith("pm_");
|
|
41
|
-
const idType = isStripeId ? "stripe" : "database";
|
|
42
|
-
const result = await fetchAPI(
|
|
43
|
-
config,
|
|
44
|
-
`${baseUrl}/billing/payment-methods/${paymentMethodId}`,
|
|
45
|
-
{
|
|
46
|
-
method: "DELETE",
|
|
47
|
-
body: JSON.stringify({
|
|
48
|
-
customer_id: customerId,
|
|
49
|
-
project_id: projectId,
|
|
50
|
-
id_type: idType,
|
|
51
|
-
test_mode: true
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
if (!result.success) {
|
|
56
|
-
return { success: false, error: result.error || "Failed to remove payment method" };
|
|
57
|
-
}
|
|
58
|
-
return { success: true };
|
|
59
|
-
}
|
|
60
|
-
async function setDefaultPaymentMethod(config, customerId, paymentMethodId) {
|
|
61
|
-
const { baseUrl, projectId } = config;
|
|
62
|
-
const isStripeId = paymentMethodId.startsWith("pm_");
|
|
63
|
-
const idType = isStripeId ? "stripe" : "database";
|
|
64
|
-
const result = await fetchAPI(
|
|
65
|
-
config,
|
|
66
|
-
`${baseUrl}/billing/payment-methods/${paymentMethodId}`,
|
|
67
|
-
{
|
|
68
|
-
method: "PUT",
|
|
69
|
-
body: JSON.stringify({
|
|
70
|
-
customer_id: customerId,
|
|
71
|
-
project_id: projectId,
|
|
72
|
-
id_type: idType,
|
|
73
|
-
is_default: true,
|
|
74
|
-
test_mode: true
|
|
75
|
-
})
|
|
76
|
-
}
|
|
77
|
-
);
|
|
78
|
-
if (!result.success) {
|
|
79
|
-
return { success: false, error: result.error || "Failed to set default payment method" };
|
|
80
|
-
}
|
|
81
|
-
return { success: true };
|
|
82
|
-
}
|
|
83
|
-
async function createSubscription(config, customerId, priceId, paymentMethodId) {
|
|
84
|
-
const { baseUrl, projectId } = config;
|
|
85
|
-
const result = await fetchAPI(
|
|
86
|
-
config,
|
|
87
|
-
`${baseUrl}/billing/subscriptions`,
|
|
88
|
-
{
|
|
89
|
-
method: "POST",
|
|
90
|
-
body: JSON.stringify({
|
|
91
|
-
customer_id: customerId,
|
|
92
|
-
price_id: priceId,
|
|
93
|
-
payment_method_id: void 0,
|
|
94
|
-
project_id: projectId,
|
|
95
|
-
sync_to_stripe: true,
|
|
96
|
-
test_mode: true
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
);
|
|
100
|
-
if (!result.success) {
|
|
101
|
-
return { success: false, error: result.error || "Failed to create subscription" };
|
|
102
|
-
}
|
|
103
|
-
return { success: true, data: result.data };
|
|
104
|
-
}
|
|
105
|
-
async function cancelSubscription(config, subscriptionId, cancelAtPeriodEnd = true) {
|
|
106
|
-
const { baseUrl, projectId } = config;
|
|
107
|
-
const result = await fetchAPI(
|
|
108
|
-
config,
|
|
109
|
-
`${baseUrl}/billing/subscriptions/${subscriptionId}/cancel`,
|
|
110
|
-
{
|
|
111
|
-
method: "POST",
|
|
112
|
-
body: JSON.stringify({
|
|
113
|
-
project_id: projectId,
|
|
114
|
-
cancel_at_period_end: cancelAtPeriodEnd,
|
|
115
|
-
cancellation_reason: "requested"
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
if (!result.success) {
|
|
120
|
-
return { success: false, error: result.error || "Failed to cancel subscription" };
|
|
121
|
-
}
|
|
122
|
-
return { success: true };
|
|
123
|
-
}
|
|
124
|
-
async function updateSubscription(config, subscriptionId, newPriceId) {
|
|
125
|
-
const { baseUrl, projectId } = config;
|
|
126
|
-
const result = await fetchAPI(
|
|
127
|
-
config,
|
|
128
|
-
`${baseUrl}/billing/subscriptions/${subscriptionId}`,
|
|
129
|
-
{
|
|
130
|
-
method: "PUT",
|
|
131
|
-
body: JSON.stringify({
|
|
132
|
-
project_id: projectId,
|
|
133
|
-
price_id: newPriceId,
|
|
134
|
-
sync_to_stripe: true
|
|
135
|
-
})
|
|
136
|
-
}
|
|
137
|
-
);
|
|
138
|
-
if (!result.success) {
|
|
139
|
-
return { success: false, error: result.error || "Failed to update subscription" };
|
|
140
|
-
}
|
|
141
|
-
return { success: true, data: result.data };
|
|
142
|
-
}
|
|
143
|
-
function UsageBar({ label, used, limit, unit = "" }) {
|
|
144
|
-
const percentage = limit > 0 ? used / limit * 100 : 0;
|
|
145
|
-
const isWarning = percentage > 80;
|
|
146
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
147
|
-
/* @__PURE__ */ jsxs("div", { className: "flex justify-between text-sm", children: [
|
|
148
|
-
/* @__PURE__ */ jsx("span", { className: "text-gray-700 dark:text-gray-300", children: label }),
|
|
149
|
-
/* @__PURE__ */ jsxs("span", { className: "text-gray-600 dark:text-gray-400", children: [
|
|
150
|
-
used.toLocaleString(),
|
|
151
|
-
unit,
|
|
152
|
-
" / ",
|
|
153
|
-
limit.toLocaleString(),
|
|
154
|
-
unit
|
|
155
|
-
] })
|
|
156
|
-
] }),
|
|
157
|
-
/* @__PURE__ */ jsx("div", { className: "w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2", children: /* @__PURE__ */ jsx(
|
|
158
|
-
"div",
|
|
159
|
-
{
|
|
160
|
-
className: `h-2 rounded-full transition-all ${isWarning ? "bg-yellow-500" : "bg-blue-600"}`,
|
|
161
|
-
style: { width: `${Math.min(percentage, 100)}%` }
|
|
162
|
-
}
|
|
163
|
-
) }),
|
|
164
|
-
/* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
|
|
165
|
-
percentage.toFixed(1),
|
|
166
|
-
"% used"
|
|
167
|
-
] })
|
|
168
|
-
] });
|
|
169
|
-
}
|
|
170
|
-
function BillingContent({
|
|
171
|
-
subscription,
|
|
172
|
-
invoices,
|
|
173
|
-
paymentMethods,
|
|
174
|
-
plans,
|
|
175
|
-
customer,
|
|
176
|
-
entitlements,
|
|
177
|
-
actionConfig,
|
|
178
|
-
className = ""
|
|
179
|
-
}) {
|
|
180
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
181
|
-
const [error, setError] = useState(null);
|
|
182
|
-
const [success, setSuccess] = useState(null);
|
|
183
|
-
const handleCancelSubscription = async () => {
|
|
184
|
-
if (!subscription) return;
|
|
185
|
-
setIsLoading(true);
|
|
186
|
-
setError(null);
|
|
187
|
-
const result = await cancelSubscription(actionConfig, subscription.id);
|
|
188
|
-
if (!result.success) {
|
|
189
|
-
setError(result.error || "Failed to cancel subscription");
|
|
190
|
-
} else {
|
|
191
|
-
setSuccess("Subscription will be canceled at the end of the billing period");
|
|
192
|
-
}
|
|
193
|
-
setIsLoading(false);
|
|
194
|
-
};
|
|
195
|
-
const handleSelectPlan = async (plan) => {
|
|
196
|
-
if (plan.current || !plan.priceId) return;
|
|
197
|
-
setIsLoading(true);
|
|
198
|
-
setError(null);
|
|
199
|
-
if (subscription) {
|
|
200
|
-
const result = await updateSubscription(actionConfig, subscription.id, plan.priceId);
|
|
201
|
-
if (!result.success) {
|
|
202
|
-
setError(result.error || "Failed to update subscription");
|
|
203
|
-
} else {
|
|
204
|
-
setSuccess(`Successfully switched to ${plan.name} plan`);
|
|
205
|
-
}
|
|
206
|
-
} else {
|
|
207
|
-
const result = await createSubscription(actionConfig, customer.id, plan.priceId);
|
|
208
|
-
if (!result.success) {
|
|
209
|
-
setError(result.error || "Failed to create subscription");
|
|
210
|
-
} else {
|
|
211
|
-
setSuccess(`Successfully subscribed to ${plan.name} plan`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
setIsLoading(false);
|
|
215
|
-
};
|
|
216
|
-
const handleRemovePaymentMethod = async (pmId) => {
|
|
217
|
-
setIsLoading(true);
|
|
218
|
-
setError(null);
|
|
219
|
-
const result = await removePaymentMethod(actionConfig, customer.id, String(pmId));
|
|
220
|
-
if (!result.success) {
|
|
221
|
-
setError(result.error || "Failed to remove payment method");
|
|
222
|
-
} else {
|
|
223
|
-
setSuccess("Payment method removed");
|
|
224
|
-
}
|
|
225
|
-
setIsLoading(false);
|
|
226
|
-
};
|
|
227
|
-
const handleSetDefaultPaymentMethod = async (pmId) => {
|
|
228
|
-
setIsLoading(true);
|
|
229
|
-
setError(null);
|
|
230
|
-
const result = await setDefaultPaymentMethod(actionConfig, customer.id, String(pmId));
|
|
231
|
-
if (!result.success) {
|
|
232
|
-
setError(result.error || "Failed to set default payment method");
|
|
233
|
-
} else {
|
|
234
|
-
setSuccess("Default payment method updated");
|
|
235
|
-
}
|
|
236
|
-
setIsLoading(false);
|
|
237
|
-
};
|
|
238
|
-
const tabs = [
|
|
239
|
-
{
|
|
240
|
-
id: "subscription",
|
|
241
|
-
label: "Subscription",
|
|
242
|
-
content: /* @__PURE__ */ jsxs("div", { className: "space-y-6 mt-6", children: [
|
|
243
|
-
error && /* @__PURE__ */ jsx("div", { className: "p-4 bg-red-50 dark:bg-red-900/20 text-red-800 dark:text-red-200 rounded-lg", children: error }),
|
|
244
|
-
success && /* @__PURE__ */ jsx("div", { className: "p-4 bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200 rounded-lg", children: success }),
|
|
245
|
-
/* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
246
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-4", children: [
|
|
247
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
248
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "Current Plan" }),
|
|
249
|
-
subscription ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
250
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
251
|
-
/* @__PURE__ */ jsx("span", { className: "text-3xl font-bold", children: subscription.price }),
|
|
252
|
-
/* @__PURE__ */ jsxs("span", { className: "text-gray-600 dark:text-gray-400", children: [
|
|
253
|
-
"/ ",
|
|
254
|
-
subscription.period
|
|
255
|
-
] })
|
|
256
|
-
] }),
|
|
257
|
-
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-gray-600 dark:text-gray-400", children: subscription.plan })
|
|
258
|
-
] }) : /* @__PURE__ */ jsx("p", { className: "text-gray-600 dark:text-gray-400", children: "No active subscription" })
|
|
259
|
-
] }),
|
|
260
|
-
subscription && /* @__PURE__ */ jsx("span", { className: `inline-flex items-center rounded-full px-3 py-1 text-sm font-medium ${subscription.status === "active" ? "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300" : subscription.status === "canceled" ? "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300" : "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300"}`, children: subscription.cancelAtPeriodEnd ? "Canceling" : subscription.status })
|
|
261
|
-
] }),
|
|
262
|
-
subscription && /* @__PURE__ */ jsx("div", { className: "space-y-3 mb-4", children: /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-sm", children: [
|
|
263
|
-
/* @__PURE__ */ jsx("span", { className: "text-gray-600 dark:text-gray-400", children: "Next billing date" }),
|
|
264
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium", children: subscription.nextBilling })
|
|
265
|
-
] }) }),
|
|
266
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
267
|
-
/* @__PURE__ */ jsx(Button, { className: "flex-1", disabled: isLoading, children: subscription ? "Change Plan" : "Choose a Plan" }),
|
|
268
|
-
subscription && !subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsx(
|
|
269
|
-
Button,
|
|
270
|
-
{
|
|
271
|
-
variant: "secondary",
|
|
272
|
-
onClick: handleCancelSubscription,
|
|
273
|
-
disabled: isLoading,
|
|
274
|
-
children: "Cancel"
|
|
275
|
-
}
|
|
276
|
-
)
|
|
277
|
-
] })
|
|
278
|
-
] }) }),
|
|
279
|
-
entitlements.length > 0 && /* @__PURE__ */ jsxs(Card, { children: [
|
|
280
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-4", children: "Current Usage" }),
|
|
281
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-4", children: entitlements.map((ent) => {
|
|
282
|
-
const featureName = ent.feature_key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
283
|
-
const entValue = typeof ent.value === "object" && ent.value?.value !== void 0 ? ent.value.value : ent.value;
|
|
284
|
-
const limit = typeof entValue === "number" ? entValue : 0;
|
|
285
|
-
const used = ent.usage_count || 0;
|
|
286
|
-
if (typeof entValue === "number" && entValue > 0) {
|
|
287
|
-
return /* @__PURE__ */ jsx(
|
|
288
|
-
UsageBar,
|
|
289
|
-
{
|
|
290
|
-
label: featureName,
|
|
291
|
-
used,
|
|
292
|
-
limit
|
|
293
|
-
},
|
|
294
|
-
ent.id
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
const isEnabled = entValue === true || entValue === "true" || entValue === "Enabled";
|
|
298
|
-
const isDisabled = entValue === false || entValue === "false";
|
|
299
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-sm", children: [
|
|
300
|
-
/* @__PURE__ */ jsx("span", { className: "text-gray-700 dark:text-gray-300", children: featureName }),
|
|
301
|
-
isEnabled || !isDisabled && entValue === void 0 ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-green-600 dark:text-green-400", children: [
|
|
302
|
-
/* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
|
|
303
|
-
"Included"
|
|
304
|
-
] }) : isDisabled ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-gray-400 dark:text-gray-500", children: [
|
|
305
|
-
/* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }),
|
|
306
|
-
"Not included"
|
|
307
|
-
] }) : /* @__PURE__ */ jsx("span", { className: "text-gray-600 dark:text-gray-400", children: String(entValue) })
|
|
308
|
-
] }, ent.id);
|
|
309
|
-
}) })
|
|
310
|
-
] })
|
|
311
|
-
] })
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
id: "plans",
|
|
315
|
-
label: "Plans",
|
|
316
|
-
content: /* @__PURE__ */ jsxs("div", { className: "space-y-6 mt-6", children: [
|
|
317
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
318
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "Choose Your Plan" }),
|
|
319
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-6", children: "Select the plan that best fits your needs. You can upgrade or downgrade at any time." })
|
|
320
|
-
] }),
|
|
321
|
-
plans.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-gray-500 dark:text-gray-400", children: "No plans available." }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: plans.map((plan) => /* @__PURE__ */ jsxs(
|
|
322
|
-
"div",
|
|
323
|
-
{
|
|
324
|
-
className: `relative rounded-lg border-2 p-6 flex flex-col ${plan.current ? "border-blue-600 dark:border-blue-500" : "border-gray-200 dark:border-neutral-700"} ${plan.popular ? "shadow-lg" : ""}`,
|
|
325
|
-
children: [
|
|
326
|
-
plan.popular && !plan.current && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx("span", { className: "bg-blue-600 text-white text-xs font-semibold px-3 py-1 rounded-full", children: "Most Popular" }) }),
|
|
327
|
-
plan.current && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx("span", { className: "bg-green-600 text-white text-xs font-semibold px-3 py-1 rounded-full", children: "Current Plan" }) }),
|
|
328
|
-
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
329
|
-
/* @__PURE__ */ jsx("h4", { className: "text-xl font-bold mb-2", children: plan.name }),
|
|
330
|
-
plan.description && /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-2", children: plan.description }),
|
|
331
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
332
|
-
/* @__PURE__ */ jsx("span", { className: "text-3xl font-bold", children: plan.price }),
|
|
333
|
-
/* @__PURE__ */ jsxs("span", { className: "text-gray-600 dark:text-gray-400", children: [
|
|
334
|
-
"/ ",
|
|
335
|
-
plan.period
|
|
336
|
-
] })
|
|
337
|
-
] })
|
|
338
|
-
] }),
|
|
339
|
-
/* @__PURE__ */ jsx("ul", { className: "space-y-3 mb-6 flex-1", children: plan.features.map((feature, idx) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2 text-sm", children: [
|
|
340
|
-
/* @__PURE__ */ jsx(
|
|
341
|
-
"svg",
|
|
342
|
-
{
|
|
343
|
-
className: "w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0 mt-0.5",
|
|
344
|
-
fill: "none",
|
|
345
|
-
stroke: "currentColor",
|
|
346
|
-
viewBox: "0 0 24 24",
|
|
347
|
-
children: /* @__PURE__ */ jsx(
|
|
348
|
-
"path",
|
|
349
|
-
{
|
|
350
|
-
strokeLinecap: "round",
|
|
351
|
-
strokeLinejoin: "round",
|
|
352
|
-
strokeWidth: 2,
|
|
353
|
-
d: "M5 13l4 4L19 7"
|
|
354
|
-
}
|
|
355
|
-
)
|
|
356
|
-
}
|
|
357
|
-
),
|
|
358
|
-
/* @__PURE__ */ jsx("span", { className: "text-gray-700 dark:text-gray-300", children: feature })
|
|
359
|
-
] }, idx)) }),
|
|
360
|
-
/* @__PURE__ */ jsx(
|
|
361
|
-
Button,
|
|
362
|
-
{
|
|
363
|
-
className: "w-full",
|
|
364
|
-
disabled: plan.current || isLoading,
|
|
365
|
-
variant: plan.current ? "secondary" : "primary",
|
|
366
|
-
onClick: () => handleSelectPlan(plan),
|
|
367
|
-
children: plan.current ? "Current Plan" : subscription ? "Switch Plan" : "Select Plan"
|
|
368
|
-
}
|
|
369
|
-
)
|
|
370
|
-
]
|
|
371
|
-
},
|
|
372
|
-
plan.id
|
|
373
|
-
)) })
|
|
374
|
-
] })
|
|
375
|
-
},
|
|
376
|
-
{
|
|
377
|
-
id: "invoices",
|
|
378
|
-
label: "Invoices",
|
|
379
|
-
content: /* @__PURE__ */ jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
380
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "Invoice History" }),
|
|
381
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-6", children: "View and download your past invoices" }),
|
|
382
|
-
invoices.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-gray-500 dark:text-gray-400", children: "No invoices yet." }) : /* @__PURE__ */ jsx("div", { className: "space-y-3", children: invoices.map((invoice) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border border-gray-200 dark:border-neutral-700 rounded-lg hover:bg-gray-50 dark:hover:bg-neutral-800 transition-colors", children: [
|
|
383
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
384
|
-
/* @__PURE__ */ jsx("div", { className: "h-10 w-10 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-blue-600 dark:text-blue-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) }),
|
|
385
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
386
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
387
|
-
/* @__PURE__ */ jsx("p", { className: "font-medium text-sm", children: invoice.id }),
|
|
388
|
-
/* @__PURE__ */ jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${invoice.status === "paid" ? "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300" : invoice.status === "open" ? "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300" : "bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-300"}`, children: invoice.status })
|
|
389
|
-
] }),
|
|
390
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-600 dark:text-gray-400", children: invoice.date })
|
|
391
|
-
] })
|
|
392
|
-
] }),
|
|
393
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
394
|
-
/* @__PURE__ */ jsx("p", { className: "font-semibold", children: invoice.amount }),
|
|
395
|
-
invoice.url && invoice.url !== "#" && /* @__PURE__ */ jsx(
|
|
396
|
-
Button,
|
|
397
|
-
{
|
|
398
|
-
variant: "secondary",
|
|
399
|
-
size: "sm",
|
|
400
|
-
onClick: () => window.open(invoice.url, "_blank"),
|
|
401
|
-
children: "Download"
|
|
402
|
-
}
|
|
403
|
-
)
|
|
404
|
-
] })
|
|
405
|
-
] }, invoice.id)) })
|
|
406
|
-
] }) })
|
|
407
|
-
},
|
|
408
|
-
{
|
|
409
|
-
id: "payment",
|
|
410
|
-
label: "Payment Method",
|
|
411
|
-
content: /* @__PURE__ */ jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
412
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "Payment Methods" }),
|
|
413
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-6", children: "Manage your payment methods" }),
|
|
414
|
-
paymentMethods.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8 border border-dashed border-gray-300 dark:border-neutral-700 rounded-lg", children: [
|
|
415
|
-
/* @__PURE__ */ jsx("p", { className: "text-gray-500 dark:text-gray-400 mb-4", children: "No payment methods on file" }),
|
|
416
|
-
/* @__PURE__ */ jsx(Button, { children: "Add Payment Method" })
|
|
417
|
-
] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
418
|
-
paymentMethods.map((pm) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border border-gray-200 dark:border-neutral-700 rounded-lg", children: [
|
|
419
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
420
|
-
/* @__PURE__ */ jsx("div", { className: "h-10 w-10 rounded-full bg-gray-100 dark:bg-neutral-800 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-gray-600 dark:text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" }) }) }),
|
|
421
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
422
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
423
|
-
/* @__PURE__ */ jsxs("p", { className: "font-medium text-sm", children: [
|
|
424
|
-
pm.card_brand || pm.type,
|
|
425
|
-
" \u2022\u2022\u2022\u2022 ",
|
|
426
|
-
pm.card_last4 || pm.bank_last4 || "****"
|
|
427
|
-
] }),
|
|
428
|
-
pm.is_default && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full bg-blue-100 dark:bg-blue-900/30 px-2 py-0.5 text-xs font-medium text-blue-800 dark:text-blue-300", children: "Default" })
|
|
429
|
-
] }),
|
|
430
|
-
pm.card_exp_month && pm.card_exp_year && /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-600 dark:text-gray-400", children: [
|
|
431
|
-
"Expires ",
|
|
432
|
-
pm.card_exp_month,
|
|
433
|
-
"/",
|
|
434
|
-
pm.card_exp_year
|
|
435
|
-
] })
|
|
436
|
-
] })
|
|
437
|
-
] }),
|
|
438
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
439
|
-
!pm.is_default && /* @__PURE__ */ jsx(
|
|
440
|
-
Button,
|
|
441
|
-
{
|
|
442
|
-
variant: "secondary",
|
|
443
|
-
size: "sm",
|
|
444
|
-
onClick: () => handleSetDefaultPaymentMethod(pm.id),
|
|
445
|
-
disabled: isLoading,
|
|
446
|
-
children: "Set Default"
|
|
447
|
-
}
|
|
448
|
-
),
|
|
449
|
-
/* @__PURE__ */ jsx(
|
|
450
|
-
Button,
|
|
451
|
-
{
|
|
452
|
-
variant: "secondary",
|
|
453
|
-
size: "sm",
|
|
454
|
-
onClick: () => handleRemovePaymentMethod(pm.id),
|
|
455
|
-
disabled: isLoading,
|
|
456
|
-
children: "Remove"
|
|
457
|
-
}
|
|
458
|
-
)
|
|
459
|
-
] })
|
|
460
|
-
] }, pm.id)),
|
|
461
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", className: "w-full mt-4", children: "Add Payment Method" })
|
|
462
|
-
] })
|
|
463
|
-
] }) })
|
|
464
|
-
}
|
|
465
|
-
];
|
|
466
|
-
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(Tabs, { tabs, defaultIndex: 0 }) });
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
export { BillingContent };
|
|
470
|
-
//# sourceMappingURL=chunk-IKBW2JFX.js.map
|
|
471
|
-
//# sourceMappingURL=chunk-IKBW2JFX.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/server/Billing/actions.ts","../src/components/client/BillingContent/index.tsx"],"names":[],"mappings":"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","file":"chunk-IKBW2JFX.js","sourcesContent":["'use server';\n\n/**\n * Billing Server Actions\n *\n * Server actions for billing mutations (add payment method, subscribe, cancel, etc.)\n * These actions can be called from client components.\n */\n\nimport type { PaymentMethod, Subscription } from './types';\n\ninterface ActionConfig {\n baseUrl: string;\n apiKey?: string;\n accessToken?: string;\n projectId: number;\n}\n\ninterface ActionResult<T = void> {\n success: boolean;\n data?: T;\n error?: string;\n}\n\nfunction createHeaders(config: ActionConfig): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json'\n };\n\n if (config.accessToken) {\n headers['Authorization'] = `Bearer ${config.accessToken}`;\n }\n\n if (config.apiKey) {\n headers['X-API-Key'] = config.apiKey;\n }\n\n return headers;\n}\n\nasync function fetchAPI<T>(\n config: ActionConfig,\n url: string,\n options: RequestInit = {}\n): Promise<{ success: boolean; data?: T; error?: string }> {\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n ...createHeaders(config),\n ...options.headers as Record<string, string>,\n },\n });\n\n return await response.json();\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'API request failed'\n };\n }\n}\n\n/**\n * Add a payment method for a customer\n */\nexport async function addPaymentMethod(\n config: ActionConfig,\n customerId: number,\n stripePaymentMethodId: string,\n setAsDefault: boolean = false\n): Promise<ActionResult<PaymentMethod>> {\n const { baseUrl, projectId } = config;\n\n const result = await fetchAPI<PaymentMethod>(\n config,\n `${baseUrl}/billing/customers/${customerId}/payment-methods`,\n {\n method: 'POST',\n body: JSON.stringify({\n project_id: projectId,\n type: 'card',\n stripe_payment_method_id: stripePaymentMethodId,\n set_as_default: setAsDefault\n })\n }\n );\n\n if (!result.success) {\n return { success: false, error: result.error || 'Failed to add payment method' };\n }\n\n return { success: true, data: result.data };\n}\n\n/**\n * Remove a payment method\n */\nexport async function removePaymentMethod(\n config: ActionConfig,\n customerId: number,\n paymentMethodId: string\n): Promise<ActionResult> {\n const { baseUrl, projectId } = config;\n\n const isStripeId = paymentMethodId.startsWith('pm_');\n const idType = isStripeId ? 'stripe' : 'database';\n\n const result = await fetchAPI(\n config,\n `${baseUrl}/billing/payment-methods/${paymentMethodId}`,\n {\n method: 'DELETE',\n body: JSON.stringify({\n customer_id: customerId,\n project_id: projectId,\n id_type: idType,\n test_mode: true\n })\n }\n );\n\n if (!result.success) {\n return { success: false, error: result.error || 'Failed to remove payment method' };\n }\n\n return { success: true };\n}\n\n/**\n * Set a payment method as default\n */\nexport async function setDefaultPaymentMethod(\n config: ActionConfig,\n customerId: number,\n paymentMethodId: string\n): Promise<ActionResult> {\n const { baseUrl, projectId } = config;\n\n const isStripeId = paymentMethodId.startsWith('pm_');\n const idType = isStripeId ? 'stripe' : 'database';\n\n const result = await fetchAPI(\n config,\n `${baseUrl}/billing/payment-methods/${paymentMethodId}`,\n {\n method: 'PUT',\n body: JSON.stringify({\n customer_id: customerId,\n project_id: projectId,\n id_type: idType,\n is_default: true,\n test_mode: true\n })\n }\n );\n\n if (!result.success) {\n return { success: false, error: result.error || 'Failed to set default payment method' };\n }\n\n return { success: true };\n}\n\n/**\n * Create a subscription\n */\nexport async function createSubscription(\n config: ActionConfig,\n customerId: number,\n priceId: number,\n paymentMethodId?: string\n): Promise<ActionResult<Subscription>> {\n const { baseUrl, projectId } = config;\n\n const result = await fetchAPI<Subscription>(\n config,\n `${baseUrl}/billing/subscriptions`,\n {\n method: 'POST',\n body: JSON.stringify({\n customer_id: customerId,\n price_id: priceId,\n payment_method_id: paymentMethodId || undefined,\n project_id: projectId,\n sync_to_stripe: true,\n test_mode: true\n })\n }\n );\n\n if (!result.success) {\n return { success: false, error: result.error || 'Failed to create subscription' };\n }\n\n return { success: true, data: result.data };\n}\n\n/**\n * Cancel a subscription\n */\nexport async function cancelSubscription(\n config: ActionConfig,\n subscriptionId: number,\n cancelAtPeriodEnd: boolean = true\n): Promise<ActionResult> {\n const { baseUrl, projectId } = config;\n\n const result = await fetchAPI(\n config,\n `${baseUrl}/billing/subscriptions/${subscriptionId}/cancel`,\n {\n method: 'POST',\n body: JSON.stringify({\n project_id: projectId,\n cancel_at_period_end: cancelAtPeriodEnd,\n cancellation_reason: 'requested'\n })\n }\n );\n\n if (!result.success) {\n return { success: false, error: result.error || 'Failed to cancel subscription' };\n }\n\n return { success: true };\n}\n\n/**\n * Update subscription (change plan)\n */\nexport async function updateSubscription(\n config: ActionConfig,\n subscriptionId: number,\n newPriceId: number\n): Promise<ActionResult<Subscription>> {\n const { baseUrl, projectId } = config;\n\n const result = await fetchAPI<Subscription>(\n config,\n `${baseUrl}/billing/subscriptions/${subscriptionId}`,\n {\n method: 'PUT',\n body: JSON.stringify({\n project_id: projectId,\n price_id: newPriceId,\n sync_to_stripe: true\n })\n }\n );\n\n if (!result.success) {\n return { success: false, error: result.error || 'Failed to update subscription' };\n }\n\n return { success: true, data: result.data };\n}\n\n/**\n * Resume a canceled subscription\n */\nexport async function resumeSubscription(\n config: ActionConfig,\n subscriptionId: number\n): Promise<ActionResult<Subscription>> {\n const { baseUrl, projectId } = config;\n\n const result = await fetchAPI<Subscription>(\n config,\n `${baseUrl}/billing/subscriptions/${subscriptionId}/resume`,\n {\n method: 'POST',\n body: JSON.stringify({\n project_id: projectId\n })\n }\n );\n\n if (!result.success) {\n return { success: false, error: result.error || 'Failed to resume subscription' };\n }\n\n return { success: true, data: result.data };\n}\n","'use client'\n\nimport { useState } from 'react'\nimport { Button, Tabs, Card } from '@marcoschwartz/lite-ui'\nimport {\n removePaymentMethod,\n setDefaultPaymentMethod,\n createSubscription,\n cancelSubscription,\n updateSubscription\n} from '../../server/Billing/actions'\nimport type { Customer, PaymentMethod, Entitlement } from '../../server/Billing/types'\n\n// Usage bar component for displaying entitlement limits (like apteva-app)\nfunction UsageBar({ label, used, limit, unit = \"\" }: { label: string; used: number; limit: number; unit?: string }) {\n const percentage = limit > 0 ? (used / limit) * 100 : 0;\n const isWarning = percentage > 80;\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-gray-700 dark:text-gray-300\">{label}</span>\n <span className=\"text-gray-600 dark:text-gray-400\">\n {used.toLocaleString()}{unit} / {limit.toLocaleString()}{unit}\n </span>\n </div>\n <div className=\"w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2\">\n <div\n className={`h-2 rounded-full transition-all ${\n isWarning ? 'bg-yellow-500' : 'bg-blue-600'\n }`}\n style={{ width: `${Math.min(percentage, 100)}%` }}\n />\n </div>\n <div className=\"text-xs text-gray-500 dark:text-gray-400\">\n {percentage.toFixed(1)}% used\n </div>\n </div>\n );\n}\n\ninterface ActionConfig {\n baseUrl: string;\n apiKey?: string;\n accessToken?: string;\n projectId: number;\n}\n\ninterface SubscriptionDisplay {\n id: number;\n plan: string;\n status: string;\n price: string;\n period: string;\n nextBilling: string;\n cancelAtPeriodEnd?: boolean;\n}\n\ninterface InvoiceDisplay {\n id: string;\n date: string;\n amount: string;\n status: string;\n url: string;\n}\n\ninterface PlanDisplay {\n id: number;\n priceId: number;\n name: string;\n description?: string;\n price: string;\n period: string;\n features: string[];\n current: boolean;\n popular?: boolean;\n}\n\ninterface BillingContentProps {\n subscription: SubscriptionDisplay | null;\n invoices: InvoiceDisplay[];\n paymentMethods: PaymentMethod[];\n plans: PlanDisplay[];\n customer: Customer;\n entitlements: Entitlement[];\n actionConfig: ActionConfig;\n className?: string;\n}\n\nexport function BillingContent({\n subscription,\n invoices,\n paymentMethods,\n plans,\n customer,\n entitlements,\n actionConfig,\n className = ''\n}: BillingContentProps) {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState<string | null>(null);\n\n const handleCancelSubscription = async () => {\n if (!subscription) return;\n\n setIsLoading(true);\n setError(null);\n\n const result = await cancelSubscription(actionConfig, subscription.id);\n\n if (!result.success) {\n setError(result.error || 'Failed to cancel subscription');\n } else {\n setSuccess('Subscription will be canceled at the end of the billing period');\n }\n\n setIsLoading(false);\n };\n\n const handleSelectPlan = async (plan: PlanDisplay) => {\n if (plan.current || !plan.priceId) return;\n\n setIsLoading(true);\n setError(null);\n\n if (subscription) {\n // Update existing subscription\n const result = await updateSubscription(actionConfig, subscription.id, plan.priceId);\n if (!result.success) {\n setError(result.error || 'Failed to update subscription');\n } else {\n setSuccess(`Successfully switched to ${plan.name} plan`);\n }\n } else {\n // Create new subscription\n const result = await createSubscription(actionConfig, customer.id, plan.priceId);\n if (!result.success) {\n setError(result.error || 'Failed to create subscription');\n } else {\n setSuccess(`Successfully subscribed to ${plan.name} plan`);\n }\n }\n\n setIsLoading(false);\n };\n\n const handleRemovePaymentMethod = async (pmId: number) => {\n setIsLoading(true);\n setError(null);\n\n const result = await removePaymentMethod(actionConfig, customer.id, String(pmId));\n\n if (!result.success) {\n setError(result.error || 'Failed to remove payment method');\n } else {\n setSuccess('Payment method removed');\n }\n\n setIsLoading(false);\n };\n\n const handleSetDefaultPaymentMethod = async (pmId: number) => {\n setIsLoading(true);\n setError(null);\n\n const result = await setDefaultPaymentMethod(actionConfig, customer.id, String(pmId));\n\n if (!result.success) {\n setError(result.error || 'Failed to set default payment method');\n } else {\n setSuccess('Default payment method updated');\n }\n\n setIsLoading(false);\n };\n\n const tabs = [\n {\n id: 'subscription',\n label: 'Subscription',\n content: (\n <div className=\"space-y-6 mt-6\">\n {/* Status Messages */}\n {error && (\n <div className=\"p-4 bg-red-50 dark:bg-red-900/20 text-red-800 dark:text-red-200 rounded-lg\">\n {error}\n </div>\n )}\n {success && (\n <div className=\"p-4 bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200 rounded-lg\">\n {success}\n </div>\n )}\n\n {/* Current Plan */}\n <Card>\n <div>\n <div className=\"flex items-start justify-between mb-4\">\n <div>\n <h3 className=\"text-lg font-semibold mb-2\">Current Plan</h3>\n {subscription ? (\n <>\n <div className=\"flex items-baseline gap-2\">\n <span className=\"text-3xl font-bold\">{subscription.price}</span>\n <span className=\"text-gray-600 dark:text-gray-400\">/ {subscription.period}</span>\n </div>\n <p className=\"mt-2 text-sm text-gray-600 dark:text-gray-400\">\n {subscription.plan}\n </p>\n </>\n ) : (\n <p className=\"text-gray-600 dark:text-gray-400\">No active subscription</p>\n )}\n </div>\n {subscription && (\n <span className={`inline-flex items-center rounded-full px-3 py-1 text-sm font-medium ${\n subscription.status === 'active'\n ? 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300'\n : subscription.status === 'canceled'\n ? 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300'\n : 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300'\n }`}>\n {subscription.cancelAtPeriodEnd ? 'Canceling' : subscription.status}\n </span>\n )}\n </div>\n\n {subscription && (\n <div className=\"space-y-3 mb-4\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-gray-600 dark:text-gray-400\">Next billing date</span>\n <span className=\"font-medium\">{subscription.nextBilling}</span>\n </div>\n </div>\n )}\n\n <div className=\"flex gap-3\">\n <Button className=\"flex-1\" disabled={isLoading}>\n {subscription ? 'Change Plan' : 'Choose a Plan'}\n </Button>\n {subscription && !subscription.cancelAtPeriodEnd && (\n <Button\n variant=\"secondary\"\n onClick={handleCancelSubscription}\n disabled={isLoading}\n >\n Cancel\n </Button>\n )}\n </div>\n </div>\n </Card>\n\n {/* Entitlements / Usage */}\n {entitlements.length > 0 && (\n <Card>\n <h3 className=\"text-lg font-semibold mb-4\">Current Usage</h3>\n <div className=\"space-y-4\">\n {entitlements.map((ent) => {\n // Format feature name: replace underscores with spaces and capitalize\n const featureName = ent.feature_key\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, c => c.toUpperCase());\n\n // Get entitlement value (limit)\n const entValue = typeof ent.value === 'object' && ent.value?.value !== undefined\n ? ent.value.value\n : ent.value;\n const limit = typeof entValue === 'number' ? entValue : 0;\n\n // Get usage count if available\n const used = ent.usage_count || 0;\n\n // If it's a numeric limit, show as progress bar\n if (typeof entValue === 'number' && entValue > 0) {\n return (\n <UsageBar\n key={ent.id}\n label={featureName}\n used={used}\n limit={limit}\n />\n );\n }\n\n // For boolean/non-numeric entitlements, show as simple row with icons\n const isEnabled = entValue === true || entValue === 'true' || entValue === 'Enabled';\n const isDisabled = entValue === false || entValue === 'false';\n\n return (\n <div key={ent.id} className=\"flex justify-between items-center text-sm\">\n <span className=\"text-gray-700 dark:text-gray-300\">{featureName}</span>\n {isEnabled || (!isDisabled && entValue === undefined) ? (\n <span className=\"flex items-center gap-1.5 text-green-600 dark:text-green-400\">\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 13l4 4L19 7\" />\n </svg>\n Included\n </span>\n ) : isDisabled ? (\n <span className=\"flex items-center gap-1.5 text-gray-400 dark:text-gray-500\">\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Not included\n </span>\n ) : (\n <span className=\"text-gray-600 dark:text-gray-400\">\n {String(entValue)}\n </span>\n )}\n </div>\n );\n })}\n </div>\n </Card>\n )}\n </div>\n ),\n },\n {\n id: 'plans',\n label: 'Plans',\n content: (\n <div className=\"space-y-6 mt-6\">\n <div>\n <h3 className=\"text-lg font-semibold mb-2\">Choose Your Plan</h3>\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-6\">\n Select the plan that best fits your needs. You can upgrade or downgrade at any time.\n </p>\n </div>\n\n {plans.length === 0 ? (\n <p className=\"text-gray-500 dark:text-gray-400\">No plans available.</p>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n {plans.map((plan) => (\n <div\n key={plan.id}\n className={`relative rounded-lg border-2 p-6 flex flex-col ${\n plan.current\n ? 'border-blue-600 dark:border-blue-500'\n : 'border-gray-200 dark:border-neutral-700'\n } ${plan.popular ? 'shadow-lg' : ''}`}\n >\n {plan.popular && !plan.current && (\n <div className=\"absolute -top-3 left-1/2 -translate-x-1/2\">\n <span className=\"bg-blue-600 text-white text-xs font-semibold px-3 py-1 rounded-full\">\n Most Popular\n </span>\n </div>\n )}\n {plan.current && (\n <div className=\"absolute -top-3 left-1/2 -translate-x-1/2\">\n <span className=\"bg-green-600 text-white text-xs font-semibold px-3 py-1 rounded-full\">\n Current Plan\n </span>\n </div>\n )}\n\n <div className=\"mb-6\">\n <h4 className=\"text-xl font-bold mb-2\">{plan.name}</h4>\n {plan.description && (\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-2\">{plan.description}</p>\n )}\n <div className=\"flex items-baseline gap-2\">\n <span className=\"text-3xl font-bold\">{plan.price}</span>\n <span className=\"text-gray-600 dark:text-gray-400\">/ {plan.period}</span>\n </div>\n </div>\n\n <ul className=\"space-y-3 mb-6 flex-1\">\n {plan.features.map((feature, idx) => (\n <li key={idx} className=\"flex items-start gap-2 text-sm\">\n <svg\n className=\"w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0 mt-0.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n <span className=\"text-gray-700 dark:text-gray-300\">{feature}</span>\n </li>\n ))}\n </ul>\n\n <Button\n className=\"w-full\"\n disabled={plan.current || isLoading}\n variant={plan.current ? 'secondary' : 'primary'}\n onClick={() => handleSelectPlan(plan)}\n >\n {plan.current ? 'Current Plan' : subscription ? 'Switch Plan' : 'Select Plan'}\n </Button>\n </div>\n ))}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'invoices',\n label: 'Invoices',\n content: (\n <div className=\"mt-6\">\n <Card>\n <h3 className=\"text-lg font-semibold mb-2\">Invoice History</h3>\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-6\">\n View and download your past invoices\n </p>\n\n {invoices.length === 0 ? (\n <p className=\"text-gray-500 dark:text-gray-400\">No invoices yet.</p>\n ) : (\n <div className=\"space-y-3\">\n {invoices.map((invoice) => (\n <div key={invoice.id} className=\"flex items-center justify-between p-4 border border-gray-200 dark:border-neutral-700 rounded-lg hover:bg-gray-50 dark:hover:bg-neutral-800 transition-colors\">\n <div className=\"flex items-center gap-4\">\n <div className=\"h-10 w-10 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center\">\n <svg className=\"w-5 h-5 text-blue-600 dark:text-blue-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-sm\">{invoice.id}</p>\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${\n invoice.status === 'paid'\n ? 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300'\n : invoice.status === 'open'\n ? 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300'\n : 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-300'\n }`}>\n {invoice.status}\n </span>\n </div>\n <p className=\"text-xs text-gray-600 dark:text-gray-400\">{invoice.date}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-4\">\n <p className=\"font-semibold\">{invoice.amount}</p>\n {invoice.url && invoice.url !== '#' && (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => window.open(invoice.url, '_blank')}\n >\n Download\n </Button>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n </Card>\n </div>\n ),\n },\n {\n id: 'payment',\n label: 'Payment Method',\n content: (\n <div className=\"mt-6\">\n <Card>\n <h3 className=\"text-lg font-semibold mb-2\">Payment Methods</h3>\n <p className=\"text-sm text-gray-600 dark:text-gray-400 mb-6\">\n Manage your payment methods\n </p>\n\n {paymentMethods.length === 0 ? (\n <div className=\"text-center py-8 border border-dashed border-gray-300 dark:border-neutral-700 rounded-lg\">\n <p className=\"text-gray-500 dark:text-gray-400 mb-4\">No payment methods on file</p>\n <Button>Add Payment Method</Button>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {paymentMethods.map((pm) => (\n <div key={pm.id} className=\"flex items-center justify-between p-4 border border-gray-200 dark:border-neutral-700 rounded-lg\">\n <div className=\"flex items-center gap-4\">\n <div className=\"h-10 w-10 rounded-full bg-gray-100 dark:bg-neutral-800 flex items-center justify-center\">\n <svg className=\"w-5 h-5 text-gray-600 dark:text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-sm\">\n {pm.card_brand || pm.type} •••• {pm.card_last4 || pm.bank_last4 || '****'}\n </p>\n {pm.is_default && (\n <span className=\"inline-flex items-center rounded-full bg-blue-100 dark:bg-blue-900/30 px-2 py-0.5 text-xs font-medium text-blue-800 dark:text-blue-300\">\n Default\n </span>\n )}\n </div>\n {pm.card_exp_month && pm.card_exp_year && (\n <p className=\"text-xs text-gray-600 dark:text-gray-400\">\n Expires {pm.card_exp_month}/{pm.card_exp_year}\n </p>\n )}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {!pm.is_default && (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => handleSetDefaultPaymentMethod(pm.id)}\n disabled={isLoading}\n >\n Set Default\n </Button>\n )}\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => handleRemovePaymentMethod(pm.id)}\n disabled={isLoading}\n >\n Remove\n </Button>\n </div>\n </div>\n ))}\n\n <Button variant=\"secondary\" className=\"w-full mt-4\">\n Add Payment Method\n </Button>\n </div>\n )}\n </Card>\n </div>\n ),\n },\n ]\n\n return (\n <div className={className}>\n <Tabs tabs={tabs} defaultIndex={0} />\n </div>\n )\n}\n"]}
|