@zuplo/zudoku-plugin-monetization 0.0.30 → 0.0.32
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 +269 -63
- 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,7 +6,7 @@ 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
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { parse } from "tinyduration";
|
|
@@ -23,7 +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
26
|
//#region src/components/FeatureItem.tsx
|
|
28
27
|
const FeatureItem = ({ feature, className }) => {
|
|
29
28
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -41,7 +40,6 @@ const FeatureItem = ({ feature, className }) => {
|
|
|
41
40
|
})]
|
|
42
41
|
});
|
|
43
42
|
};
|
|
44
|
-
|
|
45
43
|
//#endregion
|
|
46
44
|
//#region src/components/QuotaItem.tsx
|
|
47
45
|
const QuotaItem = ({ quota, className }) => {
|
|
@@ -70,7 +68,6 @@ const QuotaItem = ({ quota, className }) => {
|
|
|
70
68
|
})]
|
|
71
69
|
});
|
|
72
70
|
};
|
|
73
|
-
|
|
74
71
|
//#endregion
|
|
75
72
|
//#region src/hooks/useDeploymentName.ts
|
|
76
73
|
const useDeploymentName = () => {
|
|
@@ -78,7 +75,6 @@ const useDeploymentName = () => {
|
|
|
78
75
|
if (!deploymentName) throw new Error("ZUPLO_PUBLIC_DEPLOYMENT_NAME is not set");
|
|
79
76
|
return deploymentName;
|
|
80
77
|
};
|
|
81
|
-
|
|
82
78
|
//#endregion
|
|
83
79
|
//#region src/hooks/usePurchaseDetails.ts
|
|
84
80
|
const usePurchaseDetails = (planId) => {
|
|
@@ -88,12 +84,10 @@ const usePurchaseDetails = (planId) => {
|
|
|
88
84
|
meta: { context: zudoku }
|
|
89
85
|
});
|
|
90
86
|
};
|
|
91
|
-
|
|
92
87
|
//#endregion
|
|
93
88
|
//#region src/MonetizationContext.tsx
|
|
94
89
|
const MonetizationContext = createContext({});
|
|
95
90
|
const useMonetizationConfig = () => use(MonetizationContext);
|
|
96
|
-
|
|
97
91
|
//#endregion
|
|
98
92
|
//#region src/utils/formatDuration.ts
|
|
99
93
|
const formatDuration = (iso) => {
|
|
@@ -146,7 +140,6 @@ const formatDurationAdjective = (iso) => {
|
|
|
146
140
|
return "billing period";
|
|
147
141
|
}
|
|
148
142
|
};
|
|
149
|
-
|
|
150
143
|
//#endregion
|
|
151
144
|
//#region src/utils/formatPrice.ts
|
|
152
145
|
const formatPrice = (amount, currency) => new Intl.NumberFormat("en-US", {
|
|
@@ -156,13 +149,21 @@ const formatPrice = (amount, currency) => new Intl.NumberFormat("en-US", {
|
|
|
156
149
|
maximumFractionDigits: 6,
|
|
157
150
|
trailingZeroDisplay: "stripIfInteger"
|
|
158
151
|
}).format(amount);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
152
|
+
/** Amount is in the smallest currency unit (e.g. Stripe); divisor from `Intl` / ISO 4217. */
|
|
153
|
+
const formatMinorCurrencyAmount = (amountInMinorUnits, currency) => {
|
|
154
|
+
const code = (currency ?? "USD").toUpperCase();
|
|
155
|
+
const fractionDigits = new Intl.NumberFormat("en-US", {
|
|
156
|
+
style: "currency",
|
|
157
|
+
currency: code
|
|
158
|
+
}).resolvedOptions().maximumFractionDigits ?? 2;
|
|
159
|
+
const divisor = 10 ** fractionDigits;
|
|
160
|
+
return new Intl.NumberFormat("en-US", {
|
|
161
|
+
style: "currency",
|
|
162
|
+
currency: code,
|
|
163
|
+
minimumFractionDigits: fractionDigits,
|
|
164
|
+
maximumFractionDigits: fractionDigits
|
|
165
|
+
}).format(amountInMinorUnits / divisor);
|
|
166
|
+
};
|
|
166
167
|
//#endregion
|
|
167
168
|
//#region src/utils/categorizeRateCards.ts
|
|
168
169
|
const categorizeRateCards = (rateCards, options) => {
|
|
@@ -212,7 +213,6 @@ const categorizeRateCards = (rateCards, options) => {
|
|
|
212
213
|
features
|
|
213
214
|
};
|
|
214
215
|
};
|
|
215
|
-
|
|
216
216
|
//#endregion
|
|
217
217
|
//#region src/utils/formatBillingCycle.ts
|
|
218
218
|
const formatBillingCycle = (duration) => {
|
|
@@ -222,7 +222,6 @@ const formatBillingCycle = (duration) => {
|
|
|
222
222
|
if (duration === "day") return "daily";
|
|
223
223
|
return `every ${duration}`;
|
|
224
224
|
};
|
|
225
|
-
|
|
226
225
|
//#endregion
|
|
227
226
|
//#region src/utils/getPriceFromPlan.ts
|
|
228
227
|
const getPriceFromPlan = (plan) => {
|
|
@@ -231,7 +230,6 @@ const getPriceFromPlan = (plan) => {
|
|
|
231
230
|
yearly: plan.yearlyPrice != null ? parseFloat(plan.yearlyPrice) : 0
|
|
232
231
|
};
|
|
233
232
|
};
|
|
234
|
-
|
|
235
233
|
//#endregion
|
|
236
234
|
//#region src/utils/purchaseDetails.ts
|
|
237
235
|
const getPlanFromPurchaseDetails = (response) => {
|
|
@@ -249,7 +247,6 @@ const getTaxLabelFromPurchaseDetails = (response) => {
|
|
|
249
247
|
const isTaxInclusiveFromPurchaseDetails = (response) => {
|
|
250
248
|
return response.tax?.taxInclusive === true;
|
|
251
249
|
};
|
|
252
|
-
|
|
253
250
|
//#endregion
|
|
254
251
|
//#region src/ZuploMonetizationWrapper.tsx
|
|
255
252
|
const DEFAULT_GATEWAY_URL = "https://api.zuploedge.com";
|
|
@@ -321,7 +318,6 @@ const ZuploMonetizationWrapper = ({ options = {} }) => /* @__PURE__ */ jsx(Query
|
|
|
321
318
|
children: /* @__PURE__ */ jsx(ClientOnly, { children: /* @__PURE__ */ jsx(Outlet, {}) })
|
|
322
319
|
})
|
|
323
320
|
});
|
|
324
|
-
|
|
325
321
|
//#endregion
|
|
326
322
|
//#region src/pages/CheckoutConfirmPage.tsx
|
|
327
323
|
const CheckoutConfirmPage = () => {
|
|
@@ -418,8 +414,8 @@ const CheckoutConfirmPage = () => {
|
|
|
418
414
|
children: formatPrice(price.monthly, selectedPlan?.currency)
|
|
419
415
|
}),
|
|
420
416
|
taxAmount != null && /* @__PURE__ */ jsx("div", {
|
|
421
|
-
className: "text-
|
|
422
|
-
children: taxInclusive ? `${
|
|
417
|
+
className: "text-sm font-normal mt-1",
|
|
418
|
+
children: taxInclusive ? `${formatMinorCurrencyAmount(taxAmount, selectedPlan?.currency)} ${taxLabel} included` : `+ ${formatMinorCurrencyAmount(taxAmount, selectedPlan?.currency)} ${taxLabel}`
|
|
423
419
|
}),
|
|
424
420
|
billingCycle && /* @__PURE__ */ jsxs("div", {
|
|
425
421
|
className: "text-sm text-muted-foreground font-normal",
|
|
@@ -485,7 +481,6 @@ const CheckoutConfirmPage = () => {
|
|
|
485
481
|
})
|
|
486
482
|
});
|
|
487
483
|
};
|
|
488
|
-
|
|
489
484
|
//#endregion
|
|
490
485
|
//#region src/components/RedirectPage.tsx
|
|
491
486
|
const RedirectPage = ({ icon: Icon, title, description, url, children }) => {
|
|
@@ -534,7 +529,6 @@ const RedirectPage = ({ icon: Icon, title, description, url, children }) => {
|
|
|
534
529
|
})
|
|
535
530
|
});
|
|
536
531
|
};
|
|
537
|
-
|
|
538
532
|
//#endregion
|
|
539
533
|
//#region src/hooks/useUrlUtils.ts
|
|
540
534
|
const useUrlUtils = () => {
|
|
@@ -544,7 +538,6 @@ const useUrlUtils = () => {
|
|
|
544
538
|
return joinUrl(window.location.origin, basePath, path, searchParams ? `?${new URLSearchParams(searchParams)}` : void 0);
|
|
545
539
|
} };
|
|
546
540
|
};
|
|
547
|
-
|
|
548
541
|
//#endregion
|
|
549
542
|
//#region src/pages/CheckoutPage.tsx
|
|
550
543
|
const CheckoutPage = () => {
|
|
@@ -595,7 +588,6 @@ const CheckoutPage = () => {
|
|
|
595
588
|
})
|
|
596
589
|
});
|
|
597
590
|
};
|
|
598
|
-
|
|
599
591
|
//#endregion
|
|
600
592
|
//#region src/pages/ManagePaymentPage.tsx
|
|
601
593
|
const ManagePaymentPage = () => {
|
|
@@ -638,7 +630,6 @@ const ManagePaymentPage = () => {
|
|
|
638
630
|
})
|
|
639
631
|
});
|
|
640
632
|
};
|
|
641
|
-
|
|
642
633
|
//#endregion
|
|
643
634
|
//#region src/hooks/usePlans.ts
|
|
644
635
|
const usePlans = () => {
|
|
@@ -649,7 +640,6 @@ const usePlans = () => {
|
|
|
649
640
|
meta: { context: auth.isAuthenticated ? zudoku : void 0 }
|
|
650
641
|
});
|
|
651
642
|
};
|
|
652
|
-
|
|
653
643
|
//#endregion
|
|
654
644
|
//#region src/pages/pricing/PricingCard.tsx
|
|
655
645
|
const PhaseSection = ({ phase, currency, showName, billingCadence }) => {
|
|
@@ -756,7 +746,6 @@ const PricingCard = ({ plan, isPopular = false, isSubscribed = false }) => {
|
|
|
756
746
|
]
|
|
757
747
|
});
|
|
758
748
|
};
|
|
759
|
-
|
|
760
749
|
//#endregion
|
|
761
750
|
//#region src/pages/PricingPage.tsx
|
|
762
751
|
const PricingPage = () => {
|
|
@@ -807,7 +796,6 @@ const PricingPage = () => {
|
|
|
807
796
|
]
|
|
808
797
|
});
|
|
809
798
|
};
|
|
810
|
-
|
|
811
799
|
//#endregion
|
|
812
800
|
//#region src/pages/PricingPageSkeleton.tsx
|
|
813
801
|
const PricingPageSkeleton = () => /* @__PURE__ */ jsxs("div", {
|
|
@@ -838,7 +826,6 @@ const PricingPageSkeleton = () => /* @__PURE__ */ jsxs("div", {
|
|
|
838
826
|
}, i))
|
|
839
827
|
})]
|
|
840
828
|
});
|
|
841
|
-
|
|
842
829
|
//#endregion
|
|
843
830
|
//#region src/pages/SubscriptionChangeConfirmPage.tsx
|
|
844
831
|
const SubscriptionChangeConfirmPage = () => {
|
|
@@ -944,8 +931,8 @@ const SubscriptionChangeConfirmPage = () => {
|
|
|
944
931
|
children: formatPrice(price.monthly, selectedPlan?.currency)
|
|
945
932
|
}),
|
|
946
933
|
taxAmount != null && /* @__PURE__ */ jsx("div", {
|
|
947
|
-
className: "text-
|
|
948
|
-
children: taxInclusive ? `${
|
|
934
|
+
className: "text-sm font-normal mt-1",
|
|
935
|
+
children: taxInclusive ? `${formatMinorCurrencyAmount(taxAmount, selectedPlan?.currency)} ${taxLabel} included` : `+ ${formatMinorCurrencyAmount(taxAmount, selectedPlan?.currency)} ${taxLabel}`
|
|
949
936
|
}),
|
|
950
937
|
billingCycle && /* @__PURE__ */ jsxs("div", {
|
|
951
938
|
className: "text-sm text-muted-foreground font-normal",
|
|
@@ -1006,7 +993,6 @@ const SubscriptionChangeConfirmPage = () => {
|
|
|
1006
993
|
})
|
|
1007
994
|
});
|
|
1008
995
|
};
|
|
1009
|
-
|
|
1010
996
|
//#endregion
|
|
1011
997
|
//#region src/hooks/useSubscriptions.ts
|
|
1012
998
|
const useSubscriptions = (environmentName) => {
|
|
@@ -1024,7 +1010,6 @@ const useSubscriptions = (environmentName) => {
|
|
|
1024
1010
|
})
|
|
1025
1011
|
});
|
|
1026
1012
|
};
|
|
1027
|
-
|
|
1028
1013
|
//#endregion
|
|
1029
1014
|
//#region src/pages/subscriptions/ConfirmDeleteKeyAlert.tsx
|
|
1030
1015
|
const ConfirmDeleteKeyAlert = ({ children, onDelete }) => {
|
|
@@ -1036,10 +1021,9 @@ const ConfirmDeleteKeyAlert = ({ children, onDelete }) => {
|
|
|
1036
1021
|
children: "Continue"
|
|
1037
1022
|
})] })] })] });
|
|
1038
1023
|
};
|
|
1039
|
-
|
|
1040
1024
|
//#endregion
|
|
1041
1025
|
//#region src/pages/subscriptions/ApiKey.tsx
|
|
1042
|
-
const formatDate$
|
|
1026
|
+
const formatDate$2 = (dateString) => {
|
|
1043
1027
|
if (!dateString) return "";
|
|
1044
1028
|
return new Date(dateString).toLocaleDateString("en-US", {
|
|
1045
1029
|
month: "short",
|
|
@@ -1050,8 +1034,7 @@ const formatDate$1 = (dateString) => {
|
|
|
1050
1034
|
const getTimeAgo = (dateString) => {
|
|
1051
1035
|
if (!dateString) return "Never";
|
|
1052
1036
|
const date = new Date(dateString);
|
|
1053
|
-
const
|
|
1054
|
-
const diffInMinutes = Math.floor((now.getTime() - date.getTime()) / (1e3 * 60));
|
|
1037
|
+
const diffInMinutes = Math.floor(((/* @__PURE__ */ new Date()).getTime() - date.getTime()) / (1e3 * 60));
|
|
1055
1038
|
if (diffInMinutes < 1) return "Just now";
|
|
1056
1039
|
if (diffInMinutes < 60) return `${diffInMinutes} minutes ago`;
|
|
1057
1040
|
const diffInHours = Math.floor(diffInMinutes / 60);
|
|
@@ -1059,7 +1042,7 @@ const getTimeAgo = (dateString) => {
|
|
|
1059
1042
|
const diffInDays = Math.floor(diffInHours / 24);
|
|
1060
1043
|
if (diffInDays === 1) return "1 day ago";
|
|
1061
1044
|
if (diffInDays < 30) return `${diffInDays} days ago`;
|
|
1062
|
-
return formatDate$
|
|
1045
|
+
return formatDate$2(dateString);
|
|
1063
1046
|
};
|
|
1064
1047
|
const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label, onDelete }) => {
|
|
1065
1048
|
const isExpiring = expiresOn && new Date(expiresOn) < new Date(Date.now() + 720 * 60 * 60 * 1e3);
|
|
@@ -1116,7 +1099,7 @@ const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label
|
|
|
1116
1099
|
children: [
|
|
1117
1100
|
/* @__PURE__ */ jsxs("div", {
|
|
1118
1101
|
className: "flex items-center gap-1.5",
|
|
1119
|
-
children: [/* @__PURE__ */ jsx(ClockIcon, { className: "size-3" }), /* @__PURE__ */ jsxs("span", { children: ["Created ", formatDate$
|
|
1102
|
+
children: [/* @__PURE__ */ jsx(ClockIcon, { className: "size-3" }), /* @__PURE__ */ jsxs("span", { children: ["Created ", formatDate$2(createdAt)] })]
|
|
1120
1103
|
}),
|
|
1121
1104
|
/* @__PURE__ */ jsx("span", {
|
|
1122
1105
|
className: "text-muted-foreground/40",
|
|
@@ -1131,7 +1114,7 @@ const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label
|
|
|
1131
1114
|
children: [
|
|
1132
1115
|
isExpired ? "Expired" : "Expires",
|
|
1133
1116
|
" on ",
|
|
1134
|
-
formatDate$
|
|
1117
|
+
formatDate$2(expiresOn)
|
|
1135
1118
|
]
|
|
1136
1119
|
})] })
|
|
1137
1120
|
]
|
|
@@ -1139,7 +1122,6 @@ const ApiKey = ({ apiKey, createdAt, lastUsed, expiresOn, isActive = true, label
|
|
|
1139
1122
|
})]
|
|
1140
1123
|
});
|
|
1141
1124
|
};
|
|
1142
|
-
|
|
1143
1125
|
//#endregion
|
|
1144
1126
|
//#region src/pages/subscriptions/ApiKeyInfo.tsx
|
|
1145
1127
|
const ApiKeyInfo = () => /* @__PURE__ */ jsxs(DismissibleAlert, {
|
|
@@ -1159,7 +1141,6 @@ const ApiKeyInfo = () => /* @__PURE__ */ jsxs(DismissibleAlert, {
|
|
|
1159
1141
|
/* @__PURE__ */ jsx(DismissibleAlertAction, {})
|
|
1160
1142
|
]
|
|
1161
1143
|
});
|
|
1162
|
-
|
|
1163
1144
|
//#endregion
|
|
1164
1145
|
//#region src/pages/subscriptions/ConfirmRollKeyAlert.tsx
|
|
1165
1146
|
const ConfirmRollKeyAlert = (props) => /* @__PURE__ */ jsxs(AlertDialog, { children: [/* @__PURE__ */ jsx(AlertDialogTrigger, {
|
|
@@ -1169,7 +1150,6 @@ const ConfirmRollKeyAlert = (props) => /* @__PURE__ */ jsxs(AlertDialog, { child
|
|
|
1169
1150
|
onClick: props.onRollKey,
|
|
1170
1151
|
children: "Continue"
|
|
1171
1152
|
})] })] })] });
|
|
1172
|
-
|
|
1173
1153
|
//#endregion
|
|
1174
1154
|
//#region src/pages/subscriptions/ApiKeysList.tsx
|
|
1175
1155
|
const PendingFirstPaymentAlert = ({ children }) => /* @__PURE__ */ jsxs("div", {
|
|
@@ -1249,7 +1229,7 @@ const ApiKeysList = ({ isPendingFirstPayment, apiKeys, deploymentName, consumerI
|
|
|
1249
1229
|
/* @__PURE__ */ jsx(AlertTitle, { children: "API key was deleted" }),
|
|
1250
1230
|
/* @__PURE__ */ jsx(AlertDescription, { children: (() => {
|
|
1251
1231
|
const deletedKey = apiKeys.find((k) => k.id === deleteKeyMutation.variables?.keyId);
|
|
1252
|
-
return deletedKey ? `API key created ${formatDate$
|
|
1232
|
+
return deletedKey ? `API key created ${formatDate$2(deletedKey.createdOn)} has been removed.` : "The API key has been deleted.";
|
|
1253
1233
|
})() }),
|
|
1254
1234
|
/* @__PURE__ */ jsx(DismissibleAlertAction, {})
|
|
1255
1235
|
]
|
|
@@ -1321,7 +1301,6 @@ const ApiKeysList = ({ isPendingFirstPayment, apiKeys, deploymentName, consumerI
|
|
|
1321
1301
|
]
|
|
1322
1302
|
});
|
|
1323
1303
|
};
|
|
1324
|
-
|
|
1325
1304
|
//#endregion
|
|
1326
1305
|
//#region src/pages/subscriptions/CancelSubscriptionDialog.tsx
|
|
1327
1306
|
const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId, billingPeriodEnd }) => {
|
|
@@ -1361,7 +1340,7 @@ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId
|
|
|
1361
1340
|
/* @__PURE__ */ jsx(AlertTitle, { children: "Your plan will be canceled at the end of your billing cycle." }),
|
|
1362
1341
|
/* @__PURE__ */ jsxs(AlertDescription, { children: [
|
|
1363
1342
|
"You'll retain access until ",
|
|
1364
|
-
formatDate$
|
|
1343
|
+
formatDate$2(billingPeriodEnd),
|
|
1365
1344
|
". After your billing period ends, this plan will not renew and you would need to subscribe again to continue."
|
|
1366
1345
|
] })
|
|
1367
1346
|
]
|
|
@@ -1374,7 +1353,7 @@ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId
|
|
|
1374
1353
|
/* @__PURE__ */ jsxs(AlertDescription, { children: [
|
|
1375
1354
|
"If you change your mind you have until",
|
|
1376
1355
|
" ",
|
|
1377
|
-
formatDate$
|
|
1356
|
+
formatDate$2(billingPeriodEnd),
|
|
1378
1357
|
" to remove this cancellation from Manage subscription."
|
|
1379
1358
|
] })
|
|
1380
1359
|
]
|
|
@@ -1428,7 +1407,6 @@ const CancelSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId
|
|
|
1428
1407
|
})
|
|
1429
1408
|
});
|
|
1430
1409
|
};
|
|
1431
|
-
|
|
1432
1410
|
//#endregion
|
|
1433
1411
|
//#region src/pages/subscriptions/RestoreSubscriptionDialog.tsx
|
|
1434
1412
|
const RestoreSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionId, billingPeriodEnd }) => {
|
|
@@ -1478,7 +1456,7 @@ const RestoreSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionI
|
|
|
1478
1456
|
className: "space-y-2",
|
|
1479
1457
|
children: [/* @__PURE__ */ jsxs("p", { children: [
|
|
1480
1458
|
"Your access stays in place until ",
|
|
1481
|
-
formatDate$
|
|
1459
|
+
formatDate$2(billingPeriodEnd),
|
|
1482
1460
|
" ",
|
|
1483
1461
|
"either way."
|
|
1484
1462
|
] }), /* @__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." })]
|
|
@@ -1510,7 +1488,6 @@ const RestoreSubscriptionDialog = ({ open, onOpenChange, planName, subscriptionI
|
|
|
1510
1488
|
})
|
|
1511
1489
|
});
|
|
1512
1490
|
};
|
|
1513
|
-
|
|
1514
1491
|
//#endregion
|
|
1515
1492
|
//#region src/pages/subscriptions/SwitchPlanModal.tsx
|
|
1516
1493
|
const getAllKeysAcrossPhases = (plan, units) => {
|
|
@@ -1660,6 +1637,7 @@ const ChangeIndicator = ({ change }) => {
|
|
|
1660
1637
|
if (change === "decrease" || change === "removed" || change === "downgraded") return /* @__PURE__ */ jsx(ArrowDownIcon, { className: "w-4 h-4 text-amber-600 shrink-0" });
|
|
1661
1638
|
return /* @__PURE__ */ jsx(CheckIcon, { className: "w-4 h-4 text-green-600 shrink-0" });
|
|
1662
1639
|
};
|
|
1640
|
+
const isPrivatePlan = (plan) => plan.metadata?.zuplo_private_plan === "true";
|
|
1663
1641
|
const modeLabelMap = {
|
|
1664
1642
|
upgrade: "Upgrade",
|
|
1665
1643
|
downgrade: "Downgrade",
|
|
@@ -1850,12 +1828,29 @@ const SwitchPlanModal = ({ subscription, children }) => {
|
|
|
1850
1828
|
});
|
|
1851
1829
|
const currentPlan = plansData?.items.find((p) => p.key === subscription.plan.key);
|
|
1852
1830
|
const { upgrades, downgrades, privatePlans } = useMemo(() => {
|
|
1853
|
-
if (!plansData?.items
|
|
1831
|
+
if (!plansData?.items) return {
|
|
1854
1832
|
upgrades: [],
|
|
1855
1833
|
downgrades: [],
|
|
1856
1834
|
privatePlans: []
|
|
1857
1835
|
};
|
|
1858
|
-
|
|
1836
|
+
if (!currentPlan) {
|
|
1837
|
+
const currentIndex = -1;
|
|
1838
|
+
return {
|
|
1839
|
+
upgrades: plansData.items.map((plan, targetIndex) => comparePlans(void 0, plan, currentIndex, targetIndex, pricing?.units)).filter((c) => !isPrivatePlan(c.plan)),
|
|
1840
|
+
downgrades: [],
|
|
1841
|
+
privatePlans: []
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
if (isPrivatePlan(currentPlan)) {
|
|
1845
|
+
const currentIndex = plansData.items.findIndex((p) => p.id === currentPlan.id);
|
|
1846
|
+
return {
|
|
1847
|
+
upgrades: plansData.items.filter((p) => p.id !== currentPlan.id).map((plan) => {
|
|
1848
|
+
return comparePlans(currentPlan, plan, currentIndex, plansData.items.indexOf(plan), pricing?.units);
|
|
1849
|
+
}).filter((c) => !isPrivatePlan(c.plan)),
|
|
1850
|
+
downgrades: [],
|
|
1851
|
+
privatePlans: []
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1859
1854
|
const currentIndex = plansData.items.findIndex((p) => p.id === currentPlan.id);
|
|
1860
1855
|
const allComparisons = plansData.items.filter((p) => p.id !== currentPlan.id).map((plan) => {
|
|
1861
1856
|
return comparePlans(currentPlan, plan, currentIndex, plansData.items.indexOf(plan), pricing?.units);
|
|
@@ -1905,6 +1900,13 @@ const SwitchPlanModal = ({ subscription, children }) => {
|
|
|
1905
1900
|
children: currentPlan.name
|
|
1906
1901
|
})] })
|
|
1907
1902
|
}),
|
|
1903
|
+
!currentPlan && /* @__PURE__ */ jsx(Item, {
|
|
1904
|
+
variant: "outline",
|
|
1905
|
+
children: /* @__PURE__ */ jsxs(ItemContent, { children: [/* @__PURE__ */ jsx(ItemTitle, { children: "Current Plan" }), /* @__PURE__ */ jsx(ItemDescription, {
|
|
1906
|
+
className: "text-lg font-bold",
|
|
1907
|
+
children: subscription.plan.name
|
|
1908
|
+
})] })
|
|
1909
|
+
}),
|
|
1908
1910
|
upgrades.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
1909
1911
|
className: "flex items-center justify-between mb-3",
|
|
1910
1912
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -1976,7 +1978,6 @@ const SwitchPlanModal = ({ subscription, children }) => {
|
|
|
1976
1978
|
}) })]
|
|
1977
1979
|
});
|
|
1978
1980
|
};
|
|
1979
|
-
|
|
1980
1981
|
//#endregion
|
|
1981
1982
|
//#region src/pages/subscriptions/ManageSubscription.tsx
|
|
1982
1983
|
const ManageSubscription = ({ subscription, planName }) => {
|
|
@@ -2068,7 +2069,217 @@ const ManageSubscription = ({ subscription, planName }) => {
|
|
|
2068
2069
|
})
|
|
2069
2070
|
] });
|
|
2070
2071
|
};
|
|
2071
|
-
|
|
2072
|
+
//#endregion
|
|
2073
|
+
//#region src/pages/subscriptions/SubscriptionPlanDetails.tsx
|
|
2074
|
+
const detailLabelClassName = "text-sm font-semibold tracking-wide mb-1";
|
|
2075
|
+
const sectionLabelClassName = "text-base font-semibold tracking-wide mb-3 mt-2";
|
|
2076
|
+
const formatDate$1 = (dateString) => {
|
|
2077
|
+
return new Date(dateString).toLocaleDateString("en-US", {
|
|
2078
|
+
month: "short",
|
|
2079
|
+
day: "numeric",
|
|
2080
|
+
year: "numeric"
|
|
2081
|
+
});
|
|
2082
|
+
};
|
|
2083
|
+
const formatDateRange = (from, to) => `${formatDate$1(from)} – ${formatDate$1(to)}`;
|
|
2084
|
+
const formatNumber = (value) => value.toLocaleString("en-US");
|
|
2085
|
+
const getOveragePriceFromItem = (item, currency, units) => {
|
|
2086
|
+
const tiers = item.price?.tiers;
|
|
2087
|
+
if (!tiers || tiers.length === 0) return void 0;
|
|
2088
|
+
const amount = tiers.find((t) => {
|
|
2089
|
+
const amount = t.unitPrice?.amount;
|
|
2090
|
+
if (!amount) return false;
|
|
2091
|
+
const parsed = parseFloat(amount);
|
|
2092
|
+
return Number.isFinite(parsed) && parsed > 0;
|
|
2093
|
+
})?.unitPrice?.amount;
|
|
2094
|
+
if (!amount) return void 0;
|
|
2095
|
+
const parsed = parseFloat(amount);
|
|
2096
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
|
|
2097
|
+
const unitLabel = units?.[item.key] ?? units?.[item.featureKey] ?? "unit";
|
|
2098
|
+
return `${formatPrice(parsed, currency)}/${unitLabel}`;
|
|
2099
|
+
};
|
|
2100
|
+
const getEntitlementsFromItems = (items, currency, units, fallbackBillingCadence) => {
|
|
2101
|
+
const features = [];
|
|
2102
|
+
for (const item of items) {
|
|
2103
|
+
const entitlement = item.included?.entitlement;
|
|
2104
|
+
if (!entitlement) continue;
|
|
2105
|
+
if (entitlement.type === "metered" && entitlement.issueAfterReset != null) {
|
|
2106
|
+
const cadence = item.billingCadence ?? fallbackBillingCadence;
|
|
2107
|
+
features.push({
|
|
2108
|
+
entitlementType: "metered",
|
|
2109
|
+
key: item.featureKey ?? item.key,
|
|
2110
|
+
name: item.name ?? item.featureKey ?? item.key,
|
|
2111
|
+
limit: entitlement.issueAfterReset,
|
|
2112
|
+
period: cadence ? formatDuration(cadence) : "month",
|
|
2113
|
+
overagePrice: entitlement.isSoftLimit !== false ? getOveragePriceFromItem(item, currency, units) : void 0
|
|
2114
|
+
});
|
|
2115
|
+
continue;
|
|
2116
|
+
}
|
|
2117
|
+
if (entitlement.type === "boolean") {
|
|
2118
|
+
features.push({
|
|
2119
|
+
entitlementType: "boolean",
|
|
2120
|
+
key: item.featureKey ?? item.key,
|
|
2121
|
+
name: item.name ?? item.featureKey ?? item.key
|
|
2122
|
+
});
|
|
2123
|
+
continue;
|
|
2124
|
+
}
|
|
2125
|
+
if (entitlement.type === "static") {
|
|
2126
|
+
const base = {
|
|
2127
|
+
key: item.featureKey ?? item.key,
|
|
2128
|
+
name: item.name ?? item.featureKey ?? item.key
|
|
2129
|
+
};
|
|
2130
|
+
if (!entitlement.config) {
|
|
2131
|
+
features.push({
|
|
2132
|
+
entitlementType: "static",
|
|
2133
|
+
...base
|
|
2134
|
+
});
|
|
2135
|
+
continue;
|
|
2136
|
+
}
|
|
2137
|
+
try {
|
|
2138
|
+
const parsed = JSON.parse(entitlement.config);
|
|
2139
|
+
features.push({
|
|
2140
|
+
entitlementType: "static",
|
|
2141
|
+
...base,
|
|
2142
|
+
value: parsed?.value != null ? String(parsed.value) : void 0
|
|
2143
|
+
});
|
|
2144
|
+
} catch {
|
|
2145
|
+
features.push({
|
|
2146
|
+
entitlementType: "static",
|
|
2147
|
+
...base
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
return { features };
|
|
2153
|
+
};
|
|
2154
|
+
const getPhaseRows = (opts) => {
|
|
2155
|
+
const { subscription, currency, units } = opts;
|
|
2156
|
+
const phases = [...subscription.phases].sort((a, b) => new Date(a.activeFrom).getTime() - new Date(b.activeFrom).getTime());
|
|
2157
|
+
const featureRows = [];
|
|
2158
|
+
for (const phase of phases) {
|
|
2159
|
+
const { features } = getEntitlementsFromItems(phase.items ?? [], currency, units, subscription.billingCadence);
|
|
2160
|
+
for (const f of features) featureRows.push({
|
|
2161
|
+
key: f.key,
|
|
2162
|
+
name: f.name,
|
|
2163
|
+
entitlementType: f.entitlementType,
|
|
2164
|
+
limit: f.entitlementType === "metered" ? f.limit : void 0,
|
|
2165
|
+
period: f.entitlementType === "metered" ? f.period : void 0,
|
|
2166
|
+
overagePrice: f.entitlementType === "metered" ? f.overagePrice : void 0,
|
|
2167
|
+
value: f.entitlementType === "static" ? f.value : void 0,
|
|
2168
|
+
phaseId: phase.id,
|
|
2169
|
+
activeFrom: phase.activeFrom,
|
|
2170
|
+
activeTo: phase.activeTo
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
return { featureRows };
|
|
2174
|
+
};
|
|
2175
|
+
const formatActiveRange = (activeFrom, activeTo) => {
|
|
2176
|
+
if (!activeTo) return `Starts ${formatDate$1(activeFrom)}`;
|
|
2177
|
+
return `${formatDate$1(activeFrom)} – ${formatDate$1(activeTo)}`;
|
|
2178
|
+
};
|
|
2179
|
+
const SubscriptionPlanDetails = ({ subscription }) => {
|
|
2180
|
+
const { pricing } = useMonetizationConfig();
|
|
2181
|
+
const plan = subscription.plan;
|
|
2182
|
+
const currency = subscription.currency ?? plan.currency;
|
|
2183
|
+
const priceInfo = getPriceFromPlan(plan);
|
|
2184
|
+
const primaryPrice = priceInfo.monthly === 0 && priceInfo.yearly === 0 ? /* @__PURE__ */ jsx("span", {
|
|
2185
|
+
className: "text-primary font-medium",
|
|
2186
|
+
children: "Free"
|
|
2187
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
2188
|
+
className: "text-primary font-medium text-lg",
|
|
2189
|
+
children: formatPrice(priceInfo.monthly, currency)
|
|
2190
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
2191
|
+
className: "text-muted-foreground",
|
|
2192
|
+
children: [" / ", formatDuration(plan.billingCadence)]
|
|
2193
|
+
})] });
|
|
2194
|
+
const { featureRows } = getPhaseRows({
|
|
2195
|
+
subscription,
|
|
2196
|
+
currency,
|
|
2197
|
+
units: pricing?.units
|
|
2198
|
+
});
|
|
2199
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2200
|
+
className: "space-y-4",
|
|
2201
|
+
children: [/* @__PURE__ */ jsx(Heading, {
|
|
2202
|
+
level: 3,
|
|
2203
|
+
children: "Subscription Details"
|
|
2204
|
+
}), /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsxs(CardHeader, { children: [/* @__PURE__ */ jsx(CardTitle, {
|
|
2205
|
+
className: "text-lg font-semibold leading-tight",
|
|
2206
|
+
children: plan.name
|
|
2207
|
+
}), plan.description ? /* @__PURE__ */ jsx(CardDescription, { children: plan.description }) : null] }), /* @__PURE__ */ jsxs(CardContent, {
|
|
2208
|
+
className: "space-y-6",
|
|
2209
|
+
children: [/* @__PURE__ */ jsxs("dl", {
|
|
2210
|
+
className: "grid gap-4 sm:grid-cols-2 text-sm",
|
|
2211
|
+
children: [
|
|
2212
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2213
|
+
className: detailLabelClassName,
|
|
2214
|
+
children: "Subscription ID"
|
|
2215
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2216
|
+
className: "text-foreground font-mono text-xs break-all",
|
|
2217
|
+
children: subscription.id
|
|
2218
|
+
})] }),
|
|
2219
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2220
|
+
className: detailLabelClassName,
|
|
2221
|
+
children: "Active since"
|
|
2222
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2223
|
+
className: "text-foreground",
|
|
2224
|
+
children: formatDate$1(subscription.activeFrom)
|
|
2225
|
+
})] }),
|
|
2226
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2227
|
+
className: detailLabelClassName,
|
|
2228
|
+
children: "Price"
|
|
2229
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2230
|
+
className: "flex flex-wrap items-baseline gap-1",
|
|
2231
|
+
children: primaryPrice
|
|
2232
|
+
})] }),
|
|
2233
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
|
|
2234
|
+
className: detailLabelClassName,
|
|
2235
|
+
children: "Current period"
|
|
2236
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
2237
|
+
className: "text-foreground",
|
|
2238
|
+
children: subscription.alignment?.currentAlignedBillingPeriod ? formatDateRange(subscription.alignment.currentAlignedBillingPeriod.from, subscription.alignment.currentAlignedBillingPeriod.to) : "—"
|
|
2239
|
+
})] })
|
|
2240
|
+
]
|
|
2241
|
+
}), featureRows.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
2242
|
+
className: "space-y-5 pt-2 border-t border-border",
|
|
2243
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2244
|
+
className: "space-y-2",
|
|
2245
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
2246
|
+
className: cn(sectionLabelClassName, "mb-5"),
|
|
2247
|
+
children: "Entitlements"
|
|
2248
|
+
}), /* @__PURE__ */ jsx("ul", {
|
|
2249
|
+
className: "space-y-3",
|
|
2250
|
+
children: featureRows.map((row) => /* @__PURE__ */ jsxs("li", {
|
|
2251
|
+
className: "grid gap-1 text-sm sm:grid-cols-4 sm:items-center sm:gap-4",
|
|
2252
|
+
children: [
|
|
2253
|
+
/* @__PURE__ */ jsx("div", {
|
|
2254
|
+
className: "flex items-start gap-2 text-muted-foreground sm:col-span-2",
|
|
2255
|
+
children: /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsxs("span", {
|
|
2256
|
+
className: "text-foreground font-medium",
|
|
2257
|
+
children: [row.name, " "]
|
|
2258
|
+
}), row.entitlementType === "static" && row.value ? `: ${row.value}` : ""] })
|
|
2259
|
+
}),
|
|
2260
|
+
/* @__PURE__ */ jsx("div", {
|
|
2261
|
+
className: "text-muted-foreground sm:text-right",
|
|
2262
|
+
children: row.entitlementType === "metered" && row.limit != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2263
|
+
formatNumber(row.limit),
|
|
2264
|
+
row.period ? ` / ${row.period}` : "",
|
|
2265
|
+
row.overagePrice ? /* @__PURE__ */ jsxs("div", {
|
|
2266
|
+
className: "text-xs mt-0.5",
|
|
2267
|
+
children: ["Overage: ", row.overagePrice]
|
|
2268
|
+
}) : null
|
|
2269
|
+
] }) : row.entitlementType === "static" && row.value ? row.value : "Included"
|
|
2270
|
+
}),
|
|
2271
|
+
/* @__PURE__ */ jsx("div", {
|
|
2272
|
+
className: "text-xs text-muted-foreground sm:text-right",
|
|
2273
|
+
children: formatActiveRange(row.activeFrom, row.activeTo)
|
|
2274
|
+
})
|
|
2275
|
+
]
|
|
2276
|
+
}, `${row.key}:${row.phaseId}`))
|
|
2277
|
+
})]
|
|
2278
|
+
})
|
|
2279
|
+
}) : null]
|
|
2280
|
+
})] })]
|
|
2281
|
+
});
|
|
2282
|
+
};
|
|
2072
2283
|
//#endregion
|
|
2073
2284
|
//#region src/pages/subscriptions/Usage.tsx
|
|
2074
2285
|
const isMeteredEntitlement = (entitlement) => {
|
|
@@ -2228,7 +2439,6 @@ const Usage = ({ usage, isFetching, currentItems, subscription, isPendingFirstPa
|
|
|
2228
2439
|
]
|
|
2229
2440
|
});
|
|
2230
2441
|
};
|
|
2231
|
-
|
|
2232
2442
|
//#endregion
|
|
2233
2443
|
//#region src/pages/subscriptions/ActiveSubscription.tsx
|
|
2234
2444
|
const ActiveSubscription = ({ subscription, deploymentName }) => {
|
|
@@ -2252,6 +2462,7 @@ const ActiveSubscription = ({ subscription, deploymentName }) => {
|
|
|
2252
2462
|
/* @__PURE__ */ jsx(DismissibleAlertAction, {})
|
|
2253
2463
|
]
|
|
2254
2464
|
}),
|
|
2465
|
+
/* @__PURE__ */ jsx(SubscriptionPlanDetails, { subscription }),
|
|
2255
2466
|
/* @__PURE__ */ jsx(Usage, {
|
|
2256
2467
|
currentItems: activePhase?.items,
|
|
2257
2468
|
usage: usageQuery.data,
|
|
@@ -2271,7 +2482,6 @@ const ActiveSubscription = ({ subscription, deploymentName }) => {
|
|
|
2271
2482
|
})
|
|
2272
2483
|
] });
|
|
2273
2484
|
};
|
|
2274
|
-
|
|
2275
2485
|
//#endregion
|
|
2276
2486
|
//#region src/pages/subscriptions/SubscriptionsList.tsx
|
|
2277
2487
|
const formatDate = (dateString) => {
|
|
@@ -2345,7 +2555,6 @@ const SubscriptionItem = ({ subscription, isSelected, isExpired }) => {
|
|
|
2345
2555
|
}, subscription.id)
|
|
2346
2556
|
});
|
|
2347
2557
|
};
|
|
2348
|
-
|
|
2349
2558
|
//#endregion
|
|
2350
2559
|
//#region src/pages/SubscriptionsPage.tsx
|
|
2351
2560
|
const SubscriptionsPage = () => {
|
|
@@ -2390,7 +2599,6 @@ const SubscriptionsPage = () => {
|
|
|
2390
2599
|
})]
|
|
2391
2600
|
});
|
|
2392
2601
|
};
|
|
2393
|
-
|
|
2394
2602
|
//#endregion
|
|
2395
2603
|
//#region src/pages/SubscriptionsPageSkeleton.tsx
|
|
2396
2604
|
const SubscriptionsPageSkeleton = () => /* @__PURE__ */ jsx("div", {
|
|
@@ -2424,7 +2632,6 @@ const SubscriptionsPageSkeleton = () => /* @__PURE__ */ jsx("div", {
|
|
|
2424
2632
|
]
|
|
2425
2633
|
})
|
|
2426
2634
|
});
|
|
2427
|
-
|
|
2428
2635
|
//#endregion
|
|
2429
2636
|
//#region src/ZuploMonetizationPlugin.tsx
|
|
2430
2637
|
const PRICING_PATH = "/pricing";
|
|
@@ -2511,6 +2718,5 @@ const zuploMonetizationPlugin = createPlugin((options = {}) => ({
|
|
|
2511
2718
|
];
|
|
2512
2719
|
}
|
|
2513
2720
|
}));
|
|
2514
|
-
|
|
2515
2721
|
//#endregion
|
|
2516
|
-
export { zuploMonetizationPlugin };
|
|
2722
|
+
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.32",
|
|
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",
|