@windrun-huaiin/third-ui 31.3.7 → 31.4.0
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/main/credit/credit-nav-button.d.ts +3 -2
- package/dist/main/credit/credit-nav-button.js +7 -9
- package/dist/main/credit/credit-nav-button.mjs +5 -7
- package/dist/main/credit/credit-overview-nav-client.d.ts +7 -2
- package/dist/main/credit/credit-overview-nav-client.js +2 -2
- package/dist/main/credit/credit-overview-nav-client.mjs +2 -2
- package/dist/main/credit/index.d.ts +1 -1
- package/dist/main/credit/types.d.ts +1 -0
- package/dist/main/money-price/index.d.ts +2 -0
- package/dist/main/money-price/index.js +4 -0
- package/dist/main/money-price/index.mjs +1 -0
- package/dist/main/money-price/money-price-interactive.d.ts +1 -1
- package/dist/main/money-price/money-price-interactive.js +7 -5
- package/dist/main/money-price/money-price-interactive.mjs +7 -5
- package/dist/main/money-price/money-price-types.d.ts +2 -0
- package/dist/main/money-price/money-price.d.ts +1 -1
- package/dist/main/money-price/money-price.js +2 -2
- package/dist/main/money-price/money-price.mjs +2 -2
- package/dist/main/money-price/pricing-modal.d.ts +33 -0
- package/dist/main/money-price/pricing-modal.js +109 -0
- package/dist/main/money-price/pricing-modal.mjs +105 -0
- package/package.json +3 -3
- package/src/main/credit/credit-nav-button.tsx +15 -56
- package/src/main/credit/credit-overview-nav-client.tsx +8 -1
- package/src/main/credit/index.ts +1 -0
- package/src/main/credit/types.ts +1 -0
- package/src/main/money-price/index.ts +10 -0
- package/src/main/money-price/money-price-interactive.tsx +41 -31
- package/src/main/money-price/money-price-types.ts +2 -0
- package/src/main/money-price/money-price.tsx +2 -0
- package/src/main/money-price/pricing-modal.tsx +283 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { __rest, __awaiter } from 'tslib';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
+
import { XIcon } from '@windrun-huaiin/base-ui/icons';
|
|
5
|
+
import { themeMainBgColor } from '@windrun-huaiin/base-ui/lib';
|
|
6
|
+
import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle } from '@windrun-huaiin/base-ui/ui';
|
|
7
|
+
import { cn } from '@windrun-huaiin/lib/utils';
|
|
8
|
+
import { createContext, useMemo, useState, useRef, useEffect, useCallback, useContext } from 'react';
|
|
9
|
+
import { dialogThemedOverlayClass } from '../alert-dialog/dialog-styles.mjs';
|
|
10
|
+
import { MoneyPriceInteractive } from './money-price-interactive.mjs';
|
|
11
|
+
|
|
12
|
+
const emptyInitUserContext = {
|
|
13
|
+
fingerprintId: null,
|
|
14
|
+
xUser: null,
|
|
15
|
+
xCredit: null,
|
|
16
|
+
xSubscription: null,
|
|
17
|
+
isClerkAuthenticated: false,
|
|
18
|
+
};
|
|
19
|
+
const PricingModalContext = createContext(null);
|
|
20
|
+
function normalizeEnabledBillingTypes(data, enabledBillingTypes) {
|
|
21
|
+
const availableKeys = data.billingSwitch.options.map((option) => option.key);
|
|
22
|
+
const configuredKeys = (enabledBillingTypes === null || enabledBillingTypes === void 0 ? void 0 : enabledBillingTypes.length) ? enabledBillingTypes : availableKeys;
|
|
23
|
+
return Array.from(new Set(configuredKeys
|
|
24
|
+
.map((billingType) => billingType.trim())
|
|
25
|
+
.filter((billingType) => availableKeys.includes(billingType))));
|
|
26
|
+
}
|
|
27
|
+
function resolveBillingType({ data, enabledBillingTypes, requestedBillingType, }) {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const enabledKeys = normalizeEnabledBillingTypes(data, enabledBillingTypes);
|
|
30
|
+
if (requestedBillingType && enabledKeys.includes(requestedBillingType)) {
|
|
31
|
+
return requestedBillingType;
|
|
32
|
+
}
|
|
33
|
+
if (enabledKeys.includes(data.billingSwitch.defaultKey)) {
|
|
34
|
+
return data.billingSwitch.defaultKey;
|
|
35
|
+
}
|
|
36
|
+
return (_a = enabledKeys[0]) !== null && _a !== void 0 ? _a : (_b = data.billingSwitch.options[0]) === null || _b === void 0 ? void 0 : _b.key;
|
|
37
|
+
}
|
|
38
|
+
function PricingModal({ open, onOpenChange, data, config, billingType, checkoutApiEndpoint, customerPortalApiEndpoint, enableClerkModal = false, enabledBillingTypes, mobileBillingSwitchBehavior, enableSubscriptionUpgrade = true, initUserContext, isInitLoading = false, }) {
|
|
39
|
+
const resolvedBillingType = useMemo(() => resolveBillingType({
|
|
40
|
+
data,
|
|
41
|
+
enabledBillingTypes,
|
|
42
|
+
requestedBillingType: billingType,
|
|
43
|
+
}), [billingType, data, enabledBillingTypes]);
|
|
44
|
+
return (jsx(AlertDialog, { open: open, onOpenChange: onOpenChange, children: open ? (jsxs(AlertDialogContent, { className: cn('mt-5 sm:mt-6 md:mt-10 lg:mt-15 w-[95vw] max-w-[1200px] overflow-hidden border border-slate-200 p-0 shadow-[0_32px_90px_rgba(15,23,42,0.25)] ring-1 ring-black/5 dark:border-white/12 dark:shadow-[0_40px_120px_rgba(0,0,0,0.6)] dark:ring-white/10', themeMainBgColor), overlayClassName: dialogThemedOverlayClass, children: [jsxs(AlertDialogHeader, { className: "flex flex-row items-center justify-between border-b border-slate-200 px-6 pt-4 pb-1 dark:border-slate-800", children: [jsx(AlertDialogTitle, { asChild: true, children: jsxs("div", { className: "flex flex-wrap items-baseline gap-3 text-slate-900 dark:text-white", children: [jsx("span", { className: "text-2xl font-semibold leading-tight", children: data.title }), data.subtitle ? (jsx("span", { className: "text-sm font-medium text-slate-500 dark:text-slate-300", children: data.subtitle })) : null] }) }), jsx("button", { type: "button", className: "rounded-full p-2 text-gray-400 transition hover:bg-gray-400 hover:text-gray-400 dark:text-white/80 dark:hover:bg-white/80 dark:hover:text-white/80", onClick: () => onOpenChange(false), children: jsx(XIcon, { className: "h-6 w-6" }) })] }), jsx("div", { className: "max-h-[60vh] overflow-y-auto px-4 pt-2 pb-6 sm:max-h-[80vh]", children: jsx("div", { className: "mx-auto w-full", children: jsx(MoneyPriceInteractive, { data: data, config: config, checkoutApiEndpoint: checkoutApiEndpoint, customerPortalApiEndpoint: customerPortalApiEndpoint, enableClerkModal: enableClerkModal, enabledBillingTypes: enabledBillingTypes, mobileBillingSwitchBehavior: mobileBillingSwitchBehavior, enableSubscriptionUpgrade: enableSubscriptionUpgrade, initialBillingType: resolvedBillingType, disableAutoDetectBilling: resolvedBillingType === 'onetime', initUserContext: initUserContext, isInitLoading: isInitLoading }, resolvedBillingType !== null && resolvedBillingType !== void 0 ? resolvedBillingType : 'default') }) })] })) : null }));
|
|
45
|
+
}
|
|
46
|
+
function PricingModalProvider(_a) {
|
|
47
|
+
var { children, pricingContextEndpoint, initUserContext: initUserContextProp, isInitLoading: isInitLoadingProp = false } = _a, modalProps = __rest(_a, ["children", "pricingContextEndpoint", "initUserContext", "isInitLoading"]);
|
|
48
|
+
const [open, setOpen] = useState(false);
|
|
49
|
+
const [requestedBillingType, setRequestedBillingType] = useState();
|
|
50
|
+
const [loadedInitUserContext, setLoadedInitUserContext] = useState(initUserContextProp !== null && initUserContextProp !== void 0 ? initUserContextProp : emptyInitUserContext);
|
|
51
|
+
const [isContextLoading, setIsContextLoading] = useState(false);
|
|
52
|
+
const loadedContextRef = useRef(!!initUserContextProp);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (initUserContextProp) {
|
|
55
|
+
loadedContextRef.current = true;
|
|
56
|
+
setLoadedInitUserContext(initUserContextProp);
|
|
57
|
+
}
|
|
58
|
+
}, [initUserContextProp]);
|
|
59
|
+
const loadPricingContext = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
if (!pricingContextEndpoint || loadedContextRef.current) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
setIsContextLoading(true);
|
|
64
|
+
try {
|
|
65
|
+
const response = yield fetch(pricingContextEndpoint, {
|
|
66
|
+
credentials: 'same-origin',
|
|
67
|
+
});
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const nextContext = (yield response.json());
|
|
72
|
+
loadedContextRef.current = true;
|
|
73
|
+
setLoadedInitUserContext(nextContext);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.warn('[PricingModalProvider] Failed to load pricing context', error);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
setIsContextLoading(false);
|
|
80
|
+
}
|
|
81
|
+
}), [pricingContextEndpoint]);
|
|
82
|
+
const openPricingModal = useCallback((options) => {
|
|
83
|
+
setRequestedBillingType(options === null || options === void 0 ? void 0 : options.billingType);
|
|
84
|
+
setOpen(true);
|
|
85
|
+
void loadPricingContext();
|
|
86
|
+
}, [loadPricingContext]);
|
|
87
|
+
const closePricingModal = useCallback(() => {
|
|
88
|
+
setOpen(false);
|
|
89
|
+
}, []);
|
|
90
|
+
const contextValue = useMemo(() => ({
|
|
91
|
+
openPricingModal,
|
|
92
|
+
closePricingModal,
|
|
93
|
+
isPricingModalOpen: open,
|
|
94
|
+
}), [closePricingModal, open, openPricingModal]);
|
|
95
|
+
return (jsxs(PricingModalContext.Provider, { value: contextValue, children: [children, jsx(PricingModal, Object.assign({}, modalProps, { open: open, onOpenChange: setOpen, billingType: requestedBillingType, initUserContext: initUserContextProp !== null && initUserContextProp !== void 0 ? initUserContextProp : loadedInitUserContext, isInitLoading: isInitLoadingProp || isContextLoading }))] }));
|
|
96
|
+
}
|
|
97
|
+
function usePricingModal() {
|
|
98
|
+
const context = useContext(PricingModalContext);
|
|
99
|
+
if (!context) {
|
|
100
|
+
throw new Error('usePricingModal must be used within PricingModalProvider.');
|
|
101
|
+
}
|
|
102
|
+
return context;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { PricingModal, PricingModalProvider, usePricingModal };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.4.0",
|
|
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/
|
|
246
|
+
"@windrun-huaiin/base-ui": "^31.0.1",
|
|
247
247
|
"@windrun-huaiin/lib": "^31.0.3",
|
|
248
|
-
"@windrun-huaiin/
|
|
248
|
+
"@windrun-huaiin/contracts": "^31.0.0"
|
|
249
249
|
},
|
|
250
250
|
"peerDependencies": {
|
|
251
251
|
"clsx": "^2.1.1",
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
4
|
-
import { GemIcon
|
|
5
|
-
import { themeMainBgColor } from '@windrun-huaiin/base-ui/lib';
|
|
4
|
+
import { GemIcon } from '@windrun-huaiin/base-ui/icons';
|
|
6
5
|
import {
|
|
7
|
-
AlertDialog,
|
|
8
|
-
AlertDialogContent,
|
|
9
|
-
AlertDialogHeader,
|
|
10
|
-
AlertDialogTitle,
|
|
11
6
|
DropdownMenu,
|
|
12
7
|
DropdownMenuContent,
|
|
13
8
|
DropdownMenuTrigger,
|
|
@@ -21,16 +16,16 @@ import {
|
|
|
21
16
|
useRef,
|
|
22
17
|
useState,
|
|
23
18
|
} from 'react';
|
|
24
|
-
import { MoneyPriceInteractive } from '../money-price/money-price-interactive';
|
|
25
19
|
import { getActiveProviderConfigUtil } from '../money-price/money-price-config-util';
|
|
26
20
|
import type { MoneyPriceData, SubscriptionProductConfig } from '../money-price/money-price-types';
|
|
27
|
-
import {
|
|
28
|
-
import type { CreditPricingContext, PricingModalMode } from './types';
|
|
21
|
+
import { PricingModal } from '../money-price/pricing-modal';
|
|
22
|
+
import type { CreditPricingContext, MobileBillingSwitchBehavior, PricingModalMode } from './types';
|
|
29
23
|
|
|
30
24
|
interface CreditNavButtonProps {
|
|
31
25
|
locale: string;
|
|
32
26
|
totalBalance: number;
|
|
33
27
|
totalLabel: string;
|
|
28
|
+
mobileBillingSwitchBehavior?: MobileBillingSwitchBehavior;
|
|
34
29
|
children: React.ReactNode;
|
|
35
30
|
}
|
|
36
31
|
|
|
@@ -38,6 +33,7 @@ export function CreditNavButton({
|
|
|
38
33
|
locale,
|
|
39
34
|
totalBalance,
|
|
40
35
|
totalLabel,
|
|
36
|
+
mobileBillingSwitchBehavior,
|
|
41
37
|
children,
|
|
42
38
|
}: CreditNavButtonProps) {
|
|
43
39
|
const [open, setOpen] = useState(false);
|
|
@@ -243,7 +239,7 @@ export function CreditNavButton({
|
|
|
243
239
|
</DropdownMenuContent>
|
|
244
240
|
</DropdownMenu>
|
|
245
241
|
{pricingModal.modalMoneyPriceData && pricingModal.pricingContext ? (
|
|
246
|
-
<
|
|
242
|
+
<PricingModal
|
|
247
243
|
open={pricingModal.open}
|
|
248
244
|
onOpenChange={(open) =>
|
|
249
245
|
setPricingModal((prev) => ({
|
|
@@ -251,52 +247,15 @@ export function CreditNavButton({
|
|
|
251
247
|
open,
|
|
252
248
|
}))
|
|
253
249
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
<AlertDialogTitle asChild>
|
|
264
|
-
<div className="flex flex-wrap items-baseline gap-3 text-slate-900 dark:text-white">
|
|
265
|
-
<span className="text-2xl font-semibold leading-tight">
|
|
266
|
-
{pricingModal.modalMoneyPriceData.title}
|
|
267
|
-
</span>
|
|
268
|
-
{pricingModal.modalMoneyPriceData.subtitle ? (
|
|
269
|
-
<span className="text-sm font-medium text-slate-500 dark:text-slate-300">
|
|
270
|
-
{pricingModal.modalMoneyPriceData.subtitle}
|
|
271
|
-
</span>
|
|
272
|
-
) : null}
|
|
273
|
-
</div>
|
|
274
|
-
</AlertDialogTitle>
|
|
275
|
-
<button
|
|
276
|
-
type="button"
|
|
277
|
-
className="rounded-full p-2 text-gray-400 transition hover:bg-gray-400 hover:text-gray-400 dark:text-white/80 dark:hover:bg-white/80 dark:hover:text-white/80"
|
|
278
|
-
onClick={closePricingModal}
|
|
279
|
-
>
|
|
280
|
-
<XIcon className="h-6 w-6" />
|
|
281
|
-
</button>
|
|
282
|
-
</AlertDialogHeader>
|
|
283
|
-
<div className="max-h-[60vh] sm:max-h-[80vh] overflow-y-auto px-4 pt-2 pb-6">
|
|
284
|
-
<div className="mx-auto w-full">
|
|
285
|
-
<MoneyPriceInteractive
|
|
286
|
-
key={pricingModal.mode}
|
|
287
|
-
data={pricingModal.modalMoneyPriceData}
|
|
288
|
-
config={pricingModal.pricingContext.moneyPriceConfig}
|
|
289
|
-
checkoutApiEndpoint={pricingModal.pricingContext.checkoutApiEndpoint}
|
|
290
|
-
customerPortalApiEndpoint={pricingModal.pricingContext.customerPortalApiEndpoint}
|
|
291
|
-
enableSubscriptionUpgrade={pricingModal.pricingContext.enableSubscriptionUpgrade}
|
|
292
|
-
initialBillingType={modalInitialBillingType}
|
|
293
|
-
disableAutoDetectBilling={isOnetimeModal}
|
|
294
|
-
initUserContext={pricingModal.pricingContext.initUserContext}
|
|
295
|
-
/>
|
|
296
|
-
</div>
|
|
297
|
-
</div>
|
|
298
|
-
</AlertDialogContent>
|
|
299
|
-
</AlertDialog>
|
|
250
|
+
data={pricingModal.modalMoneyPriceData}
|
|
251
|
+
config={pricingModal.pricingContext.moneyPriceConfig}
|
|
252
|
+
checkoutApiEndpoint={pricingModal.pricingContext.checkoutApiEndpoint}
|
|
253
|
+
customerPortalApiEndpoint={pricingModal.pricingContext.customerPortalApiEndpoint}
|
|
254
|
+
mobileBillingSwitchBehavior={mobileBillingSwitchBehavior}
|
|
255
|
+
enableSubscriptionUpgrade={pricingModal.pricingContext.enableSubscriptionUpgrade}
|
|
256
|
+
billingType={modalInitialBillingType}
|
|
257
|
+
initUserContext={pricingModal.pricingContext.initUserContext}
|
|
258
|
+
/>
|
|
300
259
|
) : null}
|
|
301
260
|
</CreditNavPopoverContext.Provider>
|
|
302
261
|
);
|
|
@@ -4,7 +4,7 @@ import { useAuth } from '@clerk/nextjs';
|
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
5
5
|
import { CreditNavButton } from './credit-nav-button';
|
|
6
6
|
import { CreditOverviewClient, type CreditOverviewTranslations } from './credit-overview-client';
|
|
7
|
-
import type { CreditOverviewData } from './types';
|
|
7
|
+
import type { CreditOverviewData, MobileBillingSwitchBehavior } from './types';
|
|
8
8
|
|
|
9
9
|
export const DEFAULT_CREDIT_OVERVIEW_REFRESH_EVENT = 'windrun-huaiin:credit-overview:refresh';
|
|
10
10
|
|
|
@@ -22,6 +22,11 @@ export interface CreditOverviewNavClientProps {
|
|
|
22
22
|
* Defaults are handled by the API/payload builder when omitted.
|
|
23
23
|
*/
|
|
24
24
|
enabledBillingTypes?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Mobile behavior for the pricing modal billing switch.
|
|
27
|
+
* Default: 'sticky'.
|
|
28
|
+
*/
|
|
29
|
+
mobileBillingSwitchBehavior?: MobileBillingSwitchBehavior;
|
|
25
30
|
/**
|
|
26
31
|
* Browser event names that should trigger credit overview reload.
|
|
27
32
|
* Business apps can dispatch these events after credit balance changes.
|
|
@@ -97,6 +102,7 @@ export function CreditOverviewNavClient({
|
|
|
97
102
|
locale,
|
|
98
103
|
endpoint,
|
|
99
104
|
enabledBillingTypes,
|
|
105
|
+
mobileBillingSwitchBehavior,
|
|
100
106
|
refreshEvents,
|
|
101
107
|
refreshDebounceMs = 300,
|
|
102
108
|
}: CreditOverviewNavClientProps) {
|
|
@@ -220,6 +226,7 @@ export function CreditOverviewNavClient({
|
|
|
220
226
|
locale={locale}
|
|
221
227
|
totalBalance={payload.data.totalBalance}
|
|
222
228
|
totalLabel={payload.totalLabel}
|
|
229
|
+
mobileBillingSwitchBehavior={mobileBillingSwitchBehavior}
|
|
223
230
|
>
|
|
224
231
|
<CreditOverviewClient
|
|
225
232
|
locale={locale}
|
package/src/main/credit/index.ts
CHANGED
package/src/main/credit/types.ts
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
export { MoneyPriceInteractive } from './money-price-interactive';
|
|
4
4
|
export { MoneyPriceButton } from './money-price-button';
|
|
5
|
+
export {
|
|
6
|
+
PricingModal,
|
|
7
|
+
PricingModalProvider,
|
|
8
|
+
usePricingModal,
|
|
9
|
+
} from './pricing-modal';
|
|
5
10
|
export type {
|
|
6
11
|
MoneyPriceConfig,
|
|
7
12
|
MoneyPriceData,
|
|
@@ -17,4 +22,9 @@ export type {
|
|
|
17
22
|
CreditPackProductConfig,
|
|
18
23
|
UserContext,
|
|
19
24
|
} from './money-price-types';
|
|
25
|
+
export type {
|
|
26
|
+
OpenPricingModalOptions,
|
|
27
|
+
PricingModalProps,
|
|
28
|
+
PricingModalProviderProps,
|
|
29
|
+
} from './pricing-modal';
|
|
20
30
|
export { UserState } from './money-price-types';
|
|
@@ -44,6 +44,7 @@ export function MoneyPriceInteractive({
|
|
|
44
44
|
customerPortalApiEndpoint,
|
|
45
45
|
enableClerkModal = false,
|
|
46
46
|
enabledBillingTypes,
|
|
47
|
+
mobileBillingSwitchBehavior = 'static',
|
|
47
48
|
enableSubscriptionUpgrade = true,
|
|
48
49
|
initialBillingType,
|
|
49
50
|
disableAutoDetectBilling = false,
|
|
@@ -71,6 +72,7 @@ export function MoneyPriceInteractive({
|
|
|
71
72
|
return acc;
|
|
72
73
|
}, {});
|
|
73
74
|
}, [billingOptions]);
|
|
75
|
+
const showBillingSwitch = billingOptions.length > 1;
|
|
74
76
|
const defaultBilling = useMemo<BillingType>(() => {
|
|
75
77
|
const defaultKey = data.billingSwitch.defaultKey;
|
|
76
78
|
|
|
@@ -395,41 +397,49 @@ export function MoneyPriceInteractive({
|
|
|
395
397
|
return selectedBillingOption.discountText.replace('{percent}', String(discountPercent));
|
|
396
398
|
}, [selectedBillingOption, providerConfig, billingType]);
|
|
397
399
|
|
|
398
|
-
// Configure the mobile
|
|
400
|
+
// Configure the mobile behavior for BillingTypeButton.
|
|
399
401
|
return (
|
|
400
402
|
<>
|
|
401
|
-
|
|
402
|
-
<div
|
|
403
|
-
{
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
403
|
+
{showBillingSwitch ? (
|
|
404
|
+
<div
|
|
405
|
+
className={cn(
|
|
406
|
+
'mb-6 flex justify-center',
|
|
407
|
+
mobileBillingSwitchBehavior === 'sticky' &&
|
|
408
|
+
'max-md:sticky max-md:top-2 max-md:z-30 max-md:py-2 max-md:bg-transparent',
|
|
409
|
+
)}
|
|
410
|
+
>
|
|
411
|
+
<div className="inline-flex max-w-[calc(100vw-2rem)] bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded-full px-2 py-2 sm:px-3 sm:py-3 shadow-sm" data-billing-switch>
|
|
412
|
+
{billingOptions.map(option => {
|
|
413
|
+
const isActive = option.key === billingType;
|
|
414
|
+
const buttonClasses = isActive
|
|
415
|
+
? cn('text-white rounded-full shadow-sm', themeButtonGradientClass, themeButtonGradientHoverClass )
|
|
416
|
+
: 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
|
|
417
|
+
const showBadge = option.key === billingType && !!discountBadgeText;
|
|
418
|
+
|
|
419
|
+
return (
|
|
420
|
+
<div key={option.key} className="relative flex items-center justify-center mx-1">
|
|
421
|
+
{showBadge && (
|
|
422
|
+
<span className="absolute z-10 left-1/2 -translate-x-1/2 -top-3 sm:-top-4 translate-y-[-50%] px-3 py-0.5 text-[0.625rem] sm:text-xs rounded-md bg-yellow-100 text-yellow-800 font-semibold shadow-sm whitespace-nowrap">
|
|
423
|
+
{discountBadgeText}
|
|
424
|
+
</span>
|
|
421
425
|
)}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
426
|
+
<button
|
|
427
|
+
className={cn(
|
|
428
|
+
'text-sm md:text-base font-medium transition relative text-center z-10 px-2 sm:px-4 py-2 min-w-[88px] min-[360px]:min-w-[100px] sm:min-w-[120px]',
|
|
429
|
+
buttonClasses
|
|
430
|
+
)}
|
|
431
|
+
type="button"
|
|
432
|
+
data-billing-button={option.key}
|
|
433
|
+
onClick={() => setUserSelectedBillingType(option.key)}
|
|
434
|
+
>
|
|
435
|
+
{option.name}
|
|
436
|
+
</button>
|
|
437
|
+
</div>
|
|
438
|
+
);
|
|
439
|
+
})}
|
|
440
|
+
</div>
|
|
431
441
|
</div>
|
|
432
|
-
|
|
442
|
+
) : null}
|
|
433
443
|
|
|
434
444
|
<div className="w-full">
|
|
435
445
|
<div className="flex flex-wrap justify-center gap-5 md:gap-6 xl:gap-8 w-full max-w-6xl mx-auto">
|
|
@@ -102,6 +102,7 @@ export interface MoneyPriceProps {
|
|
|
102
102
|
enableClerkModal?: boolean;
|
|
103
103
|
sectionClassName?: string;
|
|
104
104
|
enabledBillingTypes?: string[];
|
|
105
|
+
mobileBillingSwitchBehavior?: 'sticky' | 'static';
|
|
105
106
|
enableSubscriptionUpgrade?: boolean;
|
|
106
107
|
initUserContext?: InitUserContext;
|
|
107
108
|
initialBillingType?: string;
|
|
@@ -115,6 +116,7 @@ export interface MoneyPriceInteractiveProps {
|
|
|
115
116
|
customerPortalApiEndpoint?: string;
|
|
116
117
|
enableClerkModal?: boolean;
|
|
117
118
|
enabledBillingTypes?: string[];
|
|
119
|
+
mobileBillingSwitchBehavior?: 'sticky' | 'static';
|
|
118
120
|
enableSubscriptionUpgrade?: boolean;
|
|
119
121
|
initialBillingType?: string;
|
|
120
122
|
disableAutoDetectBilling?: boolean;
|
|
@@ -11,6 +11,7 @@ export async function MoneyPrice({
|
|
|
11
11
|
enableClerkModal = false,
|
|
12
12
|
sectionClassName,
|
|
13
13
|
enabledBillingTypes,
|
|
14
|
+
mobileBillingSwitchBehavior,
|
|
14
15
|
enableSubscriptionUpgrade = true,
|
|
15
16
|
initUserContext,
|
|
16
17
|
initialBillingType,
|
|
@@ -36,6 +37,7 @@ export async function MoneyPrice({
|
|
|
36
37
|
customerPortalApiEndpoint={customerPortalApiEndpoint}
|
|
37
38
|
enableClerkModal={enableClerkModal}
|
|
38
39
|
enabledBillingTypes={enabledBillingTypes}
|
|
40
|
+
mobileBillingSwitchBehavior={mobileBillingSwitchBehavior}
|
|
39
41
|
enableSubscriptionUpgrade={enableSubscriptionUpgrade}
|
|
40
42
|
initUserContext={initUserContext}
|
|
41
43
|
initialBillingType={initialBillingType}
|