@zuplo/zudoku-plugin-monetization 0.0.31 → 0.0.33
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 +2 -3
- package/dist/index.mjs +517 -192
- package/package.json +6 -6
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import * as zudoku from "zudoku";
|
|
1
|
+
import * as _$zudoku from "zudoku";
|
|
3
2
|
|
|
4
3
|
//#region src/MonetizationContext.d.ts
|
|
5
4
|
interface MonetizationConfig {
|
|
@@ -12,6 +11,6 @@ interface MonetizationConfig {
|
|
|
12
11
|
}
|
|
13
12
|
//#endregion
|
|
14
13
|
//#region src/ZuploMonetizationPlugin.d.ts
|
|
15
|
-
declare const zuploMonetizationPlugin: (options?: MonetizationConfig | undefined) => zudoku.ZudokuPlugin;
|
|
14
|
+
declare const zuploMonetizationPlugin: (options?: MonetizationConfig | undefined) => _$zudoku.ZudokuPlugin;
|
|
16
15
|
//#endregion
|
|
17
16
|
export { zuploMonetizationPlugin };
|
package/dist/index.mjs
CHANGED
|
@@ -6,10 +6,10 @@ import { useAuth, useZudoku } from "zudoku/hooks";
|
|
|
6
6
|
import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient, useSuspenseQuery } from "zudoku/react-query";
|
|
7
7
|
import { Link as Link$1, Outlet, useLocation, useNavigate, useSearchParams } from "zudoku/router";
|
|
8
8
|
import { Alert, AlertAction, AlertDescription, AlertTitle } from "zudoku/ui/Alert";
|
|
9
|
-
import { Card, CardContent, CardHeader, CardTitle } from "zudoku/ui/Card";
|
|
9
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "zudoku/ui/Card";
|
|
10
10
|
import { Separator } from "zudoku/ui/Separator";
|
|
11
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
11
|
import { parse } from "tinyduration";
|
|
12
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { Button as Button$1 } from "zudoku/ui/Button";
|
|
14
14
|
import { Skeleton } from "zudoku/ui/Skeleton";
|
|
15
15
|
import { DismissibleAlert, DismissibleAlertAction } from "zudoku/ui/DismissibleAlert";
|
|
@@ -23,78 +23,6 @@ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent,
|
|
|
23
23
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "zudoku/ui/Dialog";
|
|
24
24
|
import { Input } from "zudoku/ui/Input";
|
|
25
25
|
import { Progress } from "zudoku/ui/Progress";
|
|
26
|
-
|
|
27
|
-
//#region src/components/FeatureItem.tsx
|
|
28
|
-
const FeatureItem = ({ feature, className }) => {
|
|
29
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
30
|
-
className: cn("flex items-start gap-2", className),
|
|
31
|
-
children: [/* @__PURE__ */ jsx(CheckIcon, { className: "w-4 h-4 text-primary shrink-0 mt-0.5" }), /* @__PURE__ */ jsx("div", {
|
|
32
|
-
className: "text-sm",
|
|
33
|
-
children: feature.value ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
34
|
-
/* @__PURE__ */ jsxs("span", {
|
|
35
|
-
className: "font-medium",
|
|
36
|
-
children: [feature.name, ":"]
|
|
37
|
-
}),
|
|
38
|
-
" ",
|
|
39
|
-
feature.value
|
|
40
|
-
] }) : feature.name
|
|
41
|
-
})]
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/components/QuotaItem.tsx
|
|
47
|
-
const QuotaItem = ({ quota, className }) => {
|
|
48
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
49
|
-
className: cn("flex items-start gap-2", className),
|
|
50
|
-
children: [/* @__PURE__ */ jsx(CheckIcon, { className: "w-4 h-4 text-primary shrink-0 mt-0.5" }), /* @__PURE__ */ jsxs("div", {
|
|
51
|
-
className: "text-sm",
|
|
52
|
-
children: [
|
|
53
|
-
/* @__PURE__ */ jsxs("span", {
|
|
54
|
-
className: "font-medium",
|
|
55
|
-
children: [quota.name, ":"]
|
|
56
|
-
}),
|
|
57
|
-
" ",
|
|
58
|
-
quota.limit.toLocaleString(),
|
|
59
|
-
" / ",
|
|
60
|
-
quota.period,
|
|
61
|
-
quota.overagePrice && /* @__PURE__ */ jsxs("div", {
|
|
62
|
-
className: "text-xs text-muted-foreground mt-0.5",
|
|
63
|
-
children: [
|
|
64
|
-
"+",
|
|
65
|
-
quota.overagePrice,
|
|
66
|
-
" after quota"
|
|
67
|
-
]
|
|
68
|
-
})
|
|
69
|
-
]
|
|
70
|
-
})]
|
|
71
|
-
});
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
//#endregion
|
|
75
|
-
//#region src/hooks/useDeploymentName.ts
|
|
76
|
-
const useDeploymentName = () => {
|
|
77
|
-
const deploymentName = useZudoku().env.ZUPLO_PUBLIC_DEPLOYMENT_NAME;
|
|
78
|
-
if (!deploymentName) throw new Error("ZUPLO_PUBLIC_DEPLOYMENT_NAME is not set");
|
|
79
|
-
return deploymentName;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region src/hooks/usePurchaseDetails.ts
|
|
84
|
-
const usePurchaseDetails = (planId) => {
|
|
85
|
-
const zudoku = useZudoku();
|
|
86
|
-
return useSuspenseQuery({
|
|
87
|
-
queryKey: [`/v3/zudoku-metering/${useDeploymentName()}/plans/${planId}/purchase-details`],
|
|
88
|
-
meta: { context: zudoku }
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
//#endregion
|
|
93
|
-
//#region src/MonetizationContext.tsx
|
|
94
|
-
const MonetizationContext = createContext({});
|
|
95
|
-
const useMonetizationConfig = () => use(MonetizationContext);
|
|
96
|
-
|
|
97
|
-
//#endregion
|
|
98
26
|
//#region src/utils/formatDuration.ts
|
|
99
27
|
const formatDuration = (iso) => {
|
|
100
28
|
try {
|
|
@@ -146,7 +74,6 @@ const formatDurationAdjective = (iso) => {
|
|
|
146
74
|
return "billing period";
|
|
147
75
|
}
|
|
148
76
|
};
|
|
149
|
-
|
|
150
77
|
//#endregion
|
|
151
78
|
//#region src/utils/formatPrice.ts
|
|
152
79
|
const formatPrice = (amount, currency) => new Intl.NumberFormat("en-US", {
|
|
@@ -171,7 +98,31 @@ const formatMinorCurrencyAmount = (amountInMinorUnits, currency) => {
|
|
|
171
98
|
maximumFractionDigits: fractionDigits
|
|
172
99
|
}).format(amountInMinorUnits / divisor);
|
|
173
100
|
};
|
|
174
|
-
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/utils/formatTieredPriceBreakdown.ts
|
|
103
|
+
const parseAmount = (value) => {
|
|
104
|
+
if (!value) return;
|
|
105
|
+
const parsed = Number.parseFloat(value);
|
|
106
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
107
|
+
};
|
|
108
|
+
const formatTieredPriceBreakdown = (opts) => {
|
|
109
|
+
const { tiers, currency, unitLabel, includedLabel, omitIncludedUpToAmount } = opts;
|
|
110
|
+
if (!tiers || tiers.length <= 1) return;
|
|
111
|
+
const lines = [];
|
|
112
|
+
let lastUpTo;
|
|
113
|
+
for (const tier of tiers) {
|
|
114
|
+
const upTo = parseAmount(tier.upToAmount);
|
|
115
|
+
const unit = parseAmount(tier.unitPriceAmount) ?? 0;
|
|
116
|
+
const flat = parseAmount(tier.flatPriceAmount) ?? 0;
|
|
117
|
+
const prefix = upTo != null ? `Up to ${upTo.toLocaleString("en-US")}` : lastUpTo != null ? `Over ${lastUpTo.toLocaleString("en-US")}` : `Per ${unitLabel}`;
|
|
118
|
+
const unitPart = unit > 0 ? `${formatPrice(unit, currency)}/${unitLabel}` : includedLabel;
|
|
119
|
+
const flatPart = flat > 0 ? ` + ${formatPrice(flat, currency)} base` : "";
|
|
120
|
+
const line = `${prefix}: ${unitPart}${flatPart}`;
|
|
121
|
+
if (omitIncludedUpToAmount != null && upTo != null && upTo === omitIncludedUpToAmount && unitPart === includedLabel && flatPart === "") {} else lines.push(line);
|
|
122
|
+
if (upTo != null) lastUpTo = upTo;
|
|
123
|
+
}
|
|
124
|
+
return lines.length > 0 ? lines : void 0;
|
|
125
|
+
};
|
|
175
126
|
//#endregion
|
|
176
127
|
//#region src/utils/categorizeRateCards.ts
|
|
177
128
|
const categorizeRateCards = (rateCards, options) => {
|
|
@@ -183,20 +134,30 @@ const categorizeRateCards = (rateCards, options) => {
|
|
|
183
134
|
if (!et) continue;
|
|
184
135
|
if (et.type === "metered" && et.issueAfterReset != null) {
|
|
185
136
|
let overagePrice;
|
|
186
|
-
|
|
137
|
+
let tierPrices;
|
|
138
|
+
if (rc.price?.type === "tiered" && rc.price.tiers) {
|
|
139
|
+
const unitLabel = units?.[rc.key] ?? units?.[rc.featureKey ?? ""] ?? "unit";
|
|
140
|
+
tierPrices = formatTieredPriceBreakdown({
|
|
141
|
+
tiers: rc.price.tiers.map((t) => ({
|
|
142
|
+
upToAmount: t.upToAmount,
|
|
143
|
+
unitPriceAmount: t.unitPrice?.amount,
|
|
144
|
+
flatPriceAmount: t.flatPrice?.amount
|
|
145
|
+
})),
|
|
146
|
+
currency,
|
|
147
|
+
unitLabel,
|
|
148
|
+
includedLabel: "Included",
|
|
149
|
+
omitIncludedUpToAmount: et.issueAfterReset
|
|
150
|
+
});
|
|
187
151
|
const overageTier = rc.price.tiers.find((t) => t.unitPrice?.amount && parseFloat(t.unitPrice.amount) > 0);
|
|
188
|
-
if (overageTier?.unitPrice) {
|
|
189
|
-
const amount = parseFloat(overageTier.unitPrice.amount);
|
|
190
|
-
const unitLabel = units?.[rc.key] ?? units?.[rc.featureKey ?? ""] ?? "unit";
|
|
191
|
-
overagePrice = `${formatPrice(amount, currency)}/${unitLabel}`;
|
|
192
|
-
}
|
|
152
|
+
if (et.isSoftLimit !== false && overageTier?.unitPrice) overagePrice = `${formatPrice(parseFloat(overageTier.unitPrice.amount), currency)}/${unitLabel}`;
|
|
193
153
|
}
|
|
194
154
|
quotas.push({
|
|
195
155
|
key: rc.featureKey ?? rc.key,
|
|
196
156
|
name: rc.name,
|
|
197
157
|
limit: et.issueAfterReset,
|
|
198
158
|
period: rc.billingCadence ? formatDuration(rc.billingCadence) : planBillingCadence ? formatDuration(planBillingCadence) : "month",
|
|
199
|
-
overagePrice
|
|
159
|
+
overagePrice,
|
|
160
|
+
tierPrices
|
|
200
161
|
});
|
|
201
162
|
} else if (et.type === "boolean") features.push({
|
|
202
163
|
key: rc.featureKey ?? rc.key,
|
|
@@ -221,7 +182,123 @@ const categorizeRateCards = (rateCards, options) => {
|
|
|
221
182
|
features
|
|
222
183
|
};
|
|
223
184
|
};
|
|
224
|
-
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/components/FeatureItem.tsx
|
|
187
|
+
const FeatureItem = ({ feature, className }) => {
|
|
188
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
189
|
+
className: cn("flex items-start gap-2", className),
|
|
190
|
+
children: [/* @__PURE__ */ jsx(CheckIcon, { className: "w-4 h-4 text-primary shrink-0 mt-0.5" }), /* @__PURE__ */ jsx("div", {
|
|
191
|
+
className: "text-sm",
|
|
192
|
+
children: feature.value ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
193
|
+
/* @__PURE__ */ jsxs("span", {
|
|
194
|
+
className: "font-medium",
|
|
195
|
+
children: [feature.name, ":"]
|
|
196
|
+
}),
|
|
197
|
+
" ",
|
|
198
|
+
feature.value
|
|
199
|
+
] }) : feature.name
|
|
200
|
+
})]
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/components/QuotaItem.tsx
|
|
205
|
+
const QuotaItem = ({ quota, className }) => {
|
|
206
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
207
|
+
className: cn("flex items-start gap-2", className),
|
|
208
|
+
children: [/* @__PURE__ */ jsx(CheckIcon, { className: "w-4 h-4 text-primary shrink-0 mt-0.5" }), /* @__PURE__ */ jsxs("div", {
|
|
209
|
+
className: "text-sm",
|
|
210
|
+
children: [
|
|
211
|
+
/* @__PURE__ */ jsxs("span", {
|
|
212
|
+
className: "font-medium",
|
|
213
|
+
children: [quota.name, ":"]
|
|
214
|
+
}),
|
|
215
|
+
" ",
|
|
216
|
+
quota.limit.toLocaleString(),
|
|
217
|
+
" / ",
|
|
218
|
+
quota.period,
|
|
219
|
+
quota.tierPrices && quota.tierPrices.length > 0 && /* @__PURE__ */ jsx("ul", {
|
|
220
|
+
className: "text-xs text-muted-foreground mt-1 space-y-0.5",
|
|
221
|
+
children: quota.tierPrices.map((line) => /* @__PURE__ */ jsx("li", { children: line }, line))
|
|
222
|
+
}),
|
|
223
|
+
quota.overagePrice && /* @__PURE__ */ jsxs("div", {
|
|
224
|
+
className: "text-xs text-muted-foreground mt-0.5",
|
|
225
|
+
children: [
|
|
226
|
+
"+",
|
|
227
|
+
quota.overagePrice,
|
|
228
|
+
" after quota"
|
|
229
|
+
]
|
|
230
|
+
})
|
|
231
|
+
]
|
|
232
|
+
})]
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
//#endregion
|
|
236
|
+
//#region src/components/PlanEntitlements.tsx
|
|
237
|
+
const PhaseSection = ({ phase, currency, showName, billingCadence, units, itemClassName }) => {
|
|
238
|
+
const { quotas, features } = categorizeRateCards(phase.rateCards, {
|
|
239
|
+
currency,
|
|
240
|
+
units,
|
|
241
|
+
planBillingCadence: billingCadence
|
|
242
|
+
});
|
|
243
|
+
if (quotas.length === 0 && features.length === 0) return null;
|
|
244
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
245
|
+
className: "space-y-2",
|
|
246
|
+
children: [
|
|
247
|
+
showName && /* @__PURE__ */ jsxs("div", {
|
|
248
|
+
className: "text-sm font-medium text-card-foreground",
|
|
249
|
+
children: [phase.name, phase.duration && /* @__PURE__ */ jsxs("span", {
|
|
250
|
+
className: "text-muted-foreground font-normal",
|
|
251
|
+
children: [
|
|
252
|
+
" ",
|
|
253
|
+
"— ",
|
|
254
|
+
formatDuration(phase.duration)
|
|
255
|
+
]
|
|
256
|
+
})]
|
|
257
|
+
}),
|
|
258
|
+
quotas.map((quota) => /* @__PURE__ */ jsx(QuotaItem, {
|
|
259
|
+
quota,
|
|
260
|
+
className: itemClassName
|
|
261
|
+
}, quota.key)),
|
|
262
|
+
features.map((feature) => /* @__PURE__ */ jsx(FeatureItem, {
|
|
263
|
+
feature,
|
|
264
|
+
className: itemClassName
|
|
265
|
+
}, feature.key))
|
|
266
|
+
]
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
const PlanEntitlements = ({ phases, currency, billingCadence, units, itemClassName }) => {
|
|
270
|
+
return /* @__PURE__ */ jsx("div", {
|
|
271
|
+
className: "space-y-4",
|
|
272
|
+
children: phases.map((phase, idx) => /* @__PURE__ */ jsx(PhaseSection, {
|
|
273
|
+
phase,
|
|
274
|
+
currency,
|
|
275
|
+
showName: phases.length > 1,
|
|
276
|
+
billingCadence,
|
|
277
|
+
units,
|
|
278
|
+
itemClassName
|
|
279
|
+
}, phase.key ?? String(idx)))
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region src/hooks/useDeploymentName.ts
|
|
284
|
+
const useDeploymentName = () => {
|
|
285
|
+
const deploymentName = useZudoku().env.ZUPLO_PUBLIC_DEPLOYMENT_NAME;
|
|
286
|
+
if (!deploymentName) throw new Error("ZUPLO_PUBLIC_DEPLOYMENT_NAME is not set");
|
|
287
|
+
return deploymentName;
|
|
288
|
+
};
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/hooks/usePurchaseDetails.ts
|
|
291
|
+
const usePurchaseDetails = (planId) => {
|
|
292
|
+
const zudoku = useZudoku();
|
|
293
|
+
return useSuspenseQuery({
|
|
294
|
+
queryKey: [`/v3/zudoku-metering/${useDeploymentName()}/plans/${planId}/purchase-details`],
|
|
295
|
+
meta: { context: zudoku }
|
|
296
|
+
});
|
|
297
|
+
};
|
|
298
|
+
//#endregion
|
|
299
|
+
//#region src/MonetizationContext.tsx
|
|
300
|
+
const MonetizationContext = createContext({});
|
|
301
|
+
const useMonetizationConfig = () => use(MonetizationContext);
|
|
225
302
|
//#endregion
|
|
226
303
|
//#region src/utils/formatBillingCycle.ts
|
|
227
304
|
const formatBillingCycle = (duration) => {
|
|
@@ -231,7 +308,6 @@ const formatBillingCycle = (duration) => {
|
|
|
231
308
|
if (duration === "day") return "daily";
|
|
232
309
|
return `every ${duration}`;
|
|
233
310
|
};
|
|
234
|
-
|
|
235
311
|
//#endregion
|
|
236
312
|
//#region src/utils/getPriceFromPlan.ts
|
|
237
313
|
const getPriceFromPlan = (plan) => {
|
|
@@ -240,7 +316,6 @@ const getPriceFromPlan = (plan) => {
|
|
|
240
316
|
yearly: plan.yearlyPrice != null ? parseFloat(plan.yearlyPrice) : 0
|
|
241
317
|
};
|
|
242
318
|
};
|
|
243
|
-
|
|
244
319
|
//#endregion
|
|
245
320
|
//#region src/utils/purchaseDetails.ts
|
|
246
321
|
const getPlanFromPurchaseDetails = (response) => {
|
|
@@ -258,7 +333,6 @@ const getTaxLabelFromPurchaseDetails = (response) => {
|
|
|
258
333
|
const isTaxInclusiveFromPurchaseDetails = (response) => {
|
|
259
334
|
return response.tax?.taxInclusive === true;
|
|
260
335
|
};
|
|
261
|
-
|
|
262
336
|
//#endregion
|
|
263
337
|
//#region src/ZuploMonetizationWrapper.tsx
|
|
264
338
|
const DEFAULT_GATEWAY_URL = "https://api.zuploedge.com";
|
|
@@ -330,7 +404,6 @@ const ZuploMonetizationWrapper = ({ options = {} }) => /* @__PURE__ */ jsx(Query
|
|
|
330
404
|
children: /* @__PURE__ */ jsx(ClientOnly, { children: /* @__PURE__ */ jsx(Outlet, {}) })
|
|
331
405
|
})
|
|
332
406
|
});
|
|
333
|
-
|
|
334
407
|
//#endregion
|
|
335
408
|
//#region src/pages/CheckoutConfirmPage.tsx
|
|
336
409
|
const CheckoutConfirmPage = () => {
|
|
@@ -346,12 +419,6 @@ const CheckoutConfirmPage = () => {
|
|
|
346
419
|
const taxAmount = getTaxAmountFromPurchaseDetails(purchaseDetails.data);
|
|
347
420
|
const taxLabel = getTaxLabelFromPurchaseDetails(purchaseDetails.data);
|
|
348
421
|
const taxInclusive = isTaxInclusiveFromPurchaseDetails(purchaseDetails.data);
|
|
349
|
-
const rateCards = selectedPlan?.phases.at(-1)?.rateCards;
|
|
350
|
-
const { quotas, features } = categorizeRateCards(rateCards ?? [], {
|
|
351
|
-
currency: selectedPlan?.currency,
|
|
352
|
-
units: pricing?.units,
|
|
353
|
-
planBillingCadence: selectedPlan?.billingCadence
|
|
354
|
-
});
|
|
355
422
|
const price = selectedPlan ? getPriceFromPlan(selectedPlan) : null;
|
|
356
423
|
const billingCycle = selectedPlan?.billingCadence ? formatDuration(selectedPlan.billingCadence) : null;
|
|
357
424
|
const createSubscriptionMutation = useMutation({
|
|
@@ -447,15 +514,12 @@ const CheckoutConfirmPage = () => {
|
|
|
447
514
|
className: "text-sm font-medium mb-3 mt-3",
|
|
448
515
|
children: "What's included:"
|
|
449
516
|
}),
|
|
450
|
-
/* @__PURE__ */
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
feature,
|
|
457
|
-
className: "text-muted-foreground"
|
|
458
|
-
}, feature.key))]
|
|
517
|
+
/* @__PURE__ */ jsx(PlanEntitlements, {
|
|
518
|
+
phases: selectedPlan.phases,
|
|
519
|
+
currency: selectedPlan.currency,
|
|
520
|
+
billingCadence: selectedPlan.billingCadence,
|
|
521
|
+
units: pricing?.units,
|
|
522
|
+
itemClassName: "text-muted-foreground"
|
|
459
523
|
})
|
|
460
524
|
] })]
|
|
461
525
|
}),
|
|
@@ -494,7 +558,6 @@ const CheckoutConfirmPage = () => {
|
|
|
494
558
|
})
|
|
495
559
|
});
|
|
496
560
|
};
|
|
497
|
-
|
|
498
561
|
//#endregion
|
|
499
562
|
//#region src/components/RedirectPage.tsx
|
|
500
563
|
const RedirectPage = ({ icon: Icon, title, description, url, children }) => {
|
|
@@ -543,7 +606,6 @@ const RedirectPage = ({ icon: Icon, title, description, url, children }) => {
|
|
|
543
606
|
})
|
|
544
607
|
});
|
|
545
608
|
};
|
|
546
|
-
|
|
547
609
|
//#endregion
|
|
548
610
|
//#region src/hooks/useUrlUtils.ts
|
|
549
611
|
const useUrlUtils = () => {
|
|
@@ -553,7 +615,6 @@ const useUrlUtils = () => {
|
|
|
553
615
|
return joinUrl(window.location.origin, basePath, path, searchParams ? `?${new URLSearchParams(searchParams)}` : void 0);
|
|
554
616
|
} };
|
|
555
617
|
};
|
|
556
|
-
|
|
557
618
|
//#endregion
|
|
558
619
|
//#region src/pages/CheckoutPage.tsx
|
|
559
620
|
const CheckoutPage = () => {
|
|
@@ -604,7 +665,6 @@ const CheckoutPage = () => {
|
|
|
604
665
|
})
|
|
605
666
|
});
|
|
606
667
|
};
|
|
607
|
-
|
|
608
668
|
//#endregion
|
|
609
669
|
//#region src/pages/ManagePaymentPage.tsx
|
|
610
670
|
const ManagePaymentPage = () => {
|
|
@@ -647,7 +707,6 @@ const ManagePaymentPage = () => {
|
|
|
647
707
|
})
|
|
648
708
|
});
|
|
649
709
|
};
|
|
650
|
-
|
|
651
710
|
//#endregion
|
|
652
711
|
//#region src/hooks/usePlans.ts
|
|
653
712
|
const usePlans = () => {
|
|
@@ -658,43 +717,47 @@ const usePlans = () => {
|
|
|
658
717
|
meta: { context: auth.isAuthenticated ? zudoku : void 0 }
|
|
659
718
|
});
|
|
660
719
|
};
|
|
661
|
-
|
|
662
720
|
//#endregion
|
|
663
|
-
//#region src/
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
className: "text-sm font-medium text-card-foreground",
|
|
677
|
-
children: [phase.name, phase.duration && /* @__PURE__ */ jsxs("span", {
|
|
678
|
-
className: "text-muted-foreground font-normal",
|
|
679
|
-
children: [
|
|
680
|
-
" ",
|
|
681
|
-
"— ",
|
|
682
|
-
formatDuration(phase.duration)
|
|
683
|
-
]
|
|
684
|
-
})]
|
|
685
|
-
}),
|
|
686
|
-
quotas.map((quota) => /* @__PURE__ */ jsx(QuotaItem, { quota }, quota.key)),
|
|
687
|
-
features.map((feature) => /* @__PURE__ */ jsx(FeatureItem, { feature }, feature.key))
|
|
688
|
-
]
|
|
689
|
-
});
|
|
721
|
+
//#region src/utils/pricingTaxLegend.ts
|
|
722
|
+
const normalizeTaxBehavior = (behavior) => {
|
|
723
|
+
switch (behavior.trim().toLowerCase()) {
|
|
724
|
+
case "exclusive":
|
|
725
|
+
case "tax_exclusive": return "exclusive";
|
|
726
|
+
case "inclusive":
|
|
727
|
+
case "tax_inclusive": return "inclusive";
|
|
728
|
+
default: return "unspecified";
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
const planHasDefaultTaxBehavior = (plan) => {
|
|
732
|
+
const behavior = plan.defaultTaxConfig?.behavior;
|
|
733
|
+
return typeof behavior === "string" && behavior.trim().length > 0;
|
|
690
734
|
};
|
|
735
|
+
const collectDefaultTaxBehaviors = (plan) => {
|
|
736
|
+
const behavior = plan.defaultTaxConfig?.behavior;
|
|
737
|
+
return typeof behavior === "string" && behavior.trim().length > 0 ? normalizeTaxBehavior(behavior) : "unspecified";
|
|
738
|
+
};
|
|
739
|
+
const taxBehaviorLegendSentence = (behavior) => {
|
|
740
|
+
switch (normalizeTaxBehavior(behavior)) {
|
|
741
|
+
case "exclusive": return "Prices exclude tax; taxes may be added at checkout if applicable.";
|
|
742
|
+
case "inclusive": return "Prices include tax where applicable.";
|
|
743
|
+
default: return;
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
const subscriptionTaxLegendSentence = (behavior) => {
|
|
747
|
+
switch (normalizeTaxBehavior(behavior)) {
|
|
748
|
+
case "exclusive": return "Price excludes tax; taxes may be added on invoice if applicable.";
|
|
749
|
+
case "inclusive": return "Price includes tax where applicable.";
|
|
750
|
+
default: return;
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
//#endregion
|
|
754
|
+
//#region src/pages/pricing/PricingCard.tsx
|
|
691
755
|
const PricingCard = ({ plan, isPopular = false, isSubscribed = false }) => {
|
|
692
756
|
const { pricing } = useMonetizationConfig();
|
|
693
757
|
if (plan.phases.length === 0) return null;
|
|
694
758
|
const price = getPriceFromPlan(plan);
|
|
695
759
|
const isFree = price.monthly === 0;
|
|
696
760
|
const isCustom = plan.metadata?.isCustom === true;
|
|
697
|
-
const hasMultiplePhases = plan.phases.length > 1;
|
|
698
761
|
const billingInterval = formatDuration(plan.billingCadence);
|
|
699
762
|
return /* @__PURE__ */ jsxs("div", {
|
|
700
763
|
className: cn("relative rounded-lg border p-6 flex flex-col", isPopular && "border-primary border-2"),
|
|
@@ -740,12 +803,12 @@ const PricingCard = ({ plan, isPopular = false, isSubscribed = false }) => {
|
|
|
740
803
|
}),
|
|
741
804
|
/* @__PURE__ */ jsx("div", {
|
|
742
805
|
className: "space-y-4 mb-6 grow",
|
|
743
|
-
children:
|
|
744
|
-
|
|
806
|
+
children: /* @__PURE__ */ jsx(PlanEntitlements, {
|
|
807
|
+
phases: plan.phases,
|
|
745
808
|
currency: plan.currency,
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
}
|
|
809
|
+
billingCadence: plan.billingCadence,
|
|
810
|
+
units: pricing?.units
|
|
811
|
+
})
|
|
749
812
|
}),
|
|
750
813
|
isSubscribed ? /* @__PURE__ */ jsx(Button, {
|
|
751
814
|
variant: isPopular ? "default" : "secondary",
|
|
@@ -765,7 +828,6 @@ const PricingCard = ({ plan, isPopular = false, isSubscribed = false }) => {
|
|
|
765
828
|
]
|
|
766
829
|
});
|
|
767
830
|
};
|
|
768
|
-
|
|
769
831
|
//#endregion
|
|
770
832
|
//#region src/pages/PricingPage.tsx
|
|
771
833
|
const PricingPage = () => {
|
|
@@ -774,6 +836,7 @@ const PricingPage = () => {
|
|
|
774
836
|
const deploymentName = useDeploymentName();
|
|
775
837
|
const auth = useAuth();
|
|
776
838
|
const { data: pricingTable } = usePlans();
|
|
839
|
+
const taxLegendSentence = taxBehaviorLegendSentence(collectDefaultTaxBehaviors(pricingTable.items[0]));
|
|
777
840
|
const { data: subscriptions = { items: [] } } = useQuery({
|
|
778
841
|
meta: { context: zudoku },
|
|
779
842
|
queryKey: [`/v3/zudoku-metering/${deploymentName}/subscriptions`],
|
|
@@ -804,19 +867,28 @@ const PricingPage = () => {
|
|
|
804
867
|
className: "text-sm mt-2",
|
|
805
868
|
children: "Make sure your plans are set up and published."
|
|
806
869
|
})]
|
|
807
|
-
}) : /* @__PURE__ */ jsx("div", {
|
|
870
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
808
871
|
className: "w-full grid grid-cols-1 sm:grid-cols-[repeat(auto-fit,minmax(300px,max-content))] justify-center gap-6",
|
|
809
872
|
children: pricingTable.items.map((plan) => /* @__PURE__ */ jsx(PricingCard, {
|
|
810
873
|
plan,
|
|
811
874
|
isPopular: plan.metadata?.zuplo_most_popular === "true",
|
|
812
875
|
isSubscribed: subscriptions.items.some((subscription) => ["active", "canceled"].includes(subscription.status))
|
|
813
876
|
}, plan.id))
|
|
814
|
-
}),
|
|
877
|
+
}), taxLegendSentence && /* @__PURE__ */ jsxs("div", {
|
|
878
|
+
role: "note",
|
|
879
|
+
className: "mt-10 pt-6 border-t border-border max-w-2xl mx-auto text-center space-y-2",
|
|
880
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
881
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
882
|
+
children: "Tax & Pricing"
|
|
883
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
884
|
+
className: "text-xs text-muted-foreground",
|
|
885
|
+
children: taxLegendSentence
|
|
886
|
+
})]
|
|
887
|
+
})] }),
|
|
815
888
|
/* @__PURE__ */ jsx(Slot.Target, { name: "pricing-page-after" })
|
|
816
889
|
]
|
|
817
890
|
});
|
|
818
891
|
};
|
|
819
|
-
|
|
820
892
|
//#endregion
|
|
821
893
|
//#region src/pages/PricingPageSkeleton.tsx
|
|
822
894
|
const PricingPageSkeleton = () => /* @__PURE__ */ jsxs("div", {
|
|
@@ -847,7 +919,6 @@ const PricingPageSkeleton = () => /* @__PURE__ */ jsxs("div", {
|
|
|
847
919
|
}, i))
|
|
848
920
|
})]
|
|
849
921
|
});
|
|
850
|
-
|
|
851
922
|
//#endregion
|
|
852
923
|
//#region src/pages/SubscriptionChangeConfirmPage.tsx
|
|
853
924
|
const SubscriptionChangeConfirmPage = () => {
|
|
@@ -866,12 +937,6 @@ const SubscriptionChangeConfirmPage = () => {
|
|
|
866
937
|
const taxAmount = getTaxAmountFromPurchaseDetails(purchaseDetails.data);
|
|
867
938
|
const taxLabel = getTaxLabelFromPurchaseDetails(purchaseDetails.data);
|
|
868
939
|
const taxInclusive = isTaxInclusiveFromPurchaseDetails(purchaseDetails.data);
|
|
869
|
-
const rateCards = selectedPlan?.phases.at(-1)?.rateCards;
|
|
870
|
-
const { quotas, features } = categorizeRateCards(rateCards ?? [], {
|
|
871
|
-
currency: selectedPlan?.currency,
|
|
872
|
-
units: pricing?.units,
|
|
873
|
-
planBillingCadence: selectedPlan?.billingCadence
|
|
874
|
-
});
|
|
875
940
|
const price = selectedPlan ? getPriceFromPlan(selectedPlan) : null;
|
|
876
941
|
const billingCycle = selectedPlan?.billingCadence ? formatDuration(selectedPlan.billingCadence) : null;
|
|
877
942
|
const effectiveChangeMessage = mode === "downgrade" ? "This change will take effect at the start of your next billing cycle." : "This change will take effect immediately.";
|
|
@@ -973,15 +1038,11 @@ const SubscriptionChangeConfirmPage = () => {
|
|
|
973
1038
|
className: "text-sm font-medium mb-3 mt-3",
|
|
974
1039
|
children: "What's included:"
|
|
975
1040
|
}),
|
|
976
|
-
/* @__PURE__ */
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
}, quota.key)), features.map((feature) => /* @__PURE__ */ jsx(FeatureItem, {
|
|
982
|
-
feature,
|
|
983
|
-
className: "text-muted-foreground"
|
|
984
|
-
}, feature.key))]
|
|
1041
|
+
/* @__PURE__ */ jsx(PlanEntitlements, {
|
|
1042
|
+
phases: selectedPlan.phases,
|
|
1043
|
+
currency: selectedPlan.currency,
|
|
1044
|
+
billingCadence: selectedPlan.billingCadence,
|
|
1045
|
+
units: pricing?.units
|
|
985
1046
|
})
|
|
986
1047
|
] })]
|
|
987
1048
|
}),
|
|
@@ -1015,7 +1076,6 @@ const SubscriptionChangeConfirmPage = () => {
|
|
|
1015
1076
|
})
|
|
1016
1077
|
});
|
|
1017
1078
|
};
|
|
1018
|
-
|
|
1019
1079
|
//#endregion
|
|
1020
1080
|
//#region src/hooks/useSubscriptions.ts
|
|
1021
1081
|
const useSubscriptions = (environmentName) => {
|
|
@@ -1033,7 +1093,6 @@ const useSubscriptions = (environmentName) => {
|
|
|
1033
1093
|
})
|
|
1034
1094
|
});
|
|
1035
1095
|
};
|
|
1036
|
-
|
|
1037
1096
|
//#endregion
|
|
1038
1097
|
//#region src/pages/subscriptions/ConfirmDeleteKeyAlert.tsx
|
|
1039
1098
|
const ConfirmDeleteKeyAlert = ({ children, onDelete }) => {
|
|
@@ -1045,10 +1104,9 @@ const ConfirmDeleteKeyAlert = ({ children, onDelete }) => {
|
|
|
1045
1104
|
children: "Continue"
|
|
1046
1105
|
})] })] })] });
|
|
1047
1106
|
};
|
|
1048
|
-
|
|
1049
1107
|
//#endregion
|
|
1050
1108
|
//#region src/pages/subscriptions/ApiKey.tsx
|
|
1051
|
-
const formatDate$
|
|
1109
|
+
const formatDate$2 = (dateString) => {
|
|
1052
1110
|
if (!dateString) return "";
|
|
1053
1111
|
return new Date(dateString).toLocaleDateString("en-US", {
|
|
1054
1112
|
month: "short",
|
|
@@ -1059,8 +1117,7 @@ const formatDate$1 = (dateString) => {
|
|
|
1059
1117
|
const getTimeAgo = (dateString) => {
|
|
1060
1118
|
if (!dateString) return "Never";
|
|
1061
1119
|
const date = new Date(dateString);
|
|
1062
|
-
const
|
|
1063
|
-
const diffInMinutes = Math.floor((now.getTime() - date.getTime()) / (1e3 * 60));
|
|
1120
|
+
const diffInMinutes = Math.floor(((/* @__PURE__ */ new Date()).getTime() - date.getTime()) / (1e3 * 60));
|
|
1064
1121
|
if (diffInMinutes < 1) return "Just now";
|
|
1065
1122
|
if (diffInMinutes < 60) return `${diffInMinutes} minutes ago`;
|
|
1066
1123
|
const diffInHours = Math.floor(diffInMinutes / 60);
|
|
@@ -1068,7 +1125,7 @@ const getTimeAgo = (dateString) => {
|
|
|
1068
1125
|
const diffInDays = Math.floor(diffInHours / 24);
|
|
1069
1126
|
if (diffInDays === 1) return "1 day ago";
|
|
1070
1127
|
if (diffInDays < 30) return `${diffInDays} days ago`;
|
|
1071
|
-
return formatDate$
|
|
1128
|
+
return formatDate$2(dateString);
|
|
1072
1129
|
};
|
|
1073
1130
|
const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label, onDelete }) => {
|
|
1074
1131
|
const isExpiring = expiresOn && new Date(expiresOn) < new Date(Date.now() + 720 * 60 * 60 * 1e3);
|
|
@@ -1125,7 +1182,7 @@ const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label
|
|
|
1125
1182
|
children: [
|
|
1126
1183
|
/* @__PURE__ */ jsxs("div", {
|
|
1127
1184
|
className: "flex items-center gap-1.5",
|
|
1128
|
-
children: [/* @__PURE__ */ jsx(ClockIcon, { className: "size-3" }), /* @__PURE__ */ jsxs("span", { children: ["Created ", formatDate$
|
|
1185
|
+
children: [/* @__PURE__ */ jsx(ClockIcon, { className: "size-3" }), /* @__PURE__ */ jsxs("span", { children: ["Created ", formatDate$2(createdAt)] })]
|
|
1129
1186
|
}),
|
|
1130
1187
|
/* @__PURE__ */ jsx("span", {
|
|
1131
1188
|
className: "text-muted-foreground/40",
|
|
@@ -1140,7 +1197,7 @@ const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label
|
|
|
1140
1197
|
children: [
|
|
1141
1198
|
isExpired ? "Expired" : "Expires",
|
|
1142
1199
|
" on ",
|
|
1143
|
-
formatDate$
|
|
1200
|
+
formatDate$2(expiresOn)
|
|
1144
1201
|
]
|
|
1145
1202
|
})] })
|
|
1146
1203
|
]
|
|
@@ -1148,7 +1205,6 @@ const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label
|
|
|
1148
1205
|
})]
|
|
1149
1206
|
});
|
|
1150
1207
|
};
|
|
1151
|
-
|
|
1152
1208
|
//#endregion
|
|
1153
1209
|
//#region src/pages/subscriptions/ApiKeyInfo.tsx
|
|
1154
1210
|
const ApiKeyInfo = () => /* @__PURE__ */ jsxs(DismissibleAlert, {
|
|
@@ -1168,7 +1224,6 @@ const ApiKeyInfo = () => /* @__PURE__ */ jsxs(DismissibleAlert, {
|
|
|
1168
1224
|
/* @__PURE__ */ jsx(DismissibleAlertAction, {})
|
|
1169
1225
|
]
|
|
1170
1226
|
});
|
|
1171
|
-
|
|
1172
1227
|
//#endregion
|
|
1173
1228
|
//#region src/pages/subscriptions/ConfirmRollKeyAlert.tsx
|
|
1174
1229
|
const ConfirmRollKeyAlert = (props) => /* @__PURE__ */ jsxs(AlertDialog, { children: [/* @__PURE__ */ jsx(AlertDialogTrigger, {
|
|
@@ -1178,7 +1233,6 @@ const ConfirmRollKeyAlert = (props) => /* @__PURE__ */ jsxs(AlertDialog, { child
|
|
|
1178
1233
|
onClick: props.onRollKey,
|
|
1179
1234
|
children: "Continue"
|
|
1180
1235
|
})] })] })] });
|
|
1181
|
-
|
|
1182
1236
|
//#endregion
|
|
1183
1237
|
//#region src/pages/subscriptions/ApiKeysList.tsx
|
|
1184
1238
|
const PendingFirstPaymentAlert = ({ children }) => /* @__PURE__ */ jsxs("div", {
|
|
@@ -1258,7 +1312,7 @@ const ApiKeysList = ({ isPendingFirstPayment, apiKeys, deploymentName, consumerI
|
|
|
1258
1312
|
/* @__PURE__ */ jsx(AlertTitle, { children: "API key was deleted" }),
|
|
1259
1313
|
/* @__PURE__ */ jsx(AlertDescription, { children: (() => {
|
|
1260
1314
|
const deletedKey = apiKeys.find((k) => k.id === deleteKeyMutation.variables?.keyId);
|
|
1261
|
-
return deletedKey ? `API key created ${formatDate$
|
|
1315
|
+
return deletedKey ? `API key created ${formatDate$2(deletedKey.createdOn)} has been removed.` : "The API key has been deleted.";
|
|
1262
1316
|
})() }),
|
|
1263
1317
|
/* @__PURE__ */ jsx(DismissibleAlertAction, {})
|
|
1264
1318
|
]
|
|
@@ -1330,7 +1384,6 @@ const ApiKeysList = ({ isPendingFirstPayment, apiKeys, deploymentName, consumerI
|
|
|
1330
1384
|
]
|
|
1331
1385
|
});
|
|
1332
1386
|
};
|
|
1333
|
-
|
|
1334
1387
|
//#endregion
|
|
1335
1388
|
//#region src/pages/subscriptions/CancelSubscriptionDialog.tsx
|
|
1336
1389
|
const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId, billingPeriodEnd }) => {
|
|
@@ -1370,7 +1423,7 @@ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId
|
|
|
1370
1423
|
/* @__PURE__ */ jsx(AlertTitle, { children: "Your plan will be canceled at the end of your billing cycle." }),
|
|
1371
1424
|
/* @__PURE__ */ jsxs(AlertDescription, { children: [
|
|
1372
1425
|
"You'll retain access until ",
|
|
1373
|
-
formatDate$
|
|
1426
|
+
formatDate$2(billingPeriodEnd),
|
|
1374
1427
|
". After your billing period ends, this plan will not renew and you would need to subscribe again to continue."
|
|
1375
1428
|
] })
|
|
1376
1429
|
]
|
|
@@ -1383,7 +1436,7 @@ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId
|
|
|
1383
1436
|
/* @__PURE__ */ jsxs(AlertDescription, { children: [
|
|
1384
1437
|
"If you change your mind you have until",
|
|
1385
1438
|
" ",
|
|
1386
|
-
formatDate$
|
|
1439
|
+
formatDate$2(billingPeriodEnd),
|
|
1387
1440
|
" to remove this cancellation from Manage subscription."
|
|
1388
1441
|
] })
|
|
1389
1442
|
]
|
|
@@ -1437,7 +1490,6 @@ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId
|
|
|
1437
1490
|
})
|
|
1438
1491
|
});
|
|
1439
1492
|
};
|
|
1440
|
-
|
|
1441
1493
|
//#endregion
|
|
1442
1494
|
//#region src/pages/subscriptions/RestoreSubscriptionDialog.tsx
|
|
1443
1495
|
const RestoreSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId, billingPeriodEnd }) => {
|
|
@@ -1487,7 +1539,7 @@ const RestoreSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionI
|
|
|
1487
1539
|
className: "space-y-2",
|
|
1488
1540
|
children: [/* @__PURE__ */ jsxs("p", { children: [
|
|
1489
1541
|
"Your access stays in place until ",
|
|
1490
|
-
formatDate$
|
|
1542
|
+
formatDate$2(billingPeriodEnd),
|
|
1491
1543
|
" ",
|
|
1492
1544
|
"either way."
|
|
1493
1545
|
] }), /* @__PURE__ */ jsx("p", { children: "Confirming will remove the pending cancellation. Your subscription will remain active and continue to renew on your normal billing schedule, and charges will apply as usual." })]
|
|
@@ -1519,7 +1571,6 @@ const RestoreSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionI
|
|
|
1519
1571
|
})
|
|
1520
1572
|
});
|
|
1521
1573
|
};
|
|
1522
|
-
|
|
1523
1574
|
//#endregion
|
|
1524
1575
|
//#region src/pages/subscriptions/SwitchPlanModal.tsx
|
|
1525
1576
|
const getAllKeysAcrossPhases = (plan, units) => {
|
|
@@ -1669,6 +1720,7 @@ const ChangeIndicator = ({ change }) => {
|
|
|
1669
1720
|
if (change === "decrease" || change === "removed" || change === "downgraded") return /* @__PURE__ */ jsx(ArrowDownIcon, { className: "w-4 h-4 text-amber-600 shrink-0" });
|
|
1670
1721
|
return /* @__PURE__ */ jsx(CheckIcon, { className: "w-4 h-4 text-green-600 shrink-0" });
|
|
1671
1722
|
};
|
|
1723
|
+
const isPrivatePlan = (plan) => plan.metadata?.zuplo_private_plan === "true";
|
|
1672
1724
|
const modeLabelMap = {
|
|
1673
1725
|
upgrade: "Upgrade",
|
|
1674
1726
|
downgrade: "Downgrade",
|
|
@@ -1859,12 +1911,29 @@ const SwitchPlanModal = ({ subscription, children }) => {
|
|
|
1859
1911
|
});
|
|
1860
1912
|
const currentPlan = plansData?.items.find((p) => p.key === subscription.plan.key);
|
|
1861
1913
|
const { upgrades, downgrades, privatePlans } = useMemo(() => {
|
|
1862
|
-
if (!plansData?.items
|
|
1914
|
+
if (!plansData?.items) return {
|
|
1863
1915
|
upgrades: [],
|
|
1864
1916
|
downgrades: [],
|
|
1865
1917
|
privatePlans: []
|
|
1866
1918
|
};
|
|
1867
|
-
|
|
1919
|
+
if (!currentPlan) {
|
|
1920
|
+
const currentIndex = -1;
|
|
1921
|
+
return {
|
|
1922
|
+
upgrades: plansData.items.map((plan, targetIndex) => comparePlans(void 0, plan, currentIndex, targetIndex, pricing?.units)).filter((c) => !isPrivatePlan(c.plan)),
|
|
1923
|
+
downgrades: [],
|
|
1924
|
+
privatePlans: []
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
if (isPrivatePlan(currentPlan)) {
|
|
1928
|
+
const currentIndex = plansData.items.findIndex((p) => p.id === currentPlan.id);
|
|
1929
|
+
return {
|
|
1930
|
+
upgrades: plansData.items.filter((p) => p.id !== currentPlan.id).map((plan) => {
|
|
1931
|
+
return comparePlans(currentPlan, plan, currentIndex, plansData.items.indexOf(plan), pricing?.units);
|
|
1932
|
+
}).filter((c) => !isPrivatePlan(c.plan)),
|
|
1933
|
+
downgrades: [],
|
|
1934
|
+
privatePlans: []
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1868
1937
|
const currentIndex = plansData.items.findIndex((p) => p.id === currentPlan.id);
|
|
1869
1938
|
const allComparisons = plansData.items.filter((p) => p.id !== currentPlan.id).map((plan) => {
|
|
1870
1939
|
return comparePlans(currentPlan, plan, currentIndex, plansData.items.indexOf(plan), pricing?.units);
|
|
@@ -1914,6 +1983,13 @@ const SwitchPlanModal = ({ subscription, children }) => {
|
|
|
1914
1983
|
children: currentPlan.name
|
|
1915
1984
|
})] })
|
|
1916
1985
|
}),
|
|
1986
|
+
!currentPlan && /* @__PURE__ */ jsx(Item, {
|
|
1987
|
+
variant: "outline",
|
|
1988
|
+
children: /* @__PURE__ */ jsxs(ItemContent, { children: [/* @__PURE__ */ jsx(ItemTitle, { children: "Current Plan" }), /* @__PURE__ */ jsx(ItemDescription, {
|
|
1989
|
+
className: "text-lg font-bold",
|
|
1990
|
+
children: subscription.plan.name
|
|
1991
|
+
})] })
|
|
1992
|
+
}),
|
|
1917
1993
|
upgrades.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
1918
1994
|
className: "flex items-center justify-between mb-3",
|
|
1919
1995
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -1985,7 +2061,6 @@ const SwitchPlanModal = ({ subscription, children }) => {
|
|
|
1985
2061
|
}) })]
|
|
1986
2062
|
});
|
|
1987
2063
|
};
|
|
1988
|
-
|
|
1989
2064
|
//#endregion
|
|
1990
2065
|
//#region src/pages/subscriptions/ManageSubscription.tsx
|
|
1991
2066
|
const ManageSubscription = ({ subscription, planName }) => {
|
|
@@ -2077,7 +2152,262 @@ const ManageSubscription = ({ subscription, planName }) => {
|
|
|
2077
2152
|
})
|
|
2078
2153
|
] });
|
|
2079
2154
|
};
|
|
2080
|
-
|
|
2155
|
+
//#endregion
|
|
2156
|
+
//#region src/pages/subscriptions/SubscriptionPlanDetails.tsx
|
|
2157
|
+
const detailLabelClassName = "text-sm font-semibold tracking-wide mb-1";
|
|
2158
|
+
const sectionLabelClassName = "text-base font-semibold tracking-wide mb-3 mt-2";
|
|
2159
|
+
const formatDate$1 = (dateString) => {
|
|
2160
|
+
return new Date(dateString).toLocaleDateString("en-US", {
|
|
2161
|
+
month: "short",
|
|
2162
|
+
day: "numeric",
|
|
2163
|
+
year: "numeric"
|
|
2164
|
+
});
|
|
2165
|
+
};
|
|
2166
|
+
const formatDateRange = (from, to) => `${formatDate$1(from)} – ${formatDate$1(to)}`;
|
|
2167
|
+
const formatNumber = (value) => value.toLocaleString("en-US");
|
|
2168
|
+
const getOveragePriceFromItem = (item, currency, units) => {
|
|
2169
|
+
const tiers = item.price?.tiers;
|
|
2170
|
+
if (!tiers || tiers.length === 0) return void 0;
|
|
2171
|
+
const amount = tiers.find((t) => {
|
|
2172
|
+
const amount = t.unitPrice?.amount;
|
|
2173
|
+
if (!amount) return false;
|
|
2174
|
+
const parsed = parseFloat(amount);
|
|
2175
|
+
return Number.isFinite(parsed) && parsed > 0;
|
|
2176
|
+
})?.unitPrice?.amount;
|
|
2177
|
+
if (!amount) return void 0;
|
|
2178
|
+
const parsed = parseFloat(amount);
|
|
2179
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
|
|
2180
|
+
const unitLabel = units?.[item.key] ?? units?.[item.featureKey] ?? "unit";
|
|
2181
|
+
return `${formatPrice(parsed, currency)}/${unitLabel}`;
|
|
2182
|
+
};
|
|
2183
|
+
const getTierPricesFromItem = (item, currency, units) => {
|
|
2184
|
+
if (item.price?.type !== "tiered") return;
|
|
2185
|
+
const tiers = item.price.tiers;
|
|
2186
|
+
if (!tiers || tiers.length <= 1) return;
|
|
2187
|
+
const unitLabel = units?.[item.key] ?? units?.[item.featureKey] ?? "unit";
|
|
2188
|
+
return formatTieredPriceBreakdown({
|
|
2189
|
+
tiers: tiers.map((t) => ({
|
|
2190
|
+
upToAmount: t.upToAmount,
|
|
2191
|
+
unitPriceAmount: t.unitPrice?.amount,
|
|
2192
|
+
flatPriceAmount: t.flatPrice?.amount
|
|
2193
|
+
})),
|
|
2194
|
+
currency,
|
|
2195
|
+
unitLabel,
|
|
2196
|
+
includedLabel: "Included",
|
|
2197
|
+
omitIncludedUpToAmount: item.included?.entitlement?.issueAfterReset
|
|
2198
|
+
});
|
|
2199
|
+
};
|
|
2200
|
+
const getEntitlementsFromItems = (items, currency, units, fallbackBillingCadence) => {
|
|
2201
|
+
const features = [];
|
|
2202
|
+
for (const item of items) {
|
|
2203
|
+
const entitlement = item.included?.entitlement;
|
|
2204
|
+
if (!entitlement) continue;
|
|
2205
|
+
if (entitlement.type === "metered" && entitlement.issueAfterReset != null) {
|
|
2206
|
+
const cadence = item.billingCadence ?? fallbackBillingCadence;
|
|
2207
|
+
features.push({
|
|
2208
|
+
entitlementType: "metered",
|
|
2209
|
+
key: item.featureKey ?? item.key,
|
|
2210
|
+
name: item.name ?? item.featureKey ?? item.key,
|
|
2211
|
+
limit: entitlement.issueAfterReset,
|
|
2212
|
+
period: cadence ? formatDuration(cadence) : "month",
|
|
2213
|
+
overagePrice: entitlement.isSoftLimit !== false ? getOveragePriceFromItem(item, currency, units) : void 0,
|
|
2214
|
+
tierPrices: getTierPricesFromItem(item, currency, units)
|
|
2215
|
+
});
|
|
2216
|
+
continue;
|
|
2217
|
+
}
|
|
2218
|
+
if (entitlement.type === "boolean") {
|
|
2219
|
+
features.push({
|
|
2220
|
+
entitlementType: "boolean",
|
|
2221
|
+
key: item.featureKey ?? item.key,
|
|
2222
|
+
name: item.name ?? item.featureKey ?? item.key
|
|
2223
|
+
});
|
|
2224
|
+
continue;
|
|
2225
|
+
}
|
|
2226
|
+
if (entitlement.type === "static") {
|
|
2227
|
+
const base = {
|
|
2228
|
+
key: item.featureKey ?? item.key,
|
|
2229
|
+
name: item.name ?? item.featureKey ?? item.key
|
|
2230
|
+
};
|
|
2231
|
+
if (!entitlement.config) {
|
|
2232
|
+
features.push({
|
|
2233
|
+
entitlementType: "static",
|
|
2234
|
+
...base
|
|
2235
|
+
});
|
|
2236
|
+
continue;
|
|
2237
|
+
}
|
|
2238
|
+
try {
|
|
2239
|
+
const parsed = JSON.parse(entitlement.config);
|
|
2240
|
+
features.push({
|
|
2241
|
+
entitlementType: "static",
|
|
2242
|
+
...base,
|
|
2243
|
+
value: parsed?.value != null ? String(parsed.value) : void 0
|
|
2244
|
+
});
|
|
2245
|
+
} catch {
|
|
2246
|
+
features.push({
|
|
2247
|
+
entitlementType: "static",
|
|
2248
|
+
...base
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
return { features };
|
|
2254
|
+
};
|
|
2255
|
+
const getPhaseRows = (opts) => {
|
|
2256
|
+
const { subscription, currency, units } = opts;
|
|
2257
|
+
const phases = [...subscription.phases].sort((a, b) => new Date(a.activeFrom).getTime() - new Date(b.activeFrom).getTime());
|
|
2258
|
+
const phaseGroups = [];
|
|
2259
|
+
for (const phase of phases) {
|
|
2260
|
+
const { features } = getEntitlementsFromItems(phase.items ?? [], currency, units, subscription.billingCadence);
|
|
2261
|
+
const rows = [];
|
|
2262
|
+
for (const f of features) rows.push({
|
|
2263
|
+
key: f.key,
|
|
2264
|
+
name: f.name,
|
|
2265
|
+
entitlementType: f.entitlementType,
|
|
2266
|
+
limit: f.entitlementType === "metered" ? f.limit : void 0,
|
|
2267
|
+
period: f.entitlementType === "metered" ? f.period : void 0,
|
|
2268
|
+
overagePrice: f.entitlementType === "metered" ? f.overagePrice : void 0,
|
|
2269
|
+
tierPrices: f.entitlementType === "metered" ? f.tierPrices : void 0,
|
|
2270
|
+
value: f.entitlementType === "static" ? f.value : void 0,
|
|
2271
|
+
phaseId: phase.id,
|
|
2272
|
+
activeFrom: phase.activeFrom,
|
|
2273
|
+
activeTo: phase.activeTo
|
|
2274
|
+
});
|
|
2275
|
+
if (rows.length > 0) phaseGroups.push({
|
|
2276
|
+
id: phase.id,
|
|
2277
|
+
name: phase.name,
|
|
2278
|
+
activeFrom: phase.activeFrom,
|
|
2279
|
+
activeTo: phase.activeTo,
|
|
2280
|
+
rows
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
return { phaseGroups };
|
|
2284
|
+
};
|
|
2285
|
+
const formatActiveRange = (activeFrom, activeTo) => {
|
|
2286
|
+
if (!activeTo) return `Starts ${formatDate$1(activeFrom)}`;
|
|
2287
|
+
return `${formatDate$1(activeFrom)} – ${formatDate$1(activeTo)}`;
|
|
2288
|
+
};
|
|
2289
|
+
const SubscriptionPlanDetails = ({ subscription }) => {
|
|
2290
|
+
const { pricing } = useMonetizationConfig();
|
|
2291
|
+
const plan = subscription.plan;
|
|
2292
|
+
const currency = subscription.currency ?? plan.currency;
|
|
2293
|
+
const priceInfo = getPriceFromPlan(plan);
|
|
2294
|
+
const taxLegendSentence = planHasDefaultTaxBehavior(plan) ? subscriptionTaxLegendSentence(plan.defaultTaxConfig?.behavior ?? "") : void 0;
|
|
2295
|
+
const primaryPrice = priceInfo.monthly === 0 && priceInfo.yearly === 0 ? /* @__PURE__ */ jsx("span", {
|
|
2296
|
+
className: "text-primary font-medium",
|
|
2297
|
+
children: "Free"
|
|
2298
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
2299
|
+
className: "text-primary font-medium text-lg",
|
|
2300
|
+
children: formatPrice(priceInfo.monthly, currency)
|
|
2301
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
2302
|
+
className: "text-muted-foreground",
|
|
2303
|
+
children: [" / ", formatDuration(plan.billingCadence)]
|
|
2304
|
+
})] });
|
|
2305
|
+
const { phaseGroups } = getPhaseRows({
|
|
2306
|
+
subscription,
|
|
2307
|
+
currency,
|
|
2308
|
+
units: pricing?.units
|
|
2309
|
+
});
|
|
2310
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2311
|
+
className: "space-y-4",
|
|
2312
|
+
children: [/* @__PURE__ */ jsx(Heading, {
|
|
2313
|
+
level: 3,
|
|
2314
|
+
children: "Subscription Details"
|
|
2315
|
+
}), /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsxs(CardHeader, { children: [/* @__PURE__ */ jsx(CardTitle, {
|
|
2316
|
+
className: "text-lg font-semibold leading-tight",
|
|
2317
|
+
children: plan.name
|
|
2318
|
+
}), plan.description ? /* @__PURE__ */ jsx(CardDescription, { children: plan.description }) : null] }), /* @__PURE__ */ jsxs(CardContent, {
|
|
2319
|
+
className: "space-y-6",
|
|
2320
|
+
children: [/* @__PURE__ */ jsxs("dl", {
|
|
2321
|
+
className: "grid gap-4 sm:grid-cols-2 text-sm",
|
|
2322
|
+
children: [
|
|
2323
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2324
|
+
className: detailLabelClassName,
|
|
2325
|
+
children: "Subscription ID"
|
|
2326
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2327
|
+
className: "text-foreground font-mono text-xs break-all",
|
|
2328
|
+
children: subscription.id
|
|
2329
|
+
})] }),
|
|
2330
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2331
|
+
className: detailLabelClassName,
|
|
2332
|
+
children: "Active since"
|
|
2333
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2334
|
+
className: "text-foreground",
|
|
2335
|
+
children: formatDate$1(subscription.activeFrom)
|
|
2336
|
+
})] }),
|
|
2337
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2338
|
+
className: detailLabelClassName,
|
|
2339
|
+
children: "Price"
|
|
2340
|
+
}), /* @__PURE__ */ jsxs("dd", { children: [/* @__PURE__ */ jsx("div", {
|
|
2341
|
+
className: "flex flex-wrap items-baseline gap-1",
|
|
2342
|
+
children: primaryPrice
|
|
2343
|
+
}), taxLegendSentence ? /* @__PURE__ */ jsx("p", {
|
|
2344
|
+
className: "text-xs text-muted-foreground mt-1",
|
|
2345
|
+
children: taxLegendSentence
|
|
2346
|
+
}) : null] })] }),
|
|
2347
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2348
|
+
className: detailLabelClassName,
|
|
2349
|
+
children: "Current period"
|
|
2350
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2351
|
+
className: "text-foreground",
|
|
2352
|
+
children: subscription.alignment?.currentAlignedBillingPeriod ? formatDateRange(subscription.alignment.currentAlignedBillingPeriod.from, subscription.alignment.currentAlignedBillingPeriod.to) : "—"
|
|
2353
|
+
})] })
|
|
2354
|
+
]
|
|
2355
|
+
}), phaseGroups.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
2356
|
+
className: "space-y-5 pt-2 border-t border-border",
|
|
2357
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2358
|
+
className: "space-y-2",
|
|
2359
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
2360
|
+
className: cn(sectionLabelClassName, "mb-5"),
|
|
2361
|
+
children: "Entitlements"
|
|
2362
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2363
|
+
className: "space-y-5",
|
|
2364
|
+
children: phaseGroups.map((phase) => /* @__PURE__ */ jsxs("div", {
|
|
2365
|
+
className: "space-y-3",
|
|
2366
|
+
children: [phaseGroups.length > 1 ? /* @__PURE__ */ jsxs("div", {
|
|
2367
|
+
className: "text-sm font-medium text-card-foreground",
|
|
2368
|
+
children: [phase.name, /* @__PURE__ */ jsxs("span", {
|
|
2369
|
+
className: "text-muted-foreground font-normal",
|
|
2370
|
+
children: [
|
|
2371
|
+
" ",
|
|
2372
|
+
"—",
|
|
2373
|
+
" ",
|
|
2374
|
+
formatActiveRange(phase.activeFrom, phase.activeTo)
|
|
2375
|
+
]
|
|
2376
|
+
})]
|
|
2377
|
+
}) : null, /* @__PURE__ */ jsx("ul", {
|
|
2378
|
+
className: "space-y-3",
|
|
2379
|
+
children: phase.rows.map((row) => /* @__PURE__ */ jsx("li", {
|
|
2380
|
+
className: "text-sm",
|
|
2381
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2382
|
+
className: "flex flex-col gap-1",
|
|
2383
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2384
|
+
className: "text-foreground font-medium",
|
|
2385
|
+
children: [row.name, row.entitlementType === "static" && row.value ? `: ${row.value}` : ""]
|
|
2386
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2387
|
+
className: "text-muted-foreground",
|
|
2388
|
+
children: row.entitlementType === "metered" && row.limit != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2389
|
+
formatNumber(row.limit),
|
|
2390
|
+
row.period ? ` / ${row.period}` : "",
|
|
2391
|
+
row.tierPrices && row.tierPrices.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
2392
|
+
className: "text-xs mt-1 space-y-0.5",
|
|
2393
|
+
children: row.tierPrices.map((line) => /* @__PURE__ */ jsx("li", { children: line }, line))
|
|
2394
|
+
}) : null,
|
|
2395
|
+
row.overagePrice ? /* @__PURE__ */ jsxs("div", {
|
|
2396
|
+
className: "text-xs mt-0.5",
|
|
2397
|
+
children: ["Overage: ", row.overagePrice]
|
|
2398
|
+
}) : null
|
|
2399
|
+
] }) : row.entitlementType === "static" && row.value ? null : "Included"
|
|
2400
|
+
})]
|
|
2401
|
+
})
|
|
2402
|
+
}, `${row.key}:${row.phaseId}`))
|
|
2403
|
+
})]
|
|
2404
|
+
}, phase.id))
|
|
2405
|
+
})]
|
|
2406
|
+
})
|
|
2407
|
+
}) : null]
|
|
2408
|
+
})] })]
|
|
2409
|
+
});
|
|
2410
|
+
};
|
|
2081
2411
|
//#endregion
|
|
2082
2412
|
//#region src/pages/subscriptions/Usage.tsx
|
|
2083
2413
|
const isMeteredEntitlement = (entitlement) => {
|
|
@@ -2237,7 +2567,6 @@ const Usage = ({ usage, isFetching, currentItems, subscription, isPendingFirstPa
|
|
|
2237
2567
|
]
|
|
2238
2568
|
});
|
|
2239
2569
|
};
|
|
2240
|
-
|
|
2241
2570
|
//#endregion
|
|
2242
2571
|
//#region src/pages/subscriptions/ActiveSubscription.tsx
|
|
2243
2572
|
const ActiveSubscription = ({ subscription, deploymentName }) => {
|
|
@@ -2261,6 +2590,7 @@ const ActiveSubscription = ({ subscription, deploymentName }) => {
|
|
|
2261
2590
|
/* @__PURE__ */ jsx(DismissibleAlertAction, {})
|
|
2262
2591
|
]
|
|
2263
2592
|
}),
|
|
2593
|
+
/* @__PURE__ */ jsx(SubscriptionPlanDetails, { subscription }),
|
|
2264
2594
|
/* @__PURE__ */ jsx(Usage, {
|
|
2265
2595
|
currentItems: activePhase?.items,
|
|
2266
2596
|
usage: usageQuery.data,
|
|
@@ -2280,7 +2610,6 @@ const ActiveSubscription = ({ subscription, deploymentName }) => {
|
|
|
2280
2610
|
})
|
|
2281
2611
|
] });
|
|
2282
2612
|
};
|
|
2283
|
-
|
|
2284
2613
|
//#endregion
|
|
2285
2614
|
//#region src/pages/subscriptions/SubscriptionsList.tsx
|
|
2286
2615
|
const formatDate = (dateString) => {
|
|
@@ -2354,7 +2683,6 @@ const SubscriptionItem = ({ subscription, isSelected, isExpired }) => {
|
|
|
2354
2683
|
}, subscription.id)
|
|
2355
2684
|
});
|
|
2356
2685
|
};
|
|
2357
|
-
|
|
2358
2686
|
//#endregion
|
|
2359
2687
|
//#region src/pages/SubscriptionsPage.tsx
|
|
2360
2688
|
const SubscriptionsPage = () => {
|
|
@@ -2399,7 +2727,6 @@ const SubscriptionsPage = () => {
|
|
|
2399
2727
|
})]
|
|
2400
2728
|
});
|
|
2401
2729
|
};
|
|
2402
|
-
|
|
2403
2730
|
//#endregion
|
|
2404
2731
|
//#region src/pages/SubscriptionsPageSkeleton.tsx
|
|
2405
2732
|
const SubscriptionsPageSkeleton = () => /* @__PURE__ */ jsx("div", {
|
|
@@ -2433,7 +2760,6 @@ const SubscriptionsPageSkeleton = () => /* @__PURE__ */ jsx("div", {
|
|
|
2433
2760
|
]
|
|
2434
2761
|
})
|
|
2435
2762
|
});
|
|
2436
|
-
|
|
2437
2763
|
//#endregion
|
|
2438
2764
|
//#region src/ZuploMonetizationPlugin.tsx
|
|
2439
2765
|
const PRICING_PATH = "/pricing";
|
|
@@ -2520,6 +2846,5 @@ const zuploMonetizationPlugin = createPlugin((options = {}) => ({
|
|
|
2520
2846
|
];
|
|
2521
2847
|
}
|
|
2522
2848
|
}));
|
|
2523
|
-
|
|
2524
2849
|
//#endregion
|
|
2525
|
-
export { zuploMonetizationPlugin };
|
|
2850
|
+
export { zuploMonetizationPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zuplo/zudoku-plugin-monetization",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/zuplo/zudoku",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@testing-library/react": "16.3.2",
|
|
28
28
|
"@types/react": "19.2.14",
|
|
29
29
|
"@types/react-dom": "19.2.3",
|
|
30
|
-
"happy-dom": "20.
|
|
31
|
-
"react": "19.2.
|
|
32
|
-
"react-dom": "19.2.
|
|
33
|
-
"tsdown": "0.
|
|
34
|
-
"zudoku": "0.
|
|
30
|
+
"happy-dom": "20.9.0",
|
|
31
|
+
"react": "19.2.5",
|
|
32
|
+
"react-dom": "19.2.5",
|
|
33
|
+
"tsdown": "0.21.9",
|
|
34
|
+
"zudoku": "0.76.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"react": ">=19.2.0",
|