@crediball/react 0.13.0 → 0.14.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/CrediballProvider.d.ts +17 -6
- package/dist/CrediballProvider.js +12 -10
- package/dist/PaywallModal.d.ts +18 -5
- package/dist/PaywallModal.js +36 -5
- package/dist/usePaywall.d.ts +6 -4
- package/dist/usePaywall.js +4 -4
- package/package.json +2 -2
|
@@ -32,14 +32,15 @@ export interface CrediballProviderProps {
|
|
|
32
32
|
* userId) and redirects — no backend wiring needed, just connect payouts in the
|
|
33
33
|
* dashboard. Provide this only to run your own top-up/checkout flow instead.
|
|
34
34
|
*/
|
|
35
|
-
onTopup?: (amount: number) => void | Promise<void>;
|
|
35
|
+
onTopup?: (amount: number, code?: string) => void | Promise<void>;
|
|
36
36
|
/**
|
|
37
37
|
* Optional override for one-time packages. If omitted, the paywall starts a
|
|
38
38
|
* Crediball-hosted Stripe Checkout itself and redirects (connect payouts in the
|
|
39
39
|
* dashboard). Provide this only to run your own flow (e.g. `meter.topup({ userId,
|
|
40
|
-
* packageId })` server-side).
|
|
40
|
+
* packageId })` server-side). The second argument is the promo code the user
|
|
41
|
+
* entered, if any (see `allowPromoCode`) — pass it through as `code`.
|
|
41
42
|
*/
|
|
42
|
-
onSelectPackage?: (pkg: PackageOption) => void | Promise<void>;
|
|
43
|
+
onSelectPackage?: (pkg: PackageOption, code?: string) => void | Promise<void>;
|
|
43
44
|
/**
|
|
44
45
|
* Optional override for subscription plans. If omitted, the paywall starts a
|
|
45
46
|
* recurring Stripe Checkout itself (connect payouts in the dashboard) and Stripe
|
|
@@ -85,6 +86,15 @@ export interface CrediballProviderProps {
|
|
|
85
86
|
customMin?: number;
|
|
86
87
|
/** Override the custom-amount maximum (defaults to the dashboard's configured maximum). */
|
|
87
88
|
customMax?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Show a "Have a promo code?" field in the paywall (Growth → Promotions'
|
|
91
|
+
* Checkout trigger). Off by default. The code is passed through to
|
|
92
|
+
* `onSelectPackage`/`onTopup`, or included automatically in the built-in
|
|
93
|
+
* checkout when neither is provided.
|
|
94
|
+
*/
|
|
95
|
+
allowPromoCode?: boolean;
|
|
96
|
+
/** Label above the promo code toggle (default "Have a promo code?"). */
|
|
97
|
+
promoCodeLabel?: string;
|
|
88
98
|
/**
|
|
89
99
|
* Currency symbol shown in the paywall. Auto-derived (via Intl) from the ISO
|
|
90
100
|
* currency you configured on the dashboard's Packages page once packages load,
|
|
@@ -153,8 +163,9 @@ interface CrediballContextValue {
|
|
|
153
163
|
error: Error | null;
|
|
154
164
|
/** Credit cost of a tracked event, from the live cost catalog. undefined if unknown. */
|
|
155
165
|
costOf: (event: string) => number | undefined;
|
|
156
|
-
/** Trigger a top-up (delegates to the `onTopup` prop) and refresh balance/usage on completion.
|
|
157
|
-
|
|
166
|
+
/** Trigger a top-up (delegates to the `onTopup` prop) and refresh balance/usage on completion.
|
|
167
|
+
* `code` is a checkout promo code, if any. */
|
|
168
|
+
topUp: (amount: number, code?: string) => Promise<void>;
|
|
158
169
|
/** Refetch balance, usage, costs, and packages immediately. No-op without publishableKey/userId. */
|
|
159
170
|
refresh: () => Promise<void>;
|
|
160
171
|
/** The live packages payload (top-up options, plans, custom-topup, currency, ui). null until loaded. */
|
|
@@ -184,7 +195,7 @@ interface CrediballContextValue {
|
|
|
184
195
|
* SSE/streaming routes (text/event-stream, ndjson) are also handled automatically —
|
|
185
196
|
* the watcher scans each chunk for credit errors, so no manual wiring is needed.
|
|
186
197
|
*/
|
|
187
|
-
export declare function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts, onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, onEnableAutoTopup, watchFetch, allowCustom, customMin, customMax, currencySymbol: currencySymbolProp, title, description, accentColor, applyRemoteTheme, captureReferrals, }: CrediballProviderProps): import("react").JSX.Element;
|
|
198
|
+
export declare function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts, onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, onEnableAutoTopup, watchFetch, allowCustom, customMin, customMax, allowPromoCode, promoCodeLabel, currencySymbol: currencySymbolProp, title, description, accentColor, applyRemoteTheme, captureReferrals, }: CrediballProviderProps): import("react").JSX.Element;
|
|
188
199
|
/**
|
|
189
200
|
* Access the paywall + live data from anywhere inside <CrediballProvider>.
|
|
190
201
|
*
|
|
@@ -63,7 +63,7 @@ function symbolForCurrency(iso) {
|
|
|
63
63
|
* SSE/streaming routes (text/event-stream, ndjson) are also handled automatically —
|
|
64
64
|
* the watcher scans each chunk for credit errors, so no manual wiring is needed.
|
|
65
65
|
*/
|
|
66
|
-
export function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts = [5, 10, 20], onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, onEnableAutoTopup, watchFetch = true, allowCustom, customMin, customMax, currencySymbol: currencySymbolProp, title, description, accentColor, applyRemoteTheme = true, captureReferrals = true, }) {
|
|
66
|
+
export function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts = [5, 10, 20], onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, onEnableAutoTopup, watchFetch = true, allowCustom, customMin, customMax, allowPromoCode, promoCodeLabel, currencySymbol: currencySymbolProp, title, description, accentColor, applyRemoteTheme = true, captureReferrals = true, }) {
|
|
67
67
|
const [open, setOpen] = useState(false);
|
|
68
68
|
// Referral auto-capture: pick up a `?ref=CODE` visit into localStorage (and
|
|
69
69
|
// count the click) as soon as the provider mounts — the visitor usually has
|
|
@@ -150,8 +150,8 @@ export function CrediballProvider({ children, publishableKey, userId, apiUrl, po
|
|
|
150
150
|
const refresh = useCallback(async () => {
|
|
151
151
|
await client?.refresh();
|
|
152
152
|
}, [client]);
|
|
153
|
-
const topUp = useCallback(async (amount) => {
|
|
154
|
-
await onTopup?.(amount);
|
|
153
|
+
const topUp = useCallback(async (amount, code) => {
|
|
154
|
+
await onTopup?.(amount, code);
|
|
155
155
|
notifyBalanceChanged();
|
|
156
156
|
await client?.refresh();
|
|
157
157
|
}, [onTopup, client]);
|
|
@@ -194,10 +194,12 @@ export function CrediballProvider({ children, publishableKey, userId, apiUrl, po
|
|
|
194
194
|
// handler always wins (and refreshes balance/usage on completion); otherwise fall
|
|
195
195
|
// back to the built-in Stripe checkout when a data client is available, leaving the
|
|
196
196
|
// modal open on failure so the error stays visible; otherwise just close the modal.
|
|
197
|
-
|
|
197
|
+
// `code` (a promo code from the paywall) is only meaningful for topup-shaped
|
|
198
|
+
// actions (handleAdd/handleSelectPackage) — other callers simply omit it.
|
|
199
|
+
async function runPaywallAction(hostHandler, arg, builtIn, errorLabel, code) {
|
|
198
200
|
if (hostHandler) {
|
|
199
201
|
try {
|
|
200
|
-
await hostHandler(arg);
|
|
202
|
+
await hostHandler(arg, code);
|
|
201
203
|
notifyBalanceChanged();
|
|
202
204
|
await client?.refresh();
|
|
203
205
|
}
|
|
@@ -218,11 +220,11 @@ export function CrediballProvider({ children, publishableKey, userId, apiUrl, po
|
|
|
218
220
|
// Data-less mode with no handler: nothing to charge against.
|
|
219
221
|
setOpen(false);
|
|
220
222
|
}
|
|
221
|
-
function handleAdd(amount) {
|
|
222
|
-
return runPaywallAction(onTopup, amount, () => startBuiltInCheckout({ eurAmount: amount }), "checkout");
|
|
223
|
+
function handleAdd(amount, code) {
|
|
224
|
+
return runPaywallAction(onTopup, amount, () => startBuiltInCheckout({ eurAmount: amount, code }), "checkout", code);
|
|
223
225
|
}
|
|
224
|
-
function handleSelectPackage(pkg) {
|
|
225
|
-
return runPaywallAction(onSelectPackage, pkg, () => startBuiltInCheckout({ packageId: pkg.id }), "checkout");
|
|
226
|
+
function handleSelectPackage(pkg, code) {
|
|
227
|
+
return runPaywallAction(onSelectPackage, pkg, () => startBuiltInCheckout({ packageId: pkg.id, code }), "checkout", code);
|
|
226
228
|
}
|
|
227
229
|
function handleSelectPlan(plan) {
|
|
228
230
|
return runPaywallAction(onSelectPlan, plan, async () => {
|
|
@@ -264,7 +266,7 @@ export function CrediballProvider({ children, publishableKey, userId, apiUrl, po
|
|
|
264
266
|
// layout box. Host props/CSS are overridden by design (dashboard wins).
|
|
265
267
|
const themeVars = applyRemoteTheme ? themeToCssVars(uiTheme) : {};
|
|
266
268
|
const hasThemeVars = Object.keys(themeVars).length > 0;
|
|
267
|
-
const inner = (_jsxs(_Fragment, { children: [children, _jsx(PaywallModal, { open: open, packages: pkgs?.packages, onSelectPackage: handleSelectPackage, subscriptionPlans: pkgs?.subscriptionPlans, onSelectPlan: handleSelectPlan, activeSubscription: pkgs?.activeSubscription, onCancelSubscription: onCancelSubscription ? handleCancelSubscription : undefined, autoTopup: pkgs?.autoTopup, onEnableAutoTopup: handleEnableAutoTopup, amounts: amounts, amountPrefix: `Add ${currencySymbol}`, onAdd: handleAdd, onClose: hidePaywall, allowCustom: effectiveAllowCustom, customMin: effectiveCustomMin, customMax: effectiveCustomMax, customTopupRate: pkgs?.customTopup.enabled ? pkgs.customTopup.rate : undefined, currencySymbol: currencySymbol, balance: snapshot.balance ?? undefined, balanceRate: pkgs?.customTopup.enabled ? pkgs.customTopup.rate : undefined, currency: pkgs?.currency, usage: snapshot.usage?.usedCredits ?? undefined, title: title ?? uiContent?.paywallTitle, description: description ?? uiContent?.paywallDescription, addButtonText: uiContent?.paywallButtonText, referralLink: referral?.link ?? undefined, referralReward: referral?.rewardCredits, referralLabel: uiContent?.referralLabel, accentColor: accentColor })] }));
|
|
269
|
+
const inner = (_jsxs(_Fragment, { children: [children, _jsx(PaywallModal, { open: open, packages: pkgs?.packages, onSelectPackage: handleSelectPackage, subscriptionPlans: pkgs?.subscriptionPlans, onSelectPlan: handleSelectPlan, activeSubscription: pkgs?.activeSubscription, onCancelSubscription: onCancelSubscription ? handleCancelSubscription : undefined, autoTopup: pkgs?.autoTopup, onEnableAutoTopup: handleEnableAutoTopup, amounts: amounts, amountPrefix: `Add ${currencySymbol}`, onAdd: handleAdd, onClose: hidePaywall, allowCustom: effectiveAllowCustom, customMin: effectiveCustomMin, customMax: effectiveCustomMax, allowPromoCode: allowPromoCode, promoCodeLabel: promoCodeLabel, customTopupRate: pkgs?.customTopup.enabled ? pkgs.customTopup.rate : undefined, currencySymbol: currencySymbol, balance: snapshot.balance ?? undefined, balanceRate: pkgs?.customTopup.enabled ? pkgs.customTopup.rate : undefined, currency: pkgs?.currency, usage: snapshot.usage?.usedCredits ?? undefined, title: title ?? uiContent?.paywallTitle, description: description ?? uiContent?.paywallDescription, addButtonText: uiContent?.paywallButtonText, referralLink: referral?.link ?? undefined, referralReward: referral?.rewardCredits, referralLabel: uiContent?.referralLabel, accentColor: accentColor })] }));
|
|
268
270
|
const configCtx = useMemo(() => ({ publishableKey, userId, apiUrl }), [publishableKey, userId, apiUrl]);
|
|
269
271
|
return (_jsx(CrediballContext.Provider, { value: ctx, children: _jsx(CrediballConfigContext.Provider, { value: configCtx, children: hasThemeVars ? (_jsx("div", { style: { display: "contents", ...themeVars }, children: inner })) : (inner) }) }));
|
|
270
272
|
}
|
package/dist/PaywallModal.d.ts
CHANGED
|
@@ -40,9 +40,11 @@ export interface PaywallModalProps extends CrediballThemeOverrides {
|
|
|
40
40
|
/**
|
|
41
41
|
* Called when the user selects a package. Use this with `packages` — call
|
|
42
42
|
* `meter.topup({ userId, packageId: pkg.id })` in your backend. No `amount`
|
|
43
|
-
* calculation needed; Crediball derives it from the package.
|
|
43
|
+
* calculation needed; Crediball derives it from the package. The second
|
|
44
|
+
* argument is the promo code the user entered (if the "Have a promo code?"
|
|
45
|
+
* field is shown and filled in) — pass it through as `code` to `topup()`.
|
|
44
46
|
*/
|
|
45
|
-
onSelectPackage?: (pkg: PackageOption) => void;
|
|
47
|
+
onSelectPackage?: (pkg: PackageOption, code?: string) => void;
|
|
46
48
|
/**
|
|
47
49
|
* Subscription plans from `meter.listPackages()`. When provided (and the user
|
|
48
50
|
* has no active subscription), the modal shows a "Subscribe" section above
|
|
@@ -94,11 +96,22 @@ export interface PaywallModalProps extends CrediballThemeOverrides {
|
|
|
94
96
|
amountPrefix?: string;
|
|
95
97
|
title?: string;
|
|
96
98
|
description?: string;
|
|
97
|
-
/** Called when the user clicks a legacy amount button.
|
|
98
|
-
|
|
99
|
+
/** Called when the user clicks a legacy amount button. The second argument is
|
|
100
|
+
* the promo code the user entered, same as `onSelectPackage`'s. */
|
|
101
|
+
onAdd?: (amount: number, code?: string) => void;
|
|
99
102
|
onClose?: () => void;
|
|
100
103
|
/** When true, show a free-form amount field in addition to the preset buttons. */
|
|
101
104
|
allowCustom?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* When true, show a "Have a promo code?" field above the top-up buttons. The
|
|
107
|
+
* code is passed as the second argument to `onSelectPackage`/`onAdd`/the
|
|
108
|
+
* built-in checkout — pass it through as `code` to `topup()` or
|
|
109
|
+
* `createCheckout()`. Not validated client-side; an invalid code is rejected
|
|
110
|
+
* when the top-up is actually processed.
|
|
111
|
+
*/
|
|
112
|
+
allowPromoCode?: boolean;
|
|
113
|
+
/** Label above the promo code toggle (default "Have a promo code?"). */
|
|
114
|
+
promoCodeLabel?: string;
|
|
102
115
|
/** Button label for the free-form amount field (default "Add"). */
|
|
103
116
|
addButtonText?: string;
|
|
104
117
|
/** Minimum custom amount (default 1). */
|
|
@@ -153,4 +166,4 @@ export interface PaywallModalProps extends CrediballThemeOverrides {
|
|
|
153
166
|
* continue. The host controls when it appears; shows a small "Powered by
|
|
154
167
|
* Crediball" line by default (set `hideBranding` to remove it).
|
|
155
168
|
*/
|
|
156
|
-
export declare function PaywallModal({ open, packages, onSelectPackage, subscriptionPlans, onSelectPlan, activeSubscription, onCancelSubscription, autoTopup, onEnableAutoTopup, amounts, amountPrefix, title, description, onAdd, onClose, allowCustom, addButtonText, customMin, customMax, customTopupRate, currencySymbol, balance, balanceRate, currency, usage, usageLabel, hideBranding, referralLink, referralReward, referralLabel, accentColor, style, }: PaywallModalProps): import("react").JSX.Element | null;
|
|
169
|
+
export declare function PaywallModal({ open, packages, onSelectPackage, subscriptionPlans, onSelectPlan, activeSubscription, onCancelSubscription, autoTopup, onEnableAutoTopup, amounts, amountPrefix, title, description, onAdd, onClose, allowCustom, allowPromoCode, promoCodeLabel, addButtonText, customMin, customMax, customTopupRate, currencySymbol, balance, balanceRate, currency, usage, usageLabel, hideBranding, referralLink, referralReward, referralLabel, accentColor, style, }: PaywallModalProps): import("react").JSX.Element | null;
|
package/dist/PaywallModal.js
CHANGED
|
@@ -25,7 +25,7 @@ function sectionLabelStyle(marginBottom) {
|
|
|
25
25
|
* continue. The host controls when it appears; shows a small "Powered by
|
|
26
26
|
* Crediball" line by default (set `hideBranding` to remove it).
|
|
27
27
|
*/
|
|
28
|
-
export function PaywallModal({ open, packages, onSelectPackage, subscriptionPlans, onSelectPlan, activeSubscription, onCancelSubscription, autoTopup, onEnableAutoTopup, amounts = [5, 10], amountPrefix = "Add €", title = "You need more credits to continue.", description = "Top up to keep using this feature.", onAdd, onClose, allowCustom = false, addButtonText = "Add", customMin = 1, customMax, customTopupRate, currencySymbol = "€", balance, balanceRate, currency = "EUR", usage, usageLabel = "Usage", hideBranding = false, referralLink, referralReward, referralLabel = "Refer a friend · earn {credits} credits", accentColor, style, }) {
|
|
28
|
+
export function PaywallModal({ open, packages, onSelectPackage, subscriptionPlans, onSelectPlan, activeSubscription, onCancelSubscription, autoTopup, onEnableAutoTopup, amounts = [5, 10], amountPrefix = "Add €", title = "You need more credits to continue.", description = "Top up to keep using this feature.", onAdd, onClose, allowCustom = false, allowPromoCode = false, promoCodeLabel = "Have a promo code?", addButtonText = "Add", customMin = 1, customMax, customTopupRate, currencySymbol = "€", balance, balanceRate, currency = "EUR", usage, usageLabel = "Usage", hideBranding = false, referralLink, referralReward, referralLabel = "Refer a friend · earn {credits} credits", accentColor, style, }) {
|
|
29
29
|
// Stack the top-up buttons one-per-line when the dialog itself is narrow.
|
|
30
30
|
// Measured off the dialog's own box (via ResizeObserver) rather than the
|
|
31
31
|
// window — in normal use the two are the same width, but this also makes
|
|
@@ -41,6 +41,8 @@ export function PaywallModal({ open, packages, onSelectPackage, subscriptionPlan
|
|
|
41
41
|
const [autoTopupOpen, setAutoTopupOpen] = useState(false);
|
|
42
42
|
const [autoTopupPackageId, setAutoTopupPackageId] = useState("");
|
|
43
43
|
const [autoTopupThreshold, setAutoTopupThreshold] = useState("");
|
|
44
|
+
const [promoCodeOpen, setPromoCodeOpen] = useState(false);
|
|
45
|
+
const [promoCode, setPromoCode] = useState("");
|
|
44
46
|
useEffect(() => {
|
|
45
47
|
const el = overlayRef.current;
|
|
46
48
|
if (!el || typeof ResizeObserver === "undefined")
|
|
@@ -82,6 +84,12 @@ export function PaywallModal({ open, packages, onSelectPackage, subscriptionPlan
|
|
|
82
84
|
setReferralCopied(true);
|
|
83
85
|
setTimeout(() => setReferralCopied(false), 2000);
|
|
84
86
|
}
|
|
87
|
+
// Undefined (not "") when empty, so onAdd/onSelectPackage receive `code`
|
|
88
|
+
// exactly as the SDK expects (an absent field, not an empty string).
|
|
89
|
+
function enteredCode() {
|
|
90
|
+
const trimmed = promoCode.trim();
|
|
91
|
+
return trimmed || undefined;
|
|
92
|
+
}
|
|
85
93
|
function submitCustom() {
|
|
86
94
|
const amt = Number(customValue);
|
|
87
95
|
if (!Number.isFinite(amt) || amt <= 0) {
|
|
@@ -97,7 +105,7 @@ export function PaywallModal({ open, packages, onSelectPackage, subscriptionPlan
|
|
|
97
105
|
return;
|
|
98
106
|
}
|
|
99
107
|
setCustomError(null);
|
|
100
|
-
onAdd?.(amt);
|
|
108
|
+
onAdd?.(amt, enteredCode());
|
|
101
109
|
}
|
|
102
110
|
function submitAutoTopup() {
|
|
103
111
|
const threshold = Number(autoTopupThreshold);
|
|
@@ -186,9 +194,32 @@ export function PaywallModal({ open, packages, onSelectPackage, subscriptionPlan
|
|
|
186
194
|
display: "flex",
|
|
187
195
|
justifyContent: "space-between",
|
|
188
196
|
alignItems: "center",
|
|
189
|
-
}, children: [_jsx("span", { children: plan.name }), _jsxs("span", { style: { opacity: 0.85, fontSize: 14 }, children: [formatMoney(plan.price, currency), "/", PERIOD_SUFFIX[plan.period], " \u00B7 ", formatCredits(plan.credits), " cr"] })] }, plan.id))) })] })),
|
|
190
|
-
|
|
191
|
-
|
|
197
|
+
}, children: [_jsx("span", { children: plan.name }), _jsxs("span", { style: { opacity: 0.85, fontSize: 14 }, children: [formatMoney(plan.price, currency), "/", PERIOD_SUFFIX[plan.period], " \u00B7 ", formatCredits(plan.credits), " cr"] })] }, plan.id))) })] })), allowPromoCode && !activeSubscription && (_jsx("div", { style: { marginTop: 16 }, children: promoCodeOpen ? (_jsxs("div", { children: [_jsx("div", { style: { ...sectionLabelStyle(6) }, children: promoCodeLabel }), _jsx("input", { value: promoCode, onChange: (e) => setPromoCode(e.target.value.toUpperCase()), placeholder: "PROMOCODE", style: {
|
|
198
|
+
width: "100%",
|
|
199
|
+
boxSizing: "border-box",
|
|
200
|
+
appearance: "none",
|
|
201
|
+
fontFamily: theme.font,
|
|
202
|
+
fontSize: 14,
|
|
203
|
+
lineHeight: "20px",
|
|
204
|
+
padding: "8px 12px",
|
|
205
|
+
borderRadius: theme.radiusPill,
|
|
206
|
+
border: `1px solid ${theme.hairline}`,
|
|
207
|
+
color: theme.ink,
|
|
208
|
+
background: theme.canvas,
|
|
209
|
+
outline: "none",
|
|
210
|
+
} })] })) : (_jsx("button", { onClick: () => setPromoCodeOpen(true), style: {
|
|
211
|
+
appearance: "none",
|
|
212
|
+
border: "none",
|
|
213
|
+
background: "transparent",
|
|
214
|
+
cursor: "pointer",
|
|
215
|
+
padding: 0,
|
|
216
|
+
fontSize: 12,
|
|
217
|
+
color: theme.inkMuted,
|
|
218
|
+
fontFamily: theme.font,
|
|
219
|
+
textDecoration: "underline",
|
|
220
|
+
}, children: promoCodeLabel })) })), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 10, marginTop: 24 }, children: [(!activeSubscription && subscriptionPlans && subscriptionPlans.length > 0) && (_jsx("div", { style: sectionLabelStyle(-2), children: "Or buy credits" })), activeSubscription && packages && packages.length > 0 && (_jsx("div", { style: sectionLabelStyle(-2), children: "Add extra credits" })), packages && packages.length > 0
|
|
221
|
+
? packages.map((pkg) => (_jsxs("button", { onClick: () => onSelectPackage?.(pkg, enteredCode()), style: { ...buttonStyle, flex: "none", display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [_jsx("span", { children: pkg.name }), _jsxs("span", { style: { opacity: 0.85, fontSize: 14 }, children: [formatMoney(pkg.price, currency), " \u00B7 ", formatCredits(pkg.credits), " cr"] })] }, pkg.id)))
|
|
222
|
+
: (!activeSubscription && (_jsx("div", { style: { display: "flex", flexDirection: narrow ? "column" : "row", gap: 12 }, children: amounts.map((amount) => (_jsxs("button", { onClick: () => onAdd?.(amount, enteredCode()), style: buttonStyle, children: [amountPrefix, amount] }, amount))) })))] }), allowCustom ? (_jsxs("div", { style: { marginTop: 12 }, children: [_jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [_jsx("span", { style: { fontSize: 14, color: theme.inkMuted }, children: currencySymbol }), _jsx("input", { value: customValue, onChange: (e) => setCustomValue(e.target.value), inputMode: "decimal", placeholder: String(customMin), style: {
|
|
192
223
|
flex: 1,
|
|
193
224
|
minWidth: 0,
|
|
194
225
|
appearance: "none",
|
package/dist/usePaywall.d.ts
CHANGED
|
@@ -7,10 +7,12 @@ import { type PaywallModalProps, type PackageOption, type SubscriptionPlanOption
|
|
|
7
7
|
* accept async handlers. Add watchFetch to auto-open on detected credit errors.
|
|
8
8
|
*/
|
|
9
9
|
export type UsePaywallProps = Omit<PaywallModalProps, "open" | "onClose" | "onAdd" | "style"> & {
|
|
10
|
-
/** Called when the user picks a legacy preset/custom top-up amount.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
/** Called when the user picks a legacy preset/custom top-up amount. The
|
|
11
|
+
* second argument is the promo code entered, if any (see `allowPromoCode`). */
|
|
12
|
+
onTopup?: (amount: number, code?: string) => void | Promise<void>;
|
|
13
|
+
/** Called when the user picks a one-time package (async override). The second
|
|
14
|
+
* argument is the promo code entered, if any (see `allowPromoCode`). */
|
|
15
|
+
onSelectPackage?: (pkg: PackageOption, code?: string) => void | Promise<void>;
|
|
14
16
|
/** Called when the user picks a subscription plan (async override). */
|
|
15
17
|
onSelectPlan?: (plan: SubscriptionPlanOption) => void | Promise<void>;
|
|
16
18
|
/**
|
package/dist/usePaywall.js
CHANGED
|
@@ -36,13 +36,13 @@ export function usePaywall({ onTopup, onSelectPackage, onSelectPlan, watchFetch
|
|
|
36
36
|
return;
|
|
37
37
|
return subscribeFetchWatcher(() => triggerRef.current());
|
|
38
38
|
}, [watchFetch]);
|
|
39
|
-
const handleTopup = useCallback(async (amount) => {
|
|
39
|
+
const handleTopup = useCallback(async (amount, code) => {
|
|
40
40
|
setIsOpen(false);
|
|
41
|
-
await onTopup?.(amount);
|
|
41
|
+
await onTopup?.(amount, code);
|
|
42
42
|
}, [onTopup]);
|
|
43
|
-
const handleSelectPackage = useCallback(async (pkg) => {
|
|
43
|
+
const handleSelectPackage = useCallback(async (pkg, code) => {
|
|
44
44
|
setIsOpen(false);
|
|
45
|
-
await onSelectPackage?.(pkg);
|
|
45
|
+
await onSelectPackage?.(pkg, code);
|
|
46
46
|
}, [onSelectPackage]);
|
|
47
47
|
const handleSelectPlan = useCallback(async (plan) => {
|
|
48
48
|
setIsOpen(false);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crediball/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Drop-in React components for showing Crediball credits inside your AI app.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Filippo Rezzadore <filipporezzadore@gmail.com>",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"react": ">=18"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@crediball/core": "^0.
|
|
54
|
+
"@crediball/core": "^0.8.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/react": "^18.3.11",
|