@crediball/react 0.5.0 → 0.7.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 -7
- package/dist/CrediballProvider.js +50 -12
- package/dist/PaywallModal.js +1 -1
- package/package.json +3 -3
|
@@ -41,13 +41,18 @@ export interface CrediballProviderProps {
|
|
|
41
41
|
*/
|
|
42
42
|
onSelectPackage?: (pkg: PackageOption) => void | Promise<void>;
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
44
|
+
* Optional override for subscription plans. If omitted, the paywall starts a
|
|
45
|
+
* recurring Stripe Checkout itself (connect payouts in the dashboard) and Stripe
|
|
46
|
+
* grants the plan's credits each period. Provide this only to run your own flow
|
|
47
|
+
* (e.g. `meter.subscribe({ userId, planId })` server-side).
|
|
48
48
|
*/
|
|
49
49
|
onSelectPlan?: (plan: SubscriptionPlanOption) => void | Promise<void>;
|
|
50
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Called when the user cancels their subscription. Cancellation is server-side
|
|
52
|
+
* only (it needs your secret key), so the paywall shows a Cancel button on the
|
|
53
|
+
* active-subscription banner ONLY when this is provided — wire it to
|
|
54
|
+
* `meter.cancelSubscription({ userId, subscriptionId })` on your backend.
|
|
55
|
+
*/
|
|
51
56
|
onCancelSubscription?: (subscriptionId: string) => void | Promise<void>;
|
|
52
57
|
/**
|
|
53
58
|
* Auto-detect insufficient-credit responses from any fetch() call and open the
|
|
@@ -68,7 +73,12 @@ export interface CrediballProviderProps {
|
|
|
68
73
|
customMin?: number;
|
|
69
74
|
/** Override the custom-amount maximum (defaults to the dashboard's configured maximum). */
|
|
70
75
|
customMax?: number;
|
|
71
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Currency symbol shown in the paywall. Auto-derived (via Intl) from the ISO
|
|
78
|
+
* currency you configured on the dashboard's Packages page once packages load,
|
|
79
|
+
* so it never drifts out of sync if you switch currencies there. Pass this only
|
|
80
|
+
* to force a specific symbol instead. Falls back to "€" before the first fetch.
|
|
81
|
+
*/
|
|
72
82
|
currencySymbol?: string;
|
|
73
83
|
title?: string;
|
|
74
84
|
description?: string;
|
|
@@ -127,7 +137,7 @@ interface CrediballContextValue {
|
|
|
127
137
|
* SSE/streaming routes (text/event-stream, ndjson) are also handled automatically —
|
|
128
138
|
* the watcher scans each chunk for credit errors, so no manual wiring is needed.
|
|
129
139
|
*/
|
|
130
|
-
export declare function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts, onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, watchFetch, allowCustom, customMin, customMax, currencySymbol, title, description, accentColor, }: CrediballProviderProps): import("react").JSX.Element;
|
|
140
|
+
export declare function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts, onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, watchFetch, allowCustom, customMin, customMax, currencySymbol: currencySymbolProp, title, description, accentColor, }: CrediballProviderProps): import("react").JSX.Element;
|
|
131
141
|
/**
|
|
132
142
|
* Access the paywall + live data from anywhere inside <CrediballProvider>.
|
|
133
143
|
*
|
|
@@ -18,6 +18,22 @@ const EMPTY_SNAPSHOT = {
|
|
|
18
18
|
};
|
|
19
19
|
const noopSubscribe = () => () => { };
|
|
20
20
|
const getEmptySnapshot = () => EMPTY_SNAPSHOT;
|
|
21
|
+
/**
|
|
22
|
+
* Map an ISO 4217 code (as returned by the dashboard's packages config) to a
|
|
23
|
+
* display symbol via Intl, so the paywall doesn't need a hand-maintained
|
|
24
|
+
* currency → symbol table that can fall out of sync with the dashboard.
|
|
25
|
+
*/
|
|
26
|
+
function symbolForCurrency(iso) {
|
|
27
|
+
try {
|
|
28
|
+
const part = new Intl.NumberFormat(undefined, { style: "currency", currency: iso })
|
|
29
|
+
.formatToParts(0)
|
|
30
|
+
.find((p) => p.type === "currency");
|
|
31
|
+
return part?.value ?? iso;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return iso;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
21
37
|
/**
|
|
22
38
|
* Pattern B, automated. Wrap your app once:
|
|
23
39
|
*
|
|
@@ -38,7 +54,7 @@ const getEmptySnapshot = () => EMPTY_SNAPSHOT;
|
|
|
38
54
|
* SSE/streaming routes (text/event-stream, ndjson) are also handled automatically —
|
|
39
55
|
* the watcher scans each chunk for credit errors, so no manual wiring is needed.
|
|
40
56
|
*/
|
|
41
|
-
export function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts = [5, 10, 20], onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, watchFetch = true, allowCustom, customMin, customMax, currencySymbol
|
|
57
|
+
export function CrediballProvider({ children, publishableKey, userId, apiUrl, pollIntervalMs, lowCreditThreshold, amounts = [5, 10, 20], onTopup, onSelectPackage, onSelectPlan, onCancelSubscription, watchFetch = true, allowCustom, customMin, customMax, currencySymbol: currencySymbolProp, title, description, accentColor, }) {
|
|
42
58
|
const [open, setOpen] = useState(false);
|
|
43
59
|
const showPaywall = useCallback(() => setOpen(true), []);
|
|
44
60
|
const hidePaywall = useCallback(() => setOpen(false), []);
|
|
@@ -158,20 +174,46 @@ export function CrediballProvider({ children, publishableKey, userId, apiUrl, po
|
|
|
158
174
|
setOpen(false);
|
|
159
175
|
}
|
|
160
176
|
async function handleSelectPlan(plan) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
177
|
+
// Host-supplied subscription flow wins.
|
|
178
|
+
if (onSelectPlan) {
|
|
179
|
+
try {
|
|
180
|
+
await onSelectPlan(plan);
|
|
181
|
+
notifyBalanceChanged();
|
|
182
|
+
await client?.refresh();
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
setOpen(false);
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
165
188
|
}
|
|
166
|
-
|
|
167
|
-
|
|
189
|
+
// Otherwise start the recurring Stripe Checkout ourselves. Leave the modal
|
|
190
|
+
// open on failure so the error is visible.
|
|
191
|
+
if (client) {
|
|
192
|
+
try {
|
|
193
|
+
const { url } = await client.createSubscriptionCheckout({
|
|
194
|
+
planId: plan.id,
|
|
195
|
+
returnPath: currentReturnPath(),
|
|
196
|
+
});
|
|
197
|
+
if (typeof window !== "undefined")
|
|
198
|
+
window.location.assign(url);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
console.error("[crediball] subscription checkout failed:", err);
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
168
204
|
}
|
|
205
|
+
setOpen(false);
|
|
169
206
|
}
|
|
170
207
|
async function handleCancelSubscription(subscriptionId) {
|
|
171
208
|
await onCancelSubscription?.(subscriptionId);
|
|
172
209
|
await client?.refresh();
|
|
173
210
|
}
|
|
174
211
|
const pkgs = snapshot.packages;
|
|
212
|
+
// Follow the dashboard's configured currency once packages load, unless the
|
|
213
|
+
// host pins an explicit symbol. Falls back to "€" only until the first fetch
|
|
214
|
+
// resolves, so switching currencies on the Packages page never requires a
|
|
215
|
+
// matching code change/redeploy here.
|
|
216
|
+
const currencySymbol = currencySymbolProp ?? (pkgs?.currency ? symbolForCurrency(pkgs.currency) : "€");
|
|
175
217
|
// Auto-derive the custom-amount field from the dashboard's custom-topup config,
|
|
176
218
|
// so a developer who enabled it doesn't also have to pass allowCustom/min/max.
|
|
177
219
|
// Explicit props still win (allowCustom={false} force-hides it).
|
|
@@ -179,11 +221,7 @@ export function CrediballProvider({ children, publishableKey, userId, apiUrl, po
|
|
|
179
221
|
const effectiveAllowCustom = allowCustom ?? customCfg?.enabled ?? false;
|
|
180
222
|
const effectiveCustomMin = customMin ?? customCfg?.minEur;
|
|
181
223
|
const effectiveCustomMax = customMax ?? customCfg?.maxEur ?? undefined;
|
|
182
|
-
return (_jsxs(CrediballContext.Provider, { value: ctx, children: [children, _jsx(PaywallModal, { open: open, packages: pkgs?.packages, onSelectPackage: handleSelectPackage,
|
|
183
|
-
// Subscriptions can't be fulfilled by the built-in checkout (that path is
|
|
184
|
-
// one-time top-ups only), so only OFFER them when the host wired an
|
|
185
|
-
// onSelectPlan to fulfill them — otherwise they'd be dead buttons.
|
|
186
|
-
subscriptionPlans: onSelectPlan ? pkgs?.subscriptionPlans : undefined, onSelectPlan: handleSelectPlan, activeSubscription: pkgs?.activeSubscription, onCancelSubscription: handleCancelSubscription, amounts: amounts, amountPrefix: `Add ${currencySymbol}`, onAdd: handleAdd, onClose: hidePaywall, allowCustom: effectiveAllowCustom, customMin: effectiveCustomMin, customMax: effectiveCustomMax, currencySymbol: currencySymbol, balance: snapshot.balance ?? undefined, balanceRate: pkgs?.customTopup.enabled ? pkgs.customTopup.rate : undefined, currency: pkgs?.currency, usage: snapshot.usage?.usedCredits ?? undefined, title: title, description: description, accentColor: accentColor })] }));
|
|
224
|
+
return (_jsxs(CrediballContext.Provider, { value: ctx, children: [children, _jsx(PaywallModal, { open: open, packages: pkgs?.packages, onSelectPackage: handleSelectPackage, subscriptionPlans: pkgs?.subscriptionPlans, onSelectPlan: handleSelectPlan, activeSubscription: pkgs?.activeSubscription, onCancelSubscription: handleCancelSubscription, amounts: amounts, amountPrefix: `Add ${currencySymbol}`, onAdd: handleAdd, onClose: hidePaywall, allowCustom: effectiveAllowCustom, customMin: effectiveCustomMin, customMax: effectiveCustomMax, currencySymbol: currencySymbol, balance: snapshot.balance ?? undefined, balanceRate: pkgs?.customTopup.enabled ? pkgs.customTopup.rate : undefined, currency: pkgs?.currency, usage: snapshot.usage?.usedCredits ?? undefined, title: title, description: description, accentColor: accentColor })] }));
|
|
187
225
|
}
|
|
188
226
|
/**
|
|
189
227
|
* Access the paywall + live data from anywhere inside <CrediballProvider>.
|
package/dist/PaywallModal.js
CHANGED
|
@@ -130,7 +130,7 @@ export function PaywallModal({ open, packages, onSelectPackage, subscriptionPlan
|
|
|
130
130
|
borderRadius: theme.radiusCard,
|
|
131
131
|
background: "#f5f5f7",
|
|
132
132
|
border: `1px solid ${theme.hairline}`,
|
|
133
|
-
}, children: [_jsx("div", { style: { fontSize: 13, fontWeight: 600, color: theme.ink }, children: cancelDone ? "Subscription canceled" : `${activeSubscription.planName} · ${activeSubscription.planPeriod}` }), !cancelDone && (_jsx("button", { onClick: handleCancelSubscription, disabled: cancelPending, style: {
|
|
133
|
+
}, children: [_jsx("div", { style: { fontSize: 13, fontWeight: 600, color: theme.ink }, children: cancelDone ? "Subscription canceled" : `${activeSubscription.planName} · ${activeSubscription.planPeriod}` }), onCancelSubscription && !cancelDone && (_jsx("button", { onClick: handleCancelSubscription, disabled: cancelPending, style: {
|
|
134
134
|
marginTop: 8,
|
|
135
135
|
appearance: "none",
|
|
136
136
|
border: "none",
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crediball/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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>",
|
|
7
|
-
"homepage": "https://crediball.
|
|
7
|
+
"homepage": "https://crediball.ai",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/filipporezzadore/Crediball.git",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"react": ">=18"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@crediball/core": "^0.
|
|
54
|
+
"@crediball/core": "^0.2.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/react": "^18.3.11",
|