@windrun-huaiin/third-ui 31.3.6 → 31.3.7

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.
@@ -17,7 +17,7 @@ const formatNumber = (locale, value) => new Intl.NumberFormat(locale, {
17
17
  maximumFractionDigits: 0,
18
18
  }).format(value);
19
19
  function CreditOverviewClient({ data, locale, translations, className, expiringSoonThresholdDays = 7, customActionHandlers, }) {
20
- var _a;
20
+ var _a, _b;
21
21
  const { redirectToSignIn } = nextjs.useClerk();
22
22
  const navPopover = creditNavButton.useCreditNavPopover();
23
23
  const isMobile = (_a = navPopover === null || navPopover === void 0 ? void 0 : navPopover.isMobile) !== null && _a !== void 0 ? _a : false;
@@ -59,6 +59,9 @@ function CreditOverviewClient({ data, locale, translations, className, expiringS
59
59
  const subscription = data.subscription;
60
60
  const pricingContext = data.pricingContext;
61
61
  const ctaBehaviors = data.ctaBehaviors;
62
+ const billingOptions = (_b = pricingContext === null || pricingContext === void 0 ? void 0 : pricingContext.moneyPriceData.billingSwitch.options) !== null && _b !== void 0 ? _b : [];
63
+ const subscriptionBillingEnabled = billingOptions.some((option) => option.key === 'monthly' || option.key === 'yearly');
64
+ const onetimeBillingEnabled = billingOptions.some((option) => option.key === 'onetime');
62
65
  const getModalMoneyPriceData = React.useCallback((mode) => {
63
66
  if (!pricingContext) {
64
67
  return null;
@@ -232,10 +235,10 @@ function CreditOverviewClient({ data, locale, translations, className, expiringS
232
235
  userToggledRef.current = true;
233
236
  setBucketExpanded(true);
234
237
  }, []);
235
- return (jsxRuntime.jsxs("section", { className: utils.cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxRuntime.jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsxRuntime.jsx(icons.GemIcon, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsxRuntime.jsx("span", { className: "text-base sm:text-lg", children: translations.totalLabel })] }), jsxRuntime.jsx("div", { className: "flex justify-center text-3xl font-semibold leading-tight sm:text-4xl", children: formatNumber(locale, data.totalBalance) }), jsxRuntime.jsxs("div", { className: "flex-1 flex-col gap-1", children: [jsxRuntime.jsx("p", { className: "text-xs text-gray-700 dark:text-slate-100 sm:text-sm", children: translations.subscriptionPeriodLabel }), jsxRuntime.jsx("h4", { className: "text-xl font-semibold sm:text-2xl", children: subscription ? subscription.planName : translations.subscriptionInactive })] }), jsxRuntime.jsx("div", { className: "pt-2 sm:pt-0", children: jsxRuntime.jsx(gradientButton.GradientButton, { title: subscription ? translations.subscriptionManage : translations.subscribePay, align: "center", icon: subscription ? jsxRuntime.jsx(icons.Settings2Icon, {}) : jsxRuntime.jsx(icons.BellIcon, {}), openInNewTab: false, className: "w-full", onClick: subscription ? handleManageAction : handleSubscribeAction }) })] }), jsxRuntime.jsx("div", { className: "absolute right-3 top-3 sm:right-6 sm:top-6", children: jsxRuntime.jsx(HoverInfo, { label: translations.totalLabel, description: translations.summaryDescription }) })] }), jsxRuntime.jsxs("section", { className: "relative flex flex-col gap-3 rounded-2xl border p-4 shadow-inner sm:gap-2 sm:p-5", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [jsxRuntime.jsx("h3", { className: "text-base text-gray-500 dark:text-slate-100 sm:text-lg", children: translations.bucketsTitle }), hasBuckets ? (jsxRuntime.jsx("button", { type: "button", "aria-expanded": bucketExpanded, "aria-label": bucketExpanded ? translations.hiddenDetail : translations.expandDetail, onClick: toggleBucketExpanded, className: "flex h-7 w-7 items-center justify-center rounded-full border border-transparent bg-white text-purple-600 shadow-[0_6px_20px_rgba(99,102,241,0.25)] transition-colors hover:text-purple-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-500 dark:bg-[#1b1541] dark:text-purple-100 dark:hover:text-purple-50 dark:shadow-[0_6px_22px_rgba(112,86,255,0.35)]", children: bucketExpanded ? (jsxRuntime.jsx(icons.ChevronUpIcon, { className: "h-4 w-4" })) : (jsxRuntime.jsx(icons.ChevronDownIcon, { className: "h-4 w-4" })) })) : null] }), hasBuckets ? (bucketExpanded ? (jsxRuntime.jsx("ul", { className: "flex flex-col gap-2", children: buckets.map((bucket) => {
238
+ return (jsxRuntime.jsxs("section", { className: utils.cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxRuntime.jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsxRuntime.jsx(icons.GemIcon, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsxRuntime.jsx("span", { className: "text-base sm:text-lg", children: translations.totalLabel })] }), jsxRuntime.jsx("div", { className: "flex justify-center text-3xl font-semibold leading-tight sm:text-4xl", children: formatNumber(locale, data.totalBalance) }), subscriptionBillingEnabled ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex-1 flex-col gap-1", children: [jsxRuntime.jsx("p", { className: "text-xs text-gray-700 dark:text-slate-100 sm:text-sm", children: translations.subscriptionPeriodLabel }), jsxRuntime.jsx("h4", { className: "text-xl font-semibold sm:text-2xl", children: subscription ? subscription.planName : translations.subscriptionInactive })] }), jsxRuntime.jsx("div", { className: "pt-2 sm:pt-0", children: jsxRuntime.jsx(gradientButton.GradientButton, { title: subscription ? translations.subscriptionManage : translations.subscribePay, align: "center", icon: subscription ? jsxRuntime.jsx(icons.Settings2Icon, {}) : jsxRuntime.jsx(icons.BellIcon, {}), openInNewTab: false, className: "w-full", onClick: subscription ? handleManageAction : handleSubscribeAction }) })] })) : null] }), jsxRuntime.jsx("div", { className: "absolute right-3 top-3 sm:right-6 sm:top-6", children: jsxRuntime.jsx(HoverInfo, { label: translations.totalLabel, description: translations.summaryDescription }) })] }), jsxRuntime.jsxs("section", { className: "relative flex flex-col gap-3 rounded-2xl border p-4 shadow-inner sm:gap-2 sm:p-5", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [jsxRuntime.jsx("h3", { className: "text-base text-gray-500 dark:text-slate-100 sm:text-lg", children: translations.bucketsTitle }), hasBuckets ? (jsxRuntime.jsx("button", { type: "button", "aria-expanded": bucketExpanded, "aria-label": bucketExpanded ? translations.hiddenDetail : translations.expandDetail, onClick: toggleBucketExpanded, className: "flex h-7 w-7 items-center justify-center rounded-full border border-transparent bg-white text-purple-600 shadow-[0_6px_20px_rgba(99,102,241,0.25)] transition-colors hover:text-purple-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-500 dark:bg-[#1b1541] dark:text-purple-100 dark:hover:text-purple-50 dark:shadow-[0_6px_22px_rgba(112,86,255,0.35)]", children: bucketExpanded ? (jsxRuntime.jsx(icons.ChevronUpIcon, { className: "h-4 w-4" })) : (jsxRuntime.jsx(icons.ChevronDownIcon, { className: "h-4 w-4" })) })) : null] }), hasBuckets ? (bucketExpanded ? (jsxRuntime.jsx("ul", { className: "flex flex-col gap-2", children: buckets.map((bucket) => {
236
239
  const balanceDisplay = formatNumber(locale, bucket.balance);
237
240
  return (jsxRuntime.jsxs("li", { "data-credit-kind": bucket.kind, className: "rounded-2xl border border-slate-200/70 bg-white/85 px-3 py-3 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 sm:px-4", children: [jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_auto] items-center gap-3 text-xs sm:text-sm", children: [jsxRuntime.jsx("span", { className: "flex min-w-0 items-center gap-2", children: jsxRuntime.jsx("span", { className: "max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs text-purple-600 shadow-sm dark:bg-purple-500/20 dark:text-purple-100 sm:text-sm", children: bucket.computedLabel }) }), jsxRuntime.jsx("span", { className: "flex min-w-0 justify-end", children: jsxRuntime.jsx("span", { className: "text-right text-base font-semibold leading-tight text-gray-500 dark:text-slate-100 sm:text-lg", title: balanceDisplay, children: balanceDisplay }) })] }), jsxRuntime.jsx("div", { className: "mt-3 flex justify-end gap-2", children: jsxRuntime.jsxs("span", { className: "text-[11px] text-gray-500 dark:text-slate-100 sm:text-xs", children: [translations.expiredAtLabel, ": ", bucket.expiresAt] }) })] }, bucket.kind));
238
- }) })) : (jsxRuntime.jsx("button", { type: "button", onClick: expandBuckets, className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 hover:text-purple-500", children: translations.expandDetail }))) : (jsxRuntime.jsx("div", { className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform dark:border-slate-800/60 dark:bg-slate-900/60 text-center", children: translations.bucketsEmpty })), jsxRuntime.jsx(gradientButton.GradientButton, { title: translations.onetimeBuy, icon: jsxRuntime.jsx(icons.ShoppingCartIcon, {}), align: "center", className: "w-full text-sm sm:text-base", onClick: handleOnetimeAction })] })] }));
241
+ }) })) : (jsxRuntime.jsx("button", { type: "button", onClick: expandBuckets, className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 hover:text-purple-500", children: translations.expandDetail }))) : (jsxRuntime.jsx("div", { className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform dark:border-slate-800/60 dark:bg-slate-900/60 text-center", children: translations.bucketsEmpty })), onetimeBillingEnabled ? (jsxRuntime.jsx(gradientButton.GradientButton, { title: translations.onetimeBuy, icon: jsxRuntime.jsx(icons.ShoppingCartIcon, {}), align: "center", className: "w-full text-sm sm:text-base", onClick: handleOnetimeAction })) : null] })] }));
239
242
  }
240
243
  function deriveStatus(expiresAt, thresholdDays = 7) {
241
244
  if (!expiresAt) {
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { __awaiter } from 'tslib';
3
- import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
  import { useClerk } from '@clerk/nextjs';
5
5
  import { GradientButton } from '../buttons/gradient-button.mjs';
6
6
  import { useState, useRef, useCallback, useMemo, useLayoutEffect } from 'react';
@@ -15,7 +15,7 @@ const formatNumber = (locale, value) => new Intl.NumberFormat(locale, {
15
15
  maximumFractionDigits: 0,
16
16
  }).format(value);
17
17
  function CreditOverviewClient({ data, locale, translations, className, expiringSoonThresholdDays = 7, customActionHandlers, }) {
18
- var _a;
18
+ var _a, _b;
19
19
  const { redirectToSignIn } = useClerk();
20
20
  const navPopover = useCreditNavPopover();
21
21
  const isMobile = (_a = navPopover === null || navPopover === void 0 ? void 0 : navPopover.isMobile) !== null && _a !== void 0 ? _a : false;
@@ -57,6 +57,9 @@ function CreditOverviewClient({ data, locale, translations, className, expiringS
57
57
  const subscription = data.subscription;
58
58
  const pricingContext = data.pricingContext;
59
59
  const ctaBehaviors = data.ctaBehaviors;
60
+ const billingOptions = (_b = pricingContext === null || pricingContext === void 0 ? void 0 : pricingContext.moneyPriceData.billingSwitch.options) !== null && _b !== void 0 ? _b : [];
61
+ const subscriptionBillingEnabled = billingOptions.some((option) => option.key === 'monthly' || option.key === 'yearly');
62
+ const onetimeBillingEnabled = billingOptions.some((option) => option.key === 'onetime');
60
63
  const getModalMoneyPriceData = useCallback((mode) => {
61
64
  if (!pricingContext) {
62
65
  return null;
@@ -230,10 +233,10 @@ function CreditOverviewClient({ data, locale, translations, className, expiringS
230
233
  userToggledRef.current = true;
231
234
  setBucketExpanded(true);
232
235
  }, []);
233
- return (jsxs("section", { className: cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsx(GemIcon, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsx("span", { className: "text-base sm:text-lg", children: translations.totalLabel })] }), jsx("div", { className: "flex justify-center text-3xl font-semibold leading-tight sm:text-4xl", children: formatNumber(locale, data.totalBalance) }), jsxs("div", { className: "flex-1 flex-col gap-1", children: [jsx("p", { className: "text-xs text-gray-700 dark:text-slate-100 sm:text-sm", children: translations.subscriptionPeriodLabel }), jsx("h4", { className: "text-xl font-semibold sm:text-2xl", children: subscription ? subscription.planName : translations.subscriptionInactive })] }), jsx("div", { className: "pt-2 sm:pt-0", children: jsx(GradientButton, { title: subscription ? translations.subscriptionManage : translations.subscribePay, align: "center", icon: subscription ? jsx(Settings2Icon, {}) : jsx(BellIcon, {}), openInNewTab: false, className: "w-full", onClick: subscription ? handleManageAction : handleSubscribeAction }) })] }), jsx("div", { className: "absolute right-3 top-3 sm:right-6 sm:top-6", children: jsx(HoverInfo, { label: translations.totalLabel, description: translations.summaryDescription }) })] }), jsxs("section", { className: "relative flex flex-col gap-3 rounded-2xl border p-4 shadow-inner sm:gap-2 sm:p-5", children: [jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [jsx("h3", { className: "text-base text-gray-500 dark:text-slate-100 sm:text-lg", children: translations.bucketsTitle }), hasBuckets ? (jsx("button", { type: "button", "aria-expanded": bucketExpanded, "aria-label": bucketExpanded ? translations.hiddenDetail : translations.expandDetail, onClick: toggleBucketExpanded, className: "flex h-7 w-7 items-center justify-center rounded-full border border-transparent bg-white text-purple-600 shadow-[0_6px_20px_rgba(99,102,241,0.25)] transition-colors hover:text-purple-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-500 dark:bg-[#1b1541] dark:text-purple-100 dark:hover:text-purple-50 dark:shadow-[0_6px_22px_rgba(112,86,255,0.35)]", children: bucketExpanded ? (jsx(ChevronUpIcon, { className: "h-4 w-4" })) : (jsx(ChevronDownIcon, { className: "h-4 w-4" })) })) : null] }), hasBuckets ? (bucketExpanded ? (jsx("ul", { className: "flex flex-col gap-2", children: buckets.map((bucket) => {
236
+ return (jsxs("section", { className: cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsx(GemIcon, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsx("span", { className: "text-base sm:text-lg", children: translations.totalLabel })] }), jsx("div", { className: "flex justify-center text-3xl font-semibold leading-tight sm:text-4xl", children: formatNumber(locale, data.totalBalance) }), subscriptionBillingEnabled ? (jsxs(Fragment, { children: [jsxs("div", { className: "flex-1 flex-col gap-1", children: [jsx("p", { className: "text-xs text-gray-700 dark:text-slate-100 sm:text-sm", children: translations.subscriptionPeriodLabel }), jsx("h4", { className: "text-xl font-semibold sm:text-2xl", children: subscription ? subscription.planName : translations.subscriptionInactive })] }), jsx("div", { className: "pt-2 sm:pt-0", children: jsx(GradientButton, { title: subscription ? translations.subscriptionManage : translations.subscribePay, align: "center", icon: subscription ? jsx(Settings2Icon, {}) : jsx(BellIcon, {}), openInNewTab: false, className: "w-full", onClick: subscription ? handleManageAction : handleSubscribeAction }) })] })) : null] }), jsx("div", { className: "absolute right-3 top-3 sm:right-6 sm:top-6", children: jsx(HoverInfo, { label: translations.totalLabel, description: translations.summaryDescription }) })] }), jsxs("section", { className: "relative flex flex-col gap-3 rounded-2xl border p-4 shadow-inner sm:gap-2 sm:p-5", children: [jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [jsx("h3", { className: "text-base text-gray-500 dark:text-slate-100 sm:text-lg", children: translations.bucketsTitle }), hasBuckets ? (jsx("button", { type: "button", "aria-expanded": bucketExpanded, "aria-label": bucketExpanded ? translations.hiddenDetail : translations.expandDetail, onClick: toggleBucketExpanded, className: "flex h-7 w-7 items-center justify-center rounded-full border border-transparent bg-white text-purple-600 shadow-[0_6px_20px_rgba(99,102,241,0.25)] transition-colors hover:text-purple-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-500 dark:bg-[#1b1541] dark:text-purple-100 dark:hover:text-purple-50 dark:shadow-[0_6px_22px_rgba(112,86,255,0.35)]", children: bucketExpanded ? (jsx(ChevronUpIcon, { className: "h-4 w-4" })) : (jsx(ChevronDownIcon, { className: "h-4 w-4" })) })) : null] }), hasBuckets ? (bucketExpanded ? (jsx("ul", { className: "flex flex-col gap-2", children: buckets.map((bucket) => {
234
237
  const balanceDisplay = formatNumber(locale, bucket.balance);
235
238
  return (jsxs("li", { "data-credit-kind": bucket.kind, className: "rounded-2xl border border-slate-200/70 bg-white/85 px-3 py-3 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 sm:px-4", children: [jsxs("div", { className: "grid grid-cols-[1fr_auto] items-center gap-3 text-xs sm:text-sm", children: [jsx("span", { className: "flex min-w-0 items-center gap-2", children: jsx("span", { className: "max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs text-purple-600 shadow-sm dark:bg-purple-500/20 dark:text-purple-100 sm:text-sm", children: bucket.computedLabel }) }), jsx("span", { className: "flex min-w-0 justify-end", children: jsx("span", { className: "text-right text-base font-semibold leading-tight text-gray-500 dark:text-slate-100 sm:text-lg", title: balanceDisplay, children: balanceDisplay }) })] }), jsx("div", { className: "mt-3 flex justify-end gap-2", children: jsxs("span", { className: "text-[11px] text-gray-500 dark:text-slate-100 sm:text-xs", children: [translations.expiredAtLabel, ": ", bucket.expiresAt] }) })] }, bucket.kind));
236
- }) })) : (jsx("button", { type: "button", onClick: expandBuckets, className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 hover:text-purple-500", children: translations.expandDetail }))) : (jsx("div", { className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform dark:border-slate-800/60 dark:bg-slate-900/60 text-center", children: translations.bucketsEmpty })), jsx(GradientButton, { title: translations.onetimeBuy, icon: jsx(ShoppingCartIcon, {}), align: "center", className: "w-full text-sm sm:text-base", onClick: handleOnetimeAction })] })] }));
239
+ }) })) : (jsx("button", { type: "button", onClick: expandBuckets, className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 hover:text-purple-500", children: translations.expandDetail }))) : (jsx("div", { className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform dark:border-slate-800/60 dark:bg-slate-900/60 text-center", children: translations.bucketsEmpty })), onetimeBillingEnabled ? (jsx(GradientButton, { title: translations.onetimeBuy, icon: jsx(ShoppingCartIcon, {}), align: "center", className: "w-full text-sm sm:text-base", onClick: handleOnetimeAction })) : null] })] }));
237
240
  }
238
241
  function deriveStatus(expiresAt, thresholdDays = 7) {
239
242
  if (!expiresAt) {
@@ -9,6 +9,11 @@ export interface CreditOverviewPayload {
9
9
  export interface CreditOverviewNavClientProps {
10
10
  locale: string;
11
11
  endpoint: string;
12
+ /**
13
+ * Billing types enabled by the business app.
14
+ * Defaults are handled by the API/payload builder when omitted.
15
+ */
16
+ enabledBillingTypes?: string[];
12
17
  /**
13
18
  * Browser event names that should trigger credit overview reload.
14
19
  * Business apps can dispatch these events after credit balance changes.
@@ -24,4 +29,4 @@ export interface CreditOverviewNavClientProps {
24
29
  refreshDebounceMs?: number;
25
30
  }
26
31
  export declare function dispatchCreditOverviewRefresh(eventName?: string): void;
27
- export declare function CreditOverviewNavClient({ locale, endpoint, refreshEvents, refreshDebounceMs, }: CreditOverviewNavClientProps): import("react/jsx-runtime").JSX.Element | null;
32
+ export declare function CreditOverviewNavClient({ locale, endpoint, enabledBillingTypes, refreshEvents, refreshDebounceMs, }: CreditOverviewNavClientProps): import("react/jsx-runtime").JSX.Element | null;
@@ -9,9 +9,23 @@ var creditNavButton = require('./credit-nav-button.js');
9
9
  var creditOverviewClient = require('./credit-overview-client.js');
10
10
 
11
11
  const DEFAULT_CREDIT_OVERVIEW_REFRESH_EVENT = 'windrun-huaiin:credit-overview:refresh';
12
- function buildCreditOverviewUrl(endpoint, locale) {
12
+ function normalizeEnabledBillingTypes(enabledBillingTypes) {
13
+ if (!(enabledBillingTypes === null || enabledBillingTypes === void 0 ? void 0 : enabledBillingTypes.length)) {
14
+ return [];
15
+ }
16
+ return Array.from(new Set(enabledBillingTypes
17
+ .map((billingType) => billingType.trim())
18
+ .filter((billingType) => billingType.length > 0)));
19
+ }
20
+ function buildEnabledBillingTypesKey(enabledBillingTypes) {
21
+ return normalizeEnabledBillingTypes(enabledBillingTypes).join('\n');
22
+ }
23
+ function buildCreditOverviewUrl(endpoint, locale, enabledBillingTypes) {
13
24
  const url = new URL(endpoint, window.location.origin);
14
25
  url.searchParams.set('locale', locale);
26
+ for (const billingType of enabledBillingTypes) {
27
+ url.searchParams.append('enabledBillingTypes', billingType);
28
+ }
15
29
  return url.toString();
16
30
  }
17
31
  function normalizeRefreshEvents(refreshEvents) {
@@ -29,13 +43,15 @@ function dispatchCreditOverviewRefresh(eventName = DEFAULT_CREDIT_OVERVIEW_REFRE
29
43
  }
30
44
  window.dispatchEvent(new CustomEvent(eventName));
31
45
  }
32
- function CreditOverviewNavClient({ locale, endpoint, refreshEvents, refreshDebounceMs = 300, }) {
46
+ function CreditOverviewNavClient({ locale, endpoint, enabledBillingTypes, refreshEvents, refreshDebounceMs = 300, }) {
33
47
  const { isLoaded, isSignedIn, userId } = nextjs.useAuth();
34
48
  const [payload, setPayload] = React.useState(null);
35
49
  const abortControllerRef = React.useRef(null);
36
50
  const isMountedRef = React.useRef(false);
37
51
  const refreshEventsKey = buildRefreshEventsKey(refreshEvents);
38
52
  const normalizedRefreshEvents = React.useMemo(() => refreshEventsKey.split('\n').filter(Boolean), [refreshEventsKey]);
53
+ const enabledBillingTypesKey = buildEnabledBillingTypesKey(enabledBillingTypes);
54
+ const normalizedEnabledBillingTypes = React.useMemo(() => enabledBillingTypesKey.split('\n').filter(Boolean), [enabledBillingTypesKey]);
39
55
  React.useEffect(() => {
40
56
  isMountedRef.current = true;
41
57
  return () => {
@@ -50,7 +66,7 @@ function CreditOverviewNavClient({ locale, endpoint, refreshEvents, refreshDebou
50
66
  const controller = new AbortController();
51
67
  abortControllerRef.current = controller;
52
68
  try {
53
- const response = yield fetch(buildCreditOverviewUrl(endpoint, locale), {
69
+ const response = yield fetch(buildCreditOverviewUrl(endpoint, locale, normalizedEnabledBillingTypes), {
54
70
  cache: 'no-store',
55
71
  credentials: 'same-origin',
56
72
  signal: controller.signal,
@@ -77,7 +93,7 @@ function CreditOverviewNavClient({ locale, endpoint, refreshEvents, refreshDebou
77
93
  abortControllerRef.current = null;
78
94
  }
79
95
  }
80
- }), [endpoint, locale]);
96
+ }), [endpoint, locale, normalizedEnabledBillingTypes]);
81
97
  React.useEffect(() => {
82
98
  var _a;
83
99
  if (!isLoaded) {
@@ -7,9 +7,23 @@ import { CreditNavButton } from './credit-nav-button.mjs';
7
7
  import { CreditOverviewClient } from './credit-overview-client.mjs';
8
8
 
9
9
  const DEFAULT_CREDIT_OVERVIEW_REFRESH_EVENT = 'windrun-huaiin:credit-overview:refresh';
10
- function buildCreditOverviewUrl(endpoint, locale) {
10
+ function normalizeEnabledBillingTypes(enabledBillingTypes) {
11
+ if (!(enabledBillingTypes === null || enabledBillingTypes === void 0 ? void 0 : enabledBillingTypes.length)) {
12
+ return [];
13
+ }
14
+ return Array.from(new Set(enabledBillingTypes
15
+ .map((billingType) => billingType.trim())
16
+ .filter((billingType) => billingType.length > 0)));
17
+ }
18
+ function buildEnabledBillingTypesKey(enabledBillingTypes) {
19
+ return normalizeEnabledBillingTypes(enabledBillingTypes).join('\n');
20
+ }
21
+ function buildCreditOverviewUrl(endpoint, locale, enabledBillingTypes) {
11
22
  const url = new URL(endpoint, window.location.origin);
12
23
  url.searchParams.set('locale', locale);
24
+ for (const billingType of enabledBillingTypes) {
25
+ url.searchParams.append('enabledBillingTypes', billingType);
26
+ }
13
27
  return url.toString();
14
28
  }
15
29
  function normalizeRefreshEvents(refreshEvents) {
@@ -27,13 +41,15 @@ function dispatchCreditOverviewRefresh(eventName = DEFAULT_CREDIT_OVERVIEW_REFRE
27
41
  }
28
42
  window.dispatchEvent(new CustomEvent(eventName));
29
43
  }
30
- function CreditOverviewNavClient({ locale, endpoint, refreshEvents, refreshDebounceMs = 300, }) {
44
+ function CreditOverviewNavClient({ locale, endpoint, enabledBillingTypes, refreshEvents, refreshDebounceMs = 300, }) {
31
45
  const { isLoaded, isSignedIn, userId } = useAuth();
32
46
  const [payload, setPayload] = useState(null);
33
47
  const abortControllerRef = useRef(null);
34
48
  const isMountedRef = useRef(false);
35
49
  const refreshEventsKey = buildRefreshEventsKey(refreshEvents);
36
50
  const normalizedRefreshEvents = useMemo(() => refreshEventsKey.split('\n').filter(Boolean), [refreshEventsKey]);
51
+ const enabledBillingTypesKey = buildEnabledBillingTypesKey(enabledBillingTypes);
52
+ const normalizedEnabledBillingTypes = useMemo(() => enabledBillingTypesKey.split('\n').filter(Boolean), [enabledBillingTypesKey]);
37
53
  useEffect(() => {
38
54
  isMountedRef.current = true;
39
55
  return () => {
@@ -48,7 +64,7 @@ function CreditOverviewNavClient({ locale, endpoint, refreshEvents, refreshDebou
48
64
  const controller = new AbortController();
49
65
  abortControllerRef.current = controller;
50
66
  try {
51
- const response = yield fetch(buildCreditOverviewUrl(endpoint, locale), {
67
+ const response = yield fetch(buildCreditOverviewUrl(endpoint, locale, normalizedEnabledBillingTypes), {
52
68
  cache: 'no-store',
53
69
  credentials: 'same-origin',
54
70
  signal: controller.signal,
@@ -75,7 +91,7 @@ function CreditOverviewNavClient({ locale, endpoint, refreshEvents, refreshDebou
75
91
  abortControllerRef.current = null;
76
92
  }
77
93
  }
78
- }), [endpoint, locale]);
94
+ }), [endpoint, locale, normalizedEnabledBillingTypes]);
79
95
  useEffect(() => {
80
96
  var _a;
81
97
  if (!isLoaded) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "31.3.6",
3
+ "version": "31.3.7",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "exports": {
6
6
  "./clerk": {
@@ -243,9 +243,9 @@
243
243
  "tslib": "^2.8.1",
244
244
  "unified": "^11.0.5",
245
245
  "zod": "^4.3.6",
246
- "@windrun-huaiin/base-ui": "^31.0.1",
247
246
  "@windrun-huaiin/contracts": "^31.0.0",
248
- "@windrun-huaiin/lib": "^31.0.3"
247
+ "@windrun-huaiin/lib": "^31.0.3",
248
+ "@windrun-huaiin/base-ui": "^31.0.1"
249
249
  },
250
250
  "peerDependencies": {
251
251
  "clsx": "^2.1.1",
@@ -128,6 +128,11 @@ export function CreditOverviewClient({
128
128
  const subscription = data.subscription;
129
129
  const pricingContext = data.pricingContext;
130
130
  const ctaBehaviors = data.ctaBehaviors;
131
+ const billingOptions = pricingContext?.moneyPriceData.billingSwitch.options ?? [];
132
+ const subscriptionBillingEnabled = billingOptions.some(
133
+ (option) => option.key === 'monthly' || option.key === 'yearly',
134
+ );
135
+ const onetimeBillingEnabled = billingOptions.some((option) => option.key === 'onetime');
131
136
  const getModalMoneyPriceData = useCallback(
132
137
  (mode: PricingModalMode) => {
133
138
  if (!pricingContext) {
@@ -383,24 +388,28 @@ export function CreditOverviewClient({
383
388
  <div className="flex justify-center text-3xl font-semibold leading-tight sm:text-4xl">
384
389
  {formatNumber(locale, data.totalBalance)}
385
390
  </div>
386
- <div className="flex-1 flex-col gap-1">
387
- <p className="text-xs text-gray-700 dark:text-slate-100 sm:text-sm">
388
- {translations.subscriptionPeriodLabel}
389
- </p>
390
- <h4 className="text-xl font-semibold sm:text-2xl">
391
- {subscription ? subscription.planName : translations.subscriptionInactive}
392
- </h4>
393
- </div>
394
- <div className="pt-2 sm:pt-0">
395
- <GradientButton
396
- title={subscription ? translations.subscriptionManage : translations.subscribePay}
397
- align="center"
398
- icon={subscription ? <Settings2Icon /> : <BellIcon />}
399
- openInNewTab={false}
400
- className="w-full"
401
- onClick={subscription ? handleManageAction : handleSubscribeAction}
402
- />
403
- </div>
391
+ {subscriptionBillingEnabled ? (
392
+ <>
393
+ <div className="flex-1 flex-col gap-1">
394
+ <p className="text-xs text-gray-700 dark:text-slate-100 sm:text-sm">
395
+ {translations.subscriptionPeriodLabel}
396
+ </p>
397
+ <h4 className="text-xl font-semibold sm:text-2xl">
398
+ {subscription ? subscription.planName : translations.subscriptionInactive}
399
+ </h4>
400
+ </div>
401
+ <div className="pt-2 sm:pt-0">
402
+ <GradientButton
403
+ title={subscription ? translations.subscriptionManage : translations.subscribePay}
404
+ align="center"
405
+ icon={subscription ? <Settings2Icon /> : <BellIcon />}
406
+ openInNewTab={false}
407
+ className="w-full"
408
+ onClick={subscription ? handleManageAction : handleSubscribeAction}
409
+ />
410
+ </div>
411
+ </>
412
+ ) : null}
404
413
  </div>
405
414
  <div className="absolute right-3 top-3 sm:right-6 sm:top-6">
406
415
  <HoverInfo
@@ -482,13 +491,15 @@ export function CreditOverviewClient({
482
491
  {translations.bucketsEmpty}
483
492
  </div>
484
493
  )}
485
- <GradientButton
486
- title={translations.onetimeBuy}
487
- icon={<ShoppingCartIcon />}
488
- align="center"
489
- className="w-full text-sm sm:text-base"
490
- onClick={handleOnetimeAction}
491
- />
494
+ {onetimeBillingEnabled ? (
495
+ <GradientButton
496
+ title={translations.onetimeBuy}
497
+ icon={<ShoppingCartIcon />}
498
+ align="center"
499
+ className="w-full text-sm sm:text-base"
500
+ onClick={handleOnetimeAction}
501
+ />
502
+ ) : null}
492
503
  </section>
493
504
  </section>
494
505
  );
@@ -17,6 +17,11 @@ export interface CreditOverviewPayload {
17
17
  export interface CreditOverviewNavClientProps {
18
18
  locale: string;
19
19
  endpoint: string;
20
+ /**
21
+ * Billing types enabled by the business app.
22
+ * Defaults are handled by the API/payload builder when omitted.
23
+ */
24
+ enabledBillingTypes?: string[];
20
25
  /**
21
26
  * Browser event names that should trigger credit overview reload.
22
27
  * Business apps can dispatch these events after credit balance changes.
@@ -32,9 +37,34 @@ export interface CreditOverviewNavClientProps {
32
37
  refreshDebounceMs?: number;
33
38
  }
34
39
 
35
- function buildCreditOverviewUrl(endpoint: string, locale: string) {
40
+ function normalizeEnabledBillingTypes(enabledBillingTypes: string[] | undefined) {
41
+ if (!enabledBillingTypes?.length) {
42
+ return [];
43
+ }
44
+
45
+ return Array.from(
46
+ new Set(
47
+ enabledBillingTypes
48
+ .map((billingType) => billingType.trim())
49
+ .filter((billingType) => billingType.length > 0),
50
+ ),
51
+ );
52
+ }
53
+
54
+ function buildEnabledBillingTypesKey(enabledBillingTypes: string[] | undefined) {
55
+ return normalizeEnabledBillingTypes(enabledBillingTypes).join('\n');
56
+ }
57
+
58
+ function buildCreditOverviewUrl(
59
+ endpoint: string,
60
+ locale: string,
61
+ enabledBillingTypes: string[],
62
+ ) {
36
63
  const url = new URL(endpoint, window.location.origin);
37
64
  url.searchParams.set('locale', locale);
65
+ for (const billingType of enabledBillingTypes) {
66
+ url.searchParams.append('enabledBillingTypes', billingType);
67
+ }
38
68
  return url.toString();
39
69
  }
40
70
 
@@ -66,6 +96,7 @@ export function dispatchCreditOverviewRefresh(
66
96
  export function CreditOverviewNavClient({
67
97
  locale,
68
98
  endpoint,
99
+ enabledBillingTypes,
69
100
  refreshEvents,
70
101
  refreshDebounceMs = 300,
71
102
  }: CreditOverviewNavClientProps) {
@@ -78,6 +109,11 @@ export function CreditOverviewNavClient({
78
109
  () => refreshEventsKey.split('\n').filter(Boolean),
79
110
  [refreshEventsKey],
80
111
  );
112
+ const enabledBillingTypesKey = buildEnabledBillingTypesKey(enabledBillingTypes);
113
+ const normalizedEnabledBillingTypes = useMemo(
114
+ () => enabledBillingTypesKey.split('\n').filter(Boolean),
115
+ [enabledBillingTypesKey],
116
+ );
81
117
 
82
118
  useEffect(() => {
83
119
  isMountedRef.current = true;
@@ -95,7 +131,11 @@ export function CreditOverviewNavClient({
95
131
  abortControllerRef.current = controller;
96
132
 
97
133
  try {
98
- const response = await fetch(buildCreditOverviewUrl(endpoint, locale), {
134
+ const response = await fetch(buildCreditOverviewUrl(
135
+ endpoint,
136
+ locale,
137
+ normalizedEnabledBillingTypes,
138
+ ), {
99
139
  cache: 'no-store',
100
140
  credentials: 'same-origin',
101
141
  signal: controller.signal,
@@ -122,7 +162,7 @@ export function CreditOverviewNavClient({
122
162
  abortControllerRef.current = null;
123
163
  }
124
164
  }
125
- }, [endpoint, locale]);
165
+ }, [endpoint, locale, normalizedEnabledBillingTypes]);
126
166
 
127
167
  useEffect(() => {
128
168
  if (!isLoaded) {