@nozle-js/react 0.8.0 → 0.9.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/index.cjs +308 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -27
- package/dist/index.d.ts +97 -27
- package/dist/index.js +309 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useMemo, useContext, useState, useEffect, useCallback } from 'react';
|
|
1
|
+
import React, { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
|
|
2
2
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { EmbeddedCheckoutProvider, EmbeddedCheckout, Elements, useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js';
|
|
4
4
|
import { loadStripe } from '@stripe/stripe-js';
|
|
@@ -25,21 +25,29 @@ var BillingContext = createContext(null);
|
|
|
25
25
|
function BillingProvider({
|
|
26
26
|
publishableKey,
|
|
27
27
|
createCheckout,
|
|
28
|
+
verifyCheckout,
|
|
29
|
+
getCheckoutStatus,
|
|
28
30
|
baseUrl = "https://api.nozle.app/engine",
|
|
29
31
|
children
|
|
30
32
|
}) {
|
|
31
33
|
if (!publishableKey.startsWith("pk_")) {
|
|
32
|
-
throw new Error(
|
|
34
|
+
throw new Error(
|
|
35
|
+
"BillingProvider publishableKey must be a publishable key (pk_)"
|
|
36
|
+
);
|
|
33
37
|
}
|
|
34
38
|
const client = useMemo(
|
|
35
39
|
() => createClient(publishableKey, baseUrl),
|
|
36
40
|
[publishableKey, baseUrl]
|
|
37
41
|
);
|
|
38
42
|
const contextValue = useMemo(
|
|
39
|
-
() => ({ client, createCheckout }),
|
|
40
|
-
[client, createCheckout]
|
|
43
|
+
() => ({ client, createCheckout, verifyCheckout, getCheckoutStatus }),
|
|
44
|
+
[client, createCheckout, verifyCheckout, getCheckoutStatus]
|
|
45
|
+
);
|
|
46
|
+
return React.createElement(
|
|
47
|
+
BillingContext.Provider,
|
|
48
|
+
{ value: contextValue },
|
|
49
|
+
children
|
|
41
50
|
);
|
|
42
|
-
return React.createElement(BillingContext.Provider, { value: contextValue }, children);
|
|
43
51
|
}
|
|
44
52
|
function useOptionalBillingContext() {
|
|
45
53
|
return useContext(BillingContext);
|
|
@@ -110,7 +118,11 @@ function useCheckout() {
|
|
|
110
118
|
navigateToCheckout(result.url);
|
|
111
119
|
return null;
|
|
112
120
|
}
|
|
113
|
-
if ("type" in result &&
|
|
121
|
+
if ("type" in result && result.type === "hosted") {
|
|
122
|
+
navigateToCheckout(result.payment_url);
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
if ("type" in result && ["completed", "scheduled", "razorpay", "processing"].includes(result.type)) {
|
|
114
126
|
return null;
|
|
115
127
|
}
|
|
116
128
|
throw new Error("Checkout response did not include a supported result type");
|
|
@@ -126,20 +138,151 @@ function useCheckout() {
|
|
|
126
138
|
);
|
|
127
139
|
return { fetchClientSecret, checkout, isLoading, error };
|
|
128
140
|
}
|
|
141
|
+
|
|
142
|
+
// src/components/billing/razorpay-checkout.ts
|
|
143
|
+
var loadingScript;
|
|
129
144
|
function loadRazorpayScript() {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
if (typeof window === "undefined")
|
|
146
|
+
return Promise.reject(new Error("Razorpay checkout requires a browser"));
|
|
147
|
+
if (window.Razorpay) return Promise.resolve();
|
|
148
|
+
if (loadingScript) return loadingScript;
|
|
149
|
+
loadingScript = new Promise((resolve, reject) => {
|
|
150
|
+
const existing = document.querySelector(
|
|
151
|
+
'script[src="https://checkout.razorpay.com/v1/checkout.js"]'
|
|
152
|
+
);
|
|
153
|
+
const script = existing || document.createElement("script");
|
|
154
|
+
const finish = (error) => {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
script.removeEventListener("load", onLoad);
|
|
157
|
+
script.removeEventListener("error", onError);
|
|
158
|
+
if (error) {
|
|
159
|
+
script.remove();
|
|
160
|
+
reject(error);
|
|
161
|
+
} else {
|
|
162
|
+
resolve();
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const onLoad = () => finish(
|
|
166
|
+
window.Razorpay ? void 0 : new Error("Razorpay checkout did not initialize")
|
|
167
|
+
);
|
|
168
|
+
const onError = () => finish(new Error("Failed to load Razorpay checkout"));
|
|
169
|
+
const timer = setTimeout(
|
|
170
|
+
() => finish(new Error("Razorpay checkout timed out while loading")),
|
|
171
|
+
15e3
|
|
172
|
+
);
|
|
173
|
+
script.addEventListener("load", onLoad);
|
|
174
|
+
script.addEventListener("error", onError);
|
|
175
|
+
if (!existing) {
|
|
176
|
+
script.id = "razorpay-js";
|
|
177
|
+
script.src = "https://checkout.razorpay.com/v1/checkout.js";
|
|
178
|
+
document.body.appendChild(script);
|
|
134
179
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
180
|
+
}).catch((error) => {
|
|
181
|
+
loadingScript = void 0;
|
|
182
|
+
throw error;
|
|
183
|
+
});
|
|
184
|
+
return loadingScript;
|
|
185
|
+
}
|
|
186
|
+
function checkStatus(status, id) {
|
|
187
|
+
if (status.checkout_id !== id || status.provider !== "razorpay")
|
|
188
|
+
throw new Error("Checkout status did not match this checkout");
|
|
189
|
+
if (["failed", "expired", "needs_review"].includes(status.status))
|
|
190
|
+
throw new Error(`Checkout ${status.status.replaceAll("_", " ")}`);
|
|
191
|
+
}
|
|
192
|
+
async function waitForCheckout(id, actions, initial, phase = "confirm") {
|
|
193
|
+
let status = initial;
|
|
194
|
+
if (!status && !actions.getCheckoutStatus)
|
|
195
|
+
throw new Error("BillingProvider getCheckoutStatus callback is required");
|
|
196
|
+
for (let attempt = 0; attempt < 30; attempt++) {
|
|
197
|
+
status = status || await actions.getCheckoutStatus(id);
|
|
198
|
+
checkStatus(status, id);
|
|
199
|
+
if (status.status === "succeeded" && status.fulfillment_status === "succeeded" || phase === "prepare" && status.status === "awaiting_payment")
|
|
200
|
+
return status;
|
|
201
|
+
actions.onProcessing?.(status);
|
|
202
|
+
if (!actions.getCheckoutStatus) return status;
|
|
203
|
+
if (attempt < 29) {
|
|
204
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
205
|
+
status = void 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return status;
|
|
209
|
+
}
|
|
210
|
+
async function openRazorpayCheckout(result, actions) {
|
|
211
|
+
if (!result.checkout_id || !result.key_id || !result.order_id)
|
|
212
|
+
throw new Error(
|
|
213
|
+
"Razorpay checkout requires server-issued checkout_id, key_id and order_id"
|
|
214
|
+
);
|
|
215
|
+
if (!actions.verifyCheckout)
|
|
216
|
+
throw new Error(
|
|
217
|
+
"BillingProvider verifyCheckout callback is required for Razorpay checkout"
|
|
218
|
+
);
|
|
219
|
+
await loadRazorpayScript();
|
|
220
|
+
await new Promise((resolve, reject) => {
|
|
221
|
+
let finishing = false;
|
|
222
|
+
const checkout = new window.Razorpay({
|
|
223
|
+
key: result.key_id,
|
|
224
|
+
order_id: result.order_id,
|
|
225
|
+
amount: result.amount_cents,
|
|
226
|
+
currency: result.currency,
|
|
227
|
+
...result.recurring && {
|
|
228
|
+
customer_id: result.customer_id,
|
|
229
|
+
recurring: "1"
|
|
230
|
+
},
|
|
231
|
+
handler: (response) => {
|
|
232
|
+
if (finishing) return;
|
|
233
|
+
finishing = true;
|
|
234
|
+
void (async () => {
|
|
235
|
+
const verified = await actions.verifyCheckout(
|
|
236
|
+
result.checkout_id,
|
|
237
|
+
response
|
|
238
|
+
);
|
|
239
|
+
const status = await waitForCheckout(
|
|
240
|
+
result.checkout_id,
|
|
241
|
+
actions,
|
|
242
|
+
verified
|
|
243
|
+
);
|
|
244
|
+
if (status.status === "succeeded" && status.fulfillment_status === "succeeded")
|
|
245
|
+
actions.onSuccess?.(response.razorpay_payment_id);
|
|
246
|
+
else actions.onProcessing?.(status);
|
|
247
|
+
resolve();
|
|
248
|
+
})().catch(reject);
|
|
249
|
+
},
|
|
250
|
+
modal: {
|
|
251
|
+
ondismiss: () => {
|
|
252
|
+
if (!finishing) {
|
|
253
|
+
finishing = true;
|
|
254
|
+
actions.onDismiss?.();
|
|
255
|
+
resolve();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
checkout.on("payment.failed", () => {
|
|
261
|
+
if (finishing) return;
|
|
262
|
+
finishing = true;
|
|
263
|
+
checkout.close();
|
|
264
|
+
reject(new Error("Payment failed. You can retry checkout."));
|
|
265
|
+
});
|
|
266
|
+
checkout.open();
|
|
141
267
|
});
|
|
142
268
|
}
|
|
269
|
+
async function resumeCheckout(result, actions) {
|
|
270
|
+
const status = await waitForCheckout(
|
|
271
|
+
result.checkout_id,
|
|
272
|
+
actions,
|
|
273
|
+
void 0,
|
|
274
|
+
"prepare"
|
|
275
|
+
);
|
|
276
|
+
if (status.status === "awaiting_payment") return status.checkout;
|
|
277
|
+
if (status.status === "succeeded" && status.fulfillment_status === "succeeded")
|
|
278
|
+
return {
|
|
279
|
+
type: "completed",
|
|
280
|
+
status: "succeeded",
|
|
281
|
+
invoice_id: status.invoice_id || void 0
|
|
282
|
+
};
|
|
283
|
+
actions.onProcessing?.(status);
|
|
284
|
+
return void 0;
|
|
285
|
+
}
|
|
143
286
|
async function handleCheckoutResult(result, options) {
|
|
144
287
|
if ("type" in result && result.type === "scheduled") {
|
|
145
288
|
options.onScheduled?.(result);
|
|
@@ -150,14 +293,16 @@ async function handleCheckoutResult(result, options) {
|
|
|
150
293
|
return;
|
|
151
294
|
}
|
|
152
295
|
if ("type" in result && result.type === "razorpay") {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
296
|
+
await openRazorpayCheckout(result, options);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if ("type" in result && result.type === "processing") {
|
|
300
|
+
const next = await resumeCheckout(result, options);
|
|
301
|
+
if (next) await handleCheckoutResult(next, options);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if ("type" in result && result.type === "hosted") {
|
|
305
|
+
window.location.assign(result.payment_url);
|
|
161
306
|
return;
|
|
162
307
|
}
|
|
163
308
|
if ("url" in result && result.url) {
|
|
@@ -170,7 +315,10 @@ async function handleCheckoutResult(result, options) {
|
|
|
170
315
|
options.onStripeClientSecret(clientSecret);
|
|
171
316
|
return;
|
|
172
317
|
}
|
|
173
|
-
if (clientSecret)
|
|
318
|
+
if (clientSecret)
|
|
319
|
+
throw new Error(
|
|
320
|
+
"onStripeClientSecret is required for embedded Stripe checkout"
|
|
321
|
+
);
|
|
174
322
|
throw new Error("Stripe checkout did not include a URL or client secret");
|
|
175
323
|
}
|
|
176
324
|
throw new Error("Unknown checkout response format");
|
|
@@ -183,30 +331,58 @@ function CheckoutButton({
|
|
|
183
331
|
style,
|
|
184
332
|
onError,
|
|
185
333
|
razorpayKeyId,
|
|
334
|
+
registerMandate,
|
|
335
|
+
onProcessing,
|
|
336
|
+
onDismiss,
|
|
186
337
|
onStripeClientSecret,
|
|
187
338
|
onSuccess,
|
|
188
339
|
onComplete,
|
|
189
340
|
onScheduled
|
|
190
341
|
}) {
|
|
191
|
-
const { createCheckout } = useBillingContext();
|
|
342
|
+
const { createCheckout, verifyCheckout, getCheckoutStatus } = useBillingContext();
|
|
343
|
+
const attempt = useRef(void 0);
|
|
344
|
+
const inFlight = useRef(false);
|
|
345
|
+
const [processing, setProcessing] = useState(false);
|
|
192
346
|
const [loading, setLoading] = useState(false);
|
|
193
347
|
const [error, setError] = useState(null);
|
|
194
348
|
async function handleClick() {
|
|
349
|
+
if (inFlight.current) return;
|
|
350
|
+
inFlight.current = true;
|
|
195
351
|
setLoading(true);
|
|
352
|
+
setProcessing(false);
|
|
196
353
|
setError(null);
|
|
197
354
|
try {
|
|
198
355
|
if (!createCheckout) {
|
|
199
|
-
throw new Error(
|
|
356
|
+
throw new Error(
|
|
357
|
+
"BillingProvider createCheckout callback is required for checkout"
|
|
358
|
+
);
|
|
200
359
|
}
|
|
360
|
+
if (attempt.current?.plan !== planCode)
|
|
361
|
+
attempt.current = { plan: planCode, key: crypto.randomUUID() };
|
|
201
362
|
const result = await createCheckout({
|
|
363
|
+
idempotencyKey: attempt.current.key,
|
|
364
|
+
...registerMandate !== void 0 && { registerMandate },
|
|
202
365
|
planCode,
|
|
203
366
|
returnUrl: returnUrl ?? window.location.href
|
|
204
367
|
});
|
|
205
368
|
await handleCheckoutResult(result, {
|
|
206
369
|
razorpayKeyId,
|
|
370
|
+
verifyCheckout,
|
|
371
|
+
getCheckoutStatus,
|
|
372
|
+
onProcessing: (status) => {
|
|
373
|
+
setProcessing(true);
|
|
374
|
+
onProcessing?.(status);
|
|
375
|
+
},
|
|
376
|
+
onDismiss,
|
|
207
377
|
onStripeClientSecret,
|
|
208
|
-
onSuccess
|
|
209
|
-
|
|
378
|
+
onSuccess: (id) => {
|
|
379
|
+
setProcessing(false);
|
|
380
|
+
onSuccess?.(id);
|
|
381
|
+
},
|
|
382
|
+
onComplete: (completed) => {
|
|
383
|
+
setProcessing(false);
|
|
384
|
+
onComplete?.(completed);
|
|
385
|
+
},
|
|
210
386
|
onScheduled
|
|
211
387
|
});
|
|
212
388
|
} catch (cause) {
|
|
@@ -214,6 +390,7 @@ function CheckoutButton({
|
|
|
214
390
|
setError(checkoutError);
|
|
215
391
|
onError?.(checkoutError);
|
|
216
392
|
} finally {
|
|
393
|
+
inFlight.current = false;
|
|
217
394
|
setLoading(false);
|
|
218
395
|
}
|
|
219
396
|
}
|
|
@@ -240,6 +417,7 @@ function CheckoutButton({
|
|
|
240
417
|
children: loading ? "Loading..." : label
|
|
241
418
|
}
|
|
242
419
|
),
|
|
420
|
+
processing && /* @__PURE__ */ jsx("span", { role: "status", children: "Payment is processing. Confirmation may take a little while." }),
|
|
243
421
|
error && /* @__PURE__ */ jsx("span", { role: "alert", children: error.message })
|
|
244
422
|
] });
|
|
245
423
|
}
|
|
@@ -512,6 +690,7 @@ function PricingTable({
|
|
|
512
690
|
const [currentPlan, setCurrentPlan] = useState(currentPlanCode ?? null);
|
|
513
691
|
const [isAnnual, setIsAnnual] = useState(false);
|
|
514
692
|
const [loading, setLoading] = useState(!propPlans);
|
|
693
|
+
const [processing, setProcessing] = useState(false);
|
|
515
694
|
const [checkoutError, setCheckoutError] = useState(null);
|
|
516
695
|
useEffect(() => {
|
|
517
696
|
if (propPlans) {
|
|
@@ -554,7 +733,14 @@ function PricingTable({
|
|
|
554
733
|
returnUrl: returnUrl ?? window.location.href
|
|
555
734
|
});
|
|
556
735
|
onCheckoutResult?.(result);
|
|
557
|
-
await handleCheckoutResult(result, {
|
|
736
|
+
await handleCheckoutResult(result, {
|
|
737
|
+
onStripeClientSecret,
|
|
738
|
+
verifyCheckout: billing?.verifyCheckout,
|
|
739
|
+
getCheckoutStatus: billing?.getCheckoutStatus,
|
|
740
|
+
onProcessing: () => setProcessing(true),
|
|
741
|
+
onSuccess: () => setProcessing(false),
|
|
742
|
+
onComplete: () => setProcessing(false)
|
|
743
|
+
});
|
|
558
744
|
} catch (cause) {
|
|
559
745
|
const error = cause instanceof Error ? cause : new Error("Checkout failed");
|
|
560
746
|
setCheckoutError(error.message);
|
|
@@ -570,6 +756,7 @@ function PricingTable({
|
|
|
570
756
|
background: C.bg
|
|
571
757
|
}, children: [
|
|
572
758
|
showToggle && hasAnnual && /* @__PURE__ */ jsx(Toggle, { isAnnual, onChange: setIsAnnual }),
|
|
759
|
+
processing && /* @__PURE__ */ jsx("p", { role: "status", children: "Payment is processing. Confirmation may take a little while." }),
|
|
573
760
|
checkoutError && /* @__PURE__ */ jsx("p", { role: "alert", children: checkoutError }),
|
|
574
761
|
/* @__PURE__ */ jsx("div", { style: {
|
|
575
762
|
display: "grid",
|
|
@@ -923,7 +1110,16 @@ function CheckoutInner({
|
|
|
923
1110
|
}
|
|
924
1111
|
}
|
|
925
1112
|
),
|
|
926
|
-
error !== null && /* @__PURE__ */ jsx(
|
|
1113
|
+
error !== null && /* @__PURE__ */ jsx(
|
|
1114
|
+
"p",
|
|
1115
|
+
{
|
|
1116
|
+
style: {
|
|
1117
|
+
color: "var(--nozle-destructive, #dc2626)",
|
|
1118
|
+
margin: "0.5rem 0 0"
|
|
1119
|
+
},
|
|
1120
|
+
children: error.message
|
|
1121
|
+
}
|
|
1122
|
+
),
|
|
927
1123
|
children ?? /* @__PURE__ */ jsx(
|
|
928
1124
|
"button",
|
|
929
1125
|
{
|
|
@@ -948,7 +1144,7 @@ function CheckoutInner({
|
|
|
948
1144
|
)
|
|
949
1145
|
] }) });
|
|
950
1146
|
}
|
|
951
|
-
function
|
|
1147
|
+
function StripeCheckout({
|
|
952
1148
|
clientSecret,
|
|
953
1149
|
publishableKey,
|
|
954
1150
|
stripeAccount,
|
|
@@ -972,7 +1168,14 @@ function Checkout({
|
|
|
972
1168
|
[clientSecret, onComplete]
|
|
973
1169
|
);
|
|
974
1170
|
if (clientSecret.startsWith("cs_")) {
|
|
975
|
-
return /* @__PURE__ */ jsx("div", { className, style, children: /* @__PURE__ */ jsx(
|
|
1171
|
+
return /* @__PURE__ */ jsx("div", { className, style, children: /* @__PURE__ */ jsx(
|
|
1172
|
+
EmbeddedCheckoutProvider,
|
|
1173
|
+
{
|
|
1174
|
+
stripe: stripePromise,
|
|
1175
|
+
options: embeddedOptions,
|
|
1176
|
+
children: /* @__PURE__ */ jsx(EmbeddedCheckout, {})
|
|
1177
|
+
}
|
|
1178
|
+
) });
|
|
976
1179
|
}
|
|
977
1180
|
const options = { clientSecret, appearance };
|
|
978
1181
|
return /* @__PURE__ */ jsx(Elements, { stripe: stripePromise, options, children: /* @__PURE__ */ jsx(
|
|
@@ -989,6 +1192,65 @@ function Checkout({
|
|
|
989
1192
|
}
|
|
990
1193
|
) }, clientSecret);
|
|
991
1194
|
}
|
|
1195
|
+
function ProviderCheckout(props) {
|
|
1196
|
+
const billing = useOptionalBillingContext();
|
|
1197
|
+
const [busy, setBusy] = useState(false);
|
|
1198
|
+
const [error, setError] = useState(null);
|
|
1199
|
+
const [processing, setProcessing] = useState(false);
|
|
1200
|
+
const pay = async () => {
|
|
1201
|
+
if (busy) return;
|
|
1202
|
+
setBusy(true);
|
|
1203
|
+
setError(null);
|
|
1204
|
+
try {
|
|
1205
|
+
await handleCheckoutResult(props.checkout, {
|
|
1206
|
+
verifyCheckout: billing?.verifyCheckout,
|
|
1207
|
+
getCheckoutStatus: billing?.getCheckoutStatus,
|
|
1208
|
+
onSuccess: (id) => {
|
|
1209
|
+
setProcessing(false);
|
|
1210
|
+
props.onSuccess?.(id);
|
|
1211
|
+
props.onComplete?.();
|
|
1212
|
+
},
|
|
1213
|
+
onComplete: () => {
|
|
1214
|
+
setProcessing(false);
|
|
1215
|
+
props.onComplete?.();
|
|
1216
|
+
},
|
|
1217
|
+
onProcessing: (status) => {
|
|
1218
|
+
setProcessing(true);
|
|
1219
|
+
props.onProcessing?.(status);
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
} catch (cause) {
|
|
1223
|
+
const failure = cause instanceof Error ? cause : new Error("Checkout failed");
|
|
1224
|
+
setError(failure);
|
|
1225
|
+
props.onError?.(failure);
|
|
1226
|
+
} finally {
|
|
1227
|
+
setBusy(false);
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
return /* @__PURE__ */ jsx(
|
|
1231
|
+
CheckoutContext.Provider,
|
|
1232
|
+
{
|
|
1233
|
+
value: { confirmPayment: pay, isProcessing: busy, error },
|
|
1234
|
+
children: /* @__PURE__ */ jsxs("div", { className: props.className, children: [
|
|
1235
|
+
/* @__PURE__ */ jsx(
|
|
1236
|
+
"button",
|
|
1237
|
+
{
|
|
1238
|
+
type: "button",
|
|
1239
|
+
disabled: busy,
|
|
1240
|
+
"aria-busy": busy,
|
|
1241
|
+
onClick: () => void pay(),
|
|
1242
|
+
children: busy ? "Processing\u2026" : props.submitLabel || "Pay now"
|
|
1243
|
+
}
|
|
1244
|
+
),
|
|
1245
|
+
processing && /* @__PURE__ */ jsx("p", { role: "status", children: "Payment is processing. Confirmation may take a little while." }),
|
|
1246
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", children: error.message })
|
|
1247
|
+
] })
|
|
1248
|
+
}
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
function Checkout(props) {
|
|
1252
|
+
return "checkout" in props ? /* @__PURE__ */ jsx(ProviderCheckout, { ...props }) : /* @__PURE__ */ jsx(StripeCheckout, { ...props });
|
|
1253
|
+
}
|
|
992
1254
|
function UpgradeModal({
|
|
993
1255
|
isOpen,
|
|
994
1256
|
planCode,
|
|
@@ -1002,7 +1264,8 @@ function UpgradeModal({
|
|
|
1002
1264
|
onCancel,
|
|
1003
1265
|
onError
|
|
1004
1266
|
}) {
|
|
1005
|
-
const { createCheckout } = useBillingContext();
|
|
1267
|
+
const { createCheckout, verifyCheckout, getCheckoutStatus } = useBillingContext();
|
|
1268
|
+
const [processing, setProcessing] = useState(false);
|
|
1006
1269
|
const [error, setError] = useState(null);
|
|
1007
1270
|
const [confirming, setConfirming] = useState(false);
|
|
1008
1271
|
async function handleConfirm() {
|
|
@@ -1017,11 +1280,21 @@ function UpgradeModal({
|
|
|
1017
1280
|
returnUrl: returnUrl ?? window.location.href
|
|
1018
1281
|
});
|
|
1019
1282
|
await handleCheckoutResult(result, {
|
|
1283
|
+
verifyCheckout,
|
|
1284
|
+
getCheckoutStatus,
|
|
1285
|
+
onSuccess: () => {
|
|
1286
|
+
setProcessing(false);
|
|
1287
|
+
onCompleted?.();
|
|
1288
|
+
},
|
|
1289
|
+
onProcessing: () => setProcessing(true),
|
|
1020
1290
|
onStripeClientSecret: (clientSecret) => {
|
|
1021
1291
|
onStripeClientSecret?.(clientSecret);
|
|
1022
1292
|
onCheckoutStarted?.();
|
|
1023
1293
|
},
|
|
1024
|
-
onComplete: () =>
|
|
1294
|
+
onComplete: () => {
|
|
1295
|
+
setProcessing(false);
|
|
1296
|
+
onCompleted?.();
|
|
1297
|
+
},
|
|
1025
1298
|
onScheduled: () => onScheduled?.()
|
|
1026
1299
|
});
|
|
1027
1300
|
onConfirm?.();
|
|
@@ -1064,6 +1337,7 @@ function UpgradeModal({
|
|
|
1064
1337
|
},
|
|
1065
1338
|
children: [
|
|
1066
1339
|
/* @__PURE__ */ jsx("h2", { style: { fontSize: "1.25rem", fontWeight: 600, margin: "0 0 1rem" }, children: "Confirm plan change" }),
|
|
1340
|
+
processing && /* @__PURE__ */ jsx("p", { role: "status", children: "Payment is processing. Confirmation may take a little while." }),
|
|
1067
1341
|
error && /* @__PURE__ */ jsx("p", { role: "alert", style: { color: "oklch(0.6 0.2 25)" }, children: error }),
|
|
1068
1342
|
preview && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "1.5rem" }, children: [
|
|
1069
1343
|
/* @__PURE__ */ jsxs(
|