@solvapay/react 1.0.0-preview.18 → 1.0.0-preview.19

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 CHANGED
@@ -56,8 +56,7 @@ function getActiveSubscriptions(subscriptions) {
56
56
  function getCancelledSubscriptionsWithEndDate(subscriptions) {
57
57
  const now = /* @__PURE__ */ new Date();
58
58
  return subscriptions.filter((sub) => {
59
- const subAny = sub;
60
- return sub.status === "active" && subAny.cancelledAt && subAny.endDate && new Date(subAny.endDate) > now;
59
+ return sub.status === "active" && sub.cancelledAt && sub.endDate && new Date(sub.endDate) > now;
61
60
  });
62
61
  }
63
62
  function getMostRecentSubscription(subscriptions) {
@@ -177,7 +176,9 @@ var SolvaPayProvider = ({
177
176
  const createPaymentRef = (0, import_react.useRef)(null);
178
177
  const processPaymentRef = (0, import_react.useRef)(null);
179
178
  const configRef = (0, import_react.useRef)(config);
180
- const buildDefaultCheckSubscriptionRef = (0, import_react.useRef)(null);
179
+ const buildDefaultCheckSubscriptionRef = (0, import_react.useRef)(
180
+ null
181
+ );
181
182
  (0, import_react.useEffect)(() => {
182
183
  configRef.current = config;
183
184
  }, [config]);
@@ -225,77 +226,83 @@ var SolvaPayProvider = ({
225
226
  (0, import_react.useEffect)(() => {
226
227
  buildDefaultCheckSubscriptionRef.current = buildDefaultCheckSubscription;
227
228
  }, [buildDefaultCheckSubscription]);
228
- const buildDefaultCreatePayment = (0, import_react.useCallback)(async (params) => {
229
- const currentConfig = configRef.current;
230
- const adapter = getAuthAdapter(currentConfig);
231
- const token = await adapter.getToken();
232
- const detectedUserId = await adapter.getUserId();
233
- const route = currentConfig?.api?.createPayment || "/api/create-payment-intent";
234
- const fetchFn = currentConfig?.fetch || fetch;
235
- const cachedRef = getCachedCustomerRef(detectedUserId);
236
- const headers = {
237
- "Content-Type": "application/json"
238
- };
239
- if (token) {
240
- headers["Authorization"] = `Bearer ${token}`;
241
- }
242
- if (cachedRef) {
243
- headers["x-solvapay-customer-ref"] = cachedRef;
244
- }
245
- if (currentConfig?.headers) {
246
- const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
247
- Object.assign(headers, customHeaders);
248
- }
249
- const body = { planRef: params.planRef };
250
- if (params.agentRef) {
251
- body.agentRef = params.agentRef;
252
- }
253
- const res = await fetchFn(route, {
254
- method: "POST",
255
- headers,
256
- body: JSON.stringify(body)
257
- });
258
- if (!res.ok) {
259
- const error = new Error(`Failed to create payment: ${res.statusText}`);
260
- currentConfig?.onError?.(error, "createPayment");
261
- throw error;
262
- }
263
- return res.json();
264
- }, []);
265
- const buildDefaultProcessPayment = (0, import_react.useCallback)(async (params) => {
266
- const currentConfig = configRef.current;
267
- const adapter = getAuthAdapter(currentConfig);
268
- const token = await adapter.getToken();
269
- const detectedUserId = await adapter.getUserId();
270
- const route = currentConfig?.api?.processPayment || "/api/process-payment";
271
- const fetchFn = currentConfig?.fetch || fetch;
272
- const cachedRef = getCachedCustomerRef(detectedUserId);
273
- const headers = {
274
- "Content-Type": "application/json"
275
- };
276
- if (token) {
277
- headers["Authorization"] = `Bearer ${token}`;
278
- }
279
- if (cachedRef) {
280
- headers["x-solvapay-customer-ref"] = cachedRef;
281
- }
282
- if (currentConfig?.headers) {
283
- const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
284
- Object.assign(headers, customHeaders);
285
- }
286
- const res = await fetchFn(route, {
287
- method: "POST",
288
- headers,
289
- body: JSON.stringify(params)
290
- });
291
- if (!res.ok) {
292
- const error = new Error(`Failed to process payment: ${res.statusText}`);
293
- currentConfig?.onError?.(error, "processPayment");
294
- throw error;
295
- }
296
- return res.json();
297
- }, []);
298
- const checkSubscription = (0, import_react.useCallback)(async () => {
229
+ const buildDefaultCreatePayment = (0, import_react.useCallback)(
230
+ async (params) => {
231
+ const currentConfig = configRef.current;
232
+ const adapter = getAuthAdapter(currentConfig);
233
+ const token = await adapter.getToken();
234
+ const detectedUserId = await adapter.getUserId();
235
+ const route = currentConfig?.api?.createPayment || "/api/create-payment-intent";
236
+ const fetchFn = currentConfig?.fetch || fetch;
237
+ const cachedRef = getCachedCustomerRef(detectedUserId);
238
+ const headers = {
239
+ "Content-Type": "application/json"
240
+ };
241
+ if (token) {
242
+ headers["Authorization"] = `Bearer ${token}`;
243
+ }
244
+ if (cachedRef) {
245
+ headers["x-solvapay-customer-ref"] = cachedRef;
246
+ }
247
+ if (currentConfig?.headers) {
248
+ const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
249
+ Object.assign(headers, customHeaders);
250
+ }
251
+ const body = { planRef: params.planRef };
252
+ if (params.agentRef) {
253
+ body.agentRef = params.agentRef;
254
+ }
255
+ const res = await fetchFn(route, {
256
+ method: "POST",
257
+ headers,
258
+ body: JSON.stringify(body)
259
+ });
260
+ if (!res.ok) {
261
+ const error = new Error(`Failed to create payment: ${res.statusText}`);
262
+ currentConfig?.onError?.(error, "createPayment");
263
+ throw error;
264
+ }
265
+ return res.json();
266
+ },
267
+ []
268
+ );
269
+ const buildDefaultProcessPayment = (0, import_react.useCallback)(
270
+ async (params) => {
271
+ const currentConfig = configRef.current;
272
+ const adapter = getAuthAdapter(currentConfig);
273
+ const token = await adapter.getToken();
274
+ const detectedUserId = await adapter.getUserId();
275
+ const route = currentConfig?.api?.processPayment || "/api/process-payment";
276
+ const fetchFn = currentConfig?.fetch || fetch;
277
+ const cachedRef = getCachedCustomerRef(detectedUserId);
278
+ const headers = {
279
+ "Content-Type": "application/json"
280
+ };
281
+ if (token) {
282
+ headers["Authorization"] = `Bearer ${token}`;
283
+ }
284
+ if (cachedRef) {
285
+ headers["x-solvapay-customer-ref"] = cachedRef;
286
+ }
287
+ if (currentConfig?.headers) {
288
+ const customHeaders = typeof currentConfig.headers === "function" ? await currentConfig.headers() : currentConfig.headers;
289
+ Object.assign(headers, customHeaders);
290
+ }
291
+ const res = await fetchFn(route, {
292
+ method: "POST",
293
+ headers,
294
+ body: JSON.stringify(params)
295
+ });
296
+ if (!res.ok) {
297
+ const error = new Error(`Failed to process payment: ${res.statusText}`);
298
+ currentConfig?.onError?.(error, "processPayment");
299
+ throw error;
300
+ }
301
+ return res.json();
302
+ },
303
+ []
304
+ );
305
+ const _checkSubscription = (0, import_react.useCallback)(async () => {
299
306
  if (checkSubscriptionRef.current) {
300
307
  return checkSubscriptionRef.current();
301
308
  }
@@ -303,19 +310,25 @@ var SolvaPayProvider = ({
303
310
  return buildDefaultCheckSubscriptionRef.current();
304
311
  }
305
312
  return buildDefaultCheckSubscription();
306
- }, []);
307
- const createPayment = (0, import_react.useCallback)(async (params) => {
308
- if (createPaymentRef.current) {
309
- return createPaymentRef.current(params);
310
- }
311
- return buildDefaultCreatePayment(params);
312
- }, [buildDefaultCreatePayment]);
313
- const processPayment = (0, import_react.useCallback)(async (params) => {
314
- if (processPaymentRef.current) {
315
- return processPaymentRef.current(params);
316
- }
317
- return buildDefaultProcessPayment(params);
318
- }, [buildDefaultProcessPayment]);
313
+ }, [buildDefaultCheckSubscription]);
314
+ const createPayment = (0, import_react.useCallback)(
315
+ async (params) => {
316
+ if (createPaymentRef.current) {
317
+ return createPaymentRef.current(params);
318
+ }
319
+ return buildDefaultCreatePayment(params);
320
+ },
321
+ [buildDefaultCreatePayment]
322
+ );
323
+ const processPayment = (0, import_react.useCallback)(
324
+ async (params) => {
325
+ if (processPaymentRef.current) {
326
+ return processPaymentRef.current(params);
327
+ }
328
+ return buildDefaultProcessPayment(params);
329
+ },
330
+ [buildDefaultProcessPayment]
331
+ );
319
332
  (0, import_react.useEffect)(() => {
320
333
  const detectAuth = async () => {
321
334
  const currentConfig = configRef.current;
@@ -344,58 +357,61 @@ var SolvaPayProvider = ({
344
357
  const interval = setInterval(detectAuth, 5e3);
345
358
  return () => clearInterval(interval);
346
359
  }, [userId]);
347
- const fetchSubscription = (0, import_react.useCallback)(async (force = false) => {
348
- if (!isAuthenticated && !internalCustomerRef) {
349
- setSubscriptionData({ subscriptions: [] });
350
- setLoading(false);
351
- inFlightRef.current = null;
352
- lastFetchedRef.current = null;
353
- return;
354
- }
355
- const cacheKey = internalCustomerRef || userId || "anonymous";
356
- if (!force && lastFetchedRef.current === cacheKey && inFlightRef.current !== cacheKey) {
357
- return;
358
- }
359
- if (inFlightRef.current === cacheKey) {
360
- return;
361
- }
362
- inFlightRef.current = cacheKey;
363
- setLoading(true);
364
- try {
365
- const checkFn = checkSubscriptionRef.current || buildDefaultCheckSubscriptionRef.current;
366
- if (!checkFn) {
367
- throw new Error("checkSubscription function not available");
368
- }
369
- const data = await checkFn();
370
- if (data.customerRef) {
371
- setInternalCustomerRef(data.customerRef);
372
- const currentAdapter = getAuthAdapter(configRef.current);
373
- const currentUserId = await currentAdapter.getUserId();
374
- setCachedCustomerRef(data.customerRef, currentUserId);
360
+ const fetchSubscription = (0, import_react.useCallback)(
361
+ async (force = false) => {
362
+ if (!isAuthenticated && !internalCustomerRef) {
363
+ setSubscriptionData({ subscriptions: [] });
364
+ setLoading(false);
365
+ inFlightRef.current = null;
366
+ lastFetchedRef.current = null;
367
+ return;
375
368
  }
376
- if (inFlightRef.current === cacheKey) {
377
- const filteredData = {
378
- ...data,
379
- subscriptions: filterSubscriptions(data.subscriptions || [])
380
- };
381
- setSubscriptionData(filteredData);
382
- lastFetchedRef.current = cacheKey;
369
+ const cacheKey = internalCustomerRef || userId || "anonymous";
370
+ if (!force && lastFetchedRef.current === cacheKey && inFlightRef.current !== cacheKey) {
371
+ return;
383
372
  }
384
- } catch (error) {
385
- console.error("[SolvaPayProvider] Failed to fetch subscription:", error);
386
373
  if (inFlightRef.current === cacheKey) {
387
- setSubscriptionData({
388
- subscriptions: []
389
- });
390
- lastFetchedRef.current = cacheKey;
374
+ return;
391
375
  }
392
- } finally {
393
- if (inFlightRef.current === cacheKey) {
394
- setLoading(false);
395
- inFlightRef.current = null;
376
+ inFlightRef.current = cacheKey;
377
+ setLoading(true);
378
+ try {
379
+ const checkFn = checkSubscriptionRef.current || buildDefaultCheckSubscriptionRef.current;
380
+ if (!checkFn) {
381
+ throw new Error("checkSubscription function not available");
382
+ }
383
+ const data = await checkFn();
384
+ if (data.customerRef) {
385
+ setInternalCustomerRef(data.customerRef);
386
+ const currentAdapter = getAuthAdapter(configRef.current);
387
+ const currentUserId = await currentAdapter.getUserId();
388
+ setCachedCustomerRef(data.customerRef, currentUserId);
389
+ }
390
+ if (inFlightRef.current === cacheKey) {
391
+ const filteredData = {
392
+ ...data,
393
+ subscriptions: filterSubscriptions(data.subscriptions || [])
394
+ };
395
+ setSubscriptionData(filteredData);
396
+ lastFetchedRef.current = cacheKey;
397
+ }
398
+ } catch (error) {
399
+ console.error("[SolvaPayProvider] Failed to fetch subscription:", error);
400
+ if (inFlightRef.current === cacheKey) {
401
+ setSubscriptionData({
402
+ subscriptions: []
403
+ });
404
+ lastFetchedRef.current = cacheKey;
405
+ }
406
+ } finally {
407
+ if (inFlightRef.current === cacheKey) {
408
+ setLoading(false);
409
+ inFlightRef.current = null;
410
+ }
396
411
  }
397
- }
398
- }, [isAuthenticated, internalCustomerRef, userId]);
412
+ },
413
+ [isAuthenticated, internalCustomerRef, userId]
414
+ );
399
415
  const fetchSubscriptionRef = (0, import_react.useRef)(fetchSubscription);
400
416
  (0, import_react.useEffect)(() => {
401
417
  fetchSubscriptionRef.current = fetchSubscription;
@@ -416,17 +432,22 @@ var SolvaPayProvider = ({
416
432
  setLoading(false);
417
433
  }
418
434
  }, [isAuthenticated, internalCustomerRef, userId]);
419
- const updateCustomerRef = (0, import_react.useCallback)((newCustomerRef) => {
420
- setInternalCustomerRef(newCustomerRef);
421
- setCachedCustomerRef(newCustomerRef, userId);
422
- fetchSubscription(true);
423
- }, [fetchSubscription, userId]);
435
+ const updateCustomerRef = (0, import_react.useCallback)(
436
+ (newCustomerRef) => {
437
+ setInternalCustomerRef(newCustomerRef);
438
+ setCachedCustomerRef(newCustomerRef, userId);
439
+ fetchSubscription(true);
440
+ },
441
+ [fetchSubscription, userId]
442
+ );
424
443
  const subscription = (0, import_react.useMemo)(() => {
425
444
  const activeSubscription = getPrimarySubscription(subscriptionData.subscriptions);
426
445
  const activePaidSubscriptions = subscriptionData.subscriptions.filter(
427
446
  (sub) => sub.status === "active" && isPaidSubscription(sub)
428
447
  );
429
- const activePaidSubscription = activePaidSubscriptions.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())[0] || null;
448
+ const activePaidSubscription = activePaidSubscriptions.sort(
449
+ (a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime()
450
+ )[0] || null;
430
451
  return {
431
452
  loading,
432
453
  customerRef: subscriptionData.customerRef || internalCustomerRef,
@@ -443,14 +464,25 @@ var SolvaPayProvider = ({
443
464
  activePaidSubscription
444
465
  };
445
466
  }, [loading, subscriptionData, internalCustomerRef]);
446
- const contextValue = (0, import_react.useMemo)(() => ({
447
- subscription,
448
- refetchSubscription,
449
- createPayment,
450
- processPayment,
451
- customerRef: subscriptionData.customerRef || internalCustomerRef,
452
- updateCustomerRef
453
- }), [subscription, refetchSubscription, createPayment, processPayment, subscriptionData.customerRef, internalCustomerRef, updateCustomerRef]);
467
+ const contextValue = (0, import_react.useMemo)(
468
+ () => ({
469
+ subscription,
470
+ refetchSubscription,
471
+ createPayment,
472
+ processPayment,
473
+ customerRef: subscriptionData.customerRef || internalCustomerRef,
474
+ updateCustomerRef
475
+ }),
476
+ [
477
+ subscription,
478
+ refetchSubscription,
479
+ createPayment,
480
+ processPayment,
481
+ subscriptionData.customerRef,
482
+ internalCustomerRef,
483
+ updateCustomerRef
484
+ ]
485
+ );
454
486
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SolvaPayContext.Provider, { value: contextValue, children });
455
487
  };
456
488
 
@@ -556,17 +588,6 @@ function useSubscription() {
556
588
  };
557
589
  }
558
590
 
559
- // src/hooks/useCustomer.ts
560
- function useCustomer() {
561
- const { subscription, customerRef } = useSolvaPay();
562
- return {
563
- customerRef: subscription.customerRef || customerRef,
564
- email: subscription.email,
565
- name: subscription.name,
566
- loading: subscription.loading
567
- };
568
- }
569
-
570
591
  // src/components/Spinner.tsx
571
592
  var import_jsx_runtime2 = require("react/jsx-runtime");
572
593
  var Spinner = ({
@@ -588,17 +609,7 @@ var Spinner = ({
588
609
  role: "status",
589
610
  "aria-busy": "true",
590
611
  children: [
591
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
592
- "circle",
593
- {
594
- className: "opacity-25",
595
- cx: "12",
596
- cy: "12",
597
- r: "10",
598
- stroke: "currentColor",
599
- strokeWidth: "4"
600
- }
601
- ),
612
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
602
613
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
603
614
  "path",
604
615
  {
@@ -615,11 +626,24 @@ var Spinner = ({
615
626
  // src/components/StripePaymentFormWrapper.tsx
616
627
  var import_react4 = require("react");
617
628
  var import_react_stripe_js = require("@stripe/react-stripe-js");
629
+
630
+ // src/hooks/useCustomer.ts
631
+ function useCustomer() {
632
+ const { subscription, customerRef } = useSolvaPay();
633
+ return {
634
+ customerRef: subscription.customerRef || customerRef,
635
+ email: subscription.email,
636
+ name: subscription.name,
637
+ loading: subscription.loading
638
+ };
639
+ }
640
+
641
+ // src/components/StripePaymentFormWrapper.tsx
618
642
  var import_jsx_runtime3 = require("react/jsx-runtime");
619
643
  var StripePaymentFormWrapper = ({
620
644
  onSuccess,
621
645
  onError,
622
- returnUrl,
646
+ returnUrl: _returnUrl,
623
647
  submitButtonText = "Pay Now",
624
648
  buttonClassName,
625
649
  clientSecret
@@ -744,16 +768,23 @@ var StripePaymentFormWrapper = ({
744
768
  }
745
769
  }
746
770
  }
747
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { padding: "12px", border: "1px solid #cbd5e1", borderRadius: "0.375rem", backgroundColor: "white", display: "flex", alignItems: "center", justifyContent: "center", minHeight: "40px" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { size: "sm" }) }),
748
- message && !isSuccess && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
771
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
749
772
  "div",
750
773
  {
751
- role: "alert",
752
- "aria-live": "assertive",
753
- "aria-atomic": "true",
754
- children: message
774
+ style: {
775
+ padding: "12px",
776
+ border: "1px solid #cbd5e1",
777
+ borderRadius: "0.375rem",
778
+ backgroundColor: "white",
779
+ display: "flex",
780
+ alignItems: "center",
781
+ justifyContent: "center",
782
+ minHeight: "40px"
783
+ },
784
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { size: "sm" })
755
785
  }
756
786
  ),
787
+ message && !isSuccess && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: message }),
757
788
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
758
789
  "button",
759
790
  {
@@ -785,106 +816,118 @@ var PaymentForm = ({
785
816
  buttonClassName
786
817
  }) => {
787
818
  const validPlanRef = planRef && typeof planRef === "string" ? planRef : "";
788
- const checkout = useCheckout(validPlanRef, agentRef);
819
+ const {
820
+ loading: checkoutLoading,
821
+ error: checkoutError,
822
+ clientSecret,
823
+ startCheckout,
824
+ stripePromise
825
+ } = useCheckout(validPlanRef, agentRef);
789
826
  const { refetch } = useSubscription();
790
- const { processPayment, customerRef } = useSolvaPay();
791
- const customer = useCustomer();
827
+ const { processPayment } = useSolvaPay();
792
828
  const hasInitializedRef = (0, import_react5.useRef)(false);
793
829
  (0, import_react5.useEffect)(() => {
794
- if (!hasInitializedRef.current && validPlanRef && !checkout.loading && !checkout.error && !checkout.clientSecret) {
830
+ if (!hasInitializedRef.current && validPlanRef && !checkoutLoading && !checkoutError && !clientSecret) {
795
831
  hasInitializedRef.current = true;
796
- checkout.startCheckout().catch(() => {
832
+ startCheckout().catch(() => {
797
833
  hasInitializedRef.current = false;
798
834
  });
799
835
  }
800
- if (validPlanRef && checkout.clientSecret) {
836
+ if (validPlanRef && clientSecret) {
801
837
  hasInitializedRef.current = true;
802
838
  }
803
- }, [validPlanRef, checkout.loading, checkout.error, checkout.clientSecret, checkout.startCheckout]);
804
- const handleSuccess = (0, import_react5.useCallback)(async (paymentIntent) => {
805
- let processingTimeout = false;
806
- let processingResult = null;
807
- if (processPayment && agentRef) {
808
- try {
809
- const result = await processPayment({
810
- paymentIntentId: paymentIntent.id,
811
- agentRef,
812
- planRef
813
- });
814
- processingResult = result;
815
- const isTimeout = result?.status === "timeout";
816
- processingTimeout = isTimeout;
817
- if (isTimeout) {
818
- for (let attempt = 1; attempt <= 5; attempt++) {
819
- const delay = attempt * 1e3;
820
- await new Promise((resolve) => setTimeout(resolve, delay));
839
+ }, [validPlanRef, checkoutLoading, checkoutError, clientSecret, startCheckout]);
840
+ const handleSuccess = (0, import_react5.useCallback)(
841
+ async (paymentIntent) => {
842
+ let processingTimeout = false;
843
+ let processingResult = null;
844
+ const paymentIntentAny = paymentIntent;
845
+ if (processPayment && agentRef) {
846
+ try {
847
+ const result = await processPayment({
848
+ paymentIntentId: paymentIntentAny.id,
849
+ agentRef,
850
+ planRef
851
+ });
852
+ processingResult = result;
853
+ const isTimeout = result?.status === "timeout";
854
+ processingTimeout = isTimeout;
855
+ if (isTimeout) {
856
+ for (let attempt = 1; attempt <= 5; attempt++) {
857
+ const delay = attempt * 1e3;
858
+ await new Promise((resolve) => setTimeout(resolve, delay));
859
+ await refetch();
860
+ }
861
+ if (onSuccess) {
862
+ await onSuccess({
863
+ ...paymentIntentAny,
864
+ _processingTimeout: processingTimeout,
865
+ _processingResult: processingResult
866
+ });
867
+ }
868
+ throw new Error("Payment processing timed out");
869
+ } else {
821
870
  await refetch();
822
871
  }
872
+ } catch (error) {
873
+ console.error("[PaymentForm] Failed to process payment:", error);
823
874
  if (onSuccess) {
824
- await onSuccess({
825
- ...paymentIntent,
826
- _processingTimeout: processingTimeout,
827
- _processingResult: processingResult
828
- });
829
- }
830
- throw new Error("Payment processing timed out");
831
- } else {
832
- await refetch();
833
- }
834
- } catch (error) {
835
- console.error("[PaymentForm] Failed to process payment:", error);
836
- if (onSuccess) {
837
- try {
838
- await onSuccess({
839
- ...paymentIntent,
840
- _processingError: error
841
- });
842
- } catch (callbackError) {
875
+ try {
876
+ await onSuccess({
877
+ ...paymentIntentAny,
878
+ _processingError: error
879
+ });
880
+ } catch {
881
+ }
843
882
  }
883
+ throw error;
844
884
  }
845
- throw error;
885
+ } else {
886
+ await refetch();
846
887
  }
847
- } else {
848
- await refetch();
849
- }
850
- if (onSuccess && !processingTimeout) {
851
- await onSuccess({
852
- ...paymentIntent,
853
- _processingTimeout: processingTimeout,
854
- _processingResult: processingResult
855
- });
856
- }
857
- }, [processPayment, agentRef, planRef, refetch, onSuccess]);
858
- const handleError = (0, import_react5.useCallback)((err) => {
859
- if (onError) {
860
- onError(err);
861
- }
862
- }, [onError]);
888
+ if (onSuccess && !processingTimeout) {
889
+ await onSuccess({
890
+ ...paymentIntentAny,
891
+ _processingTimeout: processingTimeout,
892
+ _processingResult: processingResult
893
+ });
894
+ }
895
+ },
896
+ [processPayment, agentRef, planRef, refetch, onSuccess]
897
+ );
898
+ const handleError = (0, import_react5.useCallback)(
899
+ (err) => {
900
+ if (onError) {
901
+ onError(err);
902
+ }
903
+ },
904
+ [onError]
905
+ );
863
906
  const finalReturnUrl = returnUrl || (typeof window !== "undefined" ? window.location.href : "/");
864
907
  const isValidPlanRef = planRef && typeof planRef === "string";
865
- const hasError = !!checkout.error;
866
- const hasStripeData = !!(checkout.stripePromise && checkout.clientSecret);
908
+ const hasError = !!checkoutError;
909
+ const hasStripeData = !!(stripePromise && clientSecret);
867
910
  const elementsOptions = (0, import_react5.useMemo)(() => {
868
- if (!checkout.clientSecret) return void 0;
869
- return { clientSecret: checkout.clientSecret };
870
- }, [checkout.clientSecret]);
911
+ if (!clientSecret) return void 0;
912
+ return { clientSecret };
913
+ }, [clientSecret]);
871
914
  const [hasMountedElements, setHasMountedElements] = (0, import_react5.useState)(false);
872
915
  (0, import_react5.useEffect)(() => {
873
916
  if (hasStripeData) {
874
917
  setHasMountedElements(true);
875
918
  }
876
919
  }, [hasStripeData]);
877
- const shouldRenderElements = hasStripeData || hasMountedElements && checkout.stripePromise && checkout.clientSecret;
920
+ const shouldRenderElements = hasStripeData || hasMountedElements && stripePromise && clientSecret;
878
921
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, children: !isValidPlanRef ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "PaymentForm: planRef is required and must be a string" }) : hasError ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
879
922
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "Payment initialization failed" }),
880
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: checkout.error?.message || "Unknown error" })
881
- ] }) : shouldRenderElements && checkout.stripePromise && elementsOptions ? (
923
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: checkoutError?.message || "Unknown error" })
924
+ ] }) : shouldRenderElements && elementsOptions ? (
882
925
  // Once we have Stripe data, always render Elements to maintain hook consistency
883
926
  // This prevents hook count mismatches when transitioning between states
884
927
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
885
928
  import_react_stripe_js2.Elements,
886
929
  {
887
- stripe: checkout.stripePromise,
930
+ stripe: stripePromise,
888
931
  options: elementsOptions,
889
932
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
890
933
  StripePaymentFormWrapper,
@@ -894,16 +937,27 @@ var PaymentForm = ({
894
937
  returnUrl: finalReturnUrl,
895
938
  submitButtonText,
896
939
  buttonClassName,
897
- clientSecret: checkout.clientSecret
940
+ clientSecret
898
941
  }
899
942
  )
900
943
  },
901
- checkout.clientSecret
944
+ clientSecret
902
945
  )
903
946
  ) : (
904
947
  // Loading state before Stripe data is available
905
948
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
906
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { minHeight: "40px", display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: "md" }) }),
949
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
950
+ "div",
951
+ {
952
+ style: {
953
+ minHeight: "40px",
954
+ display: "flex",
955
+ alignItems: "center",
956
+ justifyContent: "center"
957
+ },
958
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Spinner, { size: "md" })
959
+ }
960
+ ),
907
961
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
908
962
  "button",
909
963
  {
@@ -994,10 +1048,7 @@ var PlanBadge = ({
994
1048
 
995
1049
  // src/components/SubscriptionGate.tsx
996
1050
  var import_jsx_runtime6 = require("react/jsx-runtime");
997
- var SubscriptionGate = ({
998
- requirePlan,
999
- children
1000
- }) => {
1051
+ var SubscriptionGate = ({ requirePlan, children }) => {
1001
1052
  const { subscriptions, loading, hasPlan } = useSubscription();
1002
1053
  const hasAccess = requirePlan ? hasPlan(requirePlan) : subscriptions.some((sub) => sub.status === "active");
1003
1054
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: children({
@@ -1036,99 +1087,99 @@ function usePlans(options) {
1036
1087
  (0, import_react7.useEffect)(() => {
1037
1088
  autoSelectFirstPaidRef.current = autoSelectFirstPaid;
1038
1089
  }, [autoSelectFirstPaid]);
1039
- const fetchPlans = (0, import_react7.useCallback)(async (force = false) => {
1040
- if (!agentRef) {
1041
- setError(new Error("Agent reference not configured"));
1042
- setLoading(false);
1043
- return;
1044
- }
1045
- const cached = plansCache.get(agentRef);
1046
- const now = Date.now();
1047
- if (!force && cached && now - cached.timestamp < CACHE_DURATION2) {
1048
- const cachedPlans = cached.plans;
1049
- let processedPlans = filterRef.current ? cachedPlans.filter(filterRef.current) : cachedPlans;
1050
- if (sortByRef.current) {
1051
- processedPlans = [...processedPlans].sort(sortByRef.current);
1090
+ const fetchPlans = (0, import_react7.useCallback)(
1091
+ async (force = false) => {
1092
+ if (!agentRef) {
1093
+ setError(new Error("Agent reference not configured"));
1094
+ setLoading(false);
1095
+ return;
1052
1096
  }
1053
- setPlans(processedPlans);
1054
- setLoading(false);
1055
- setError(null);
1056
- if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1057
- const firstPaidIndex = processedPlans.findIndex(
1058
- (plan) => plan.price && plan.price > 0
1059
- );
1060
- setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1097
+ const cached = plansCache.get(agentRef);
1098
+ const now = Date.now();
1099
+ if (!force && cached && now - cached.timestamp < CACHE_DURATION2) {
1100
+ const cachedPlans = cached.plans;
1101
+ let processedPlans = filterRef.current ? cachedPlans.filter(filterRef.current) : cachedPlans;
1102
+ if (sortByRef.current) {
1103
+ processedPlans = [...processedPlans].sort(sortByRef.current);
1104
+ }
1105
+ setPlans(processedPlans);
1106
+ setLoading(false);
1107
+ setError(null);
1108
+ if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1109
+ const firstPaidIndex = processedPlans.findIndex((plan) => plan.price && plan.price > 0);
1110
+ setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1111
+ }
1112
+ return;
1113
+ }
1114
+ if (cached?.promise) {
1115
+ try {
1116
+ setLoading(true);
1117
+ const fetchedPlans = await cached.promise;
1118
+ let processedPlans = filterRef.current ? fetchedPlans.filter(filterRef.current) : fetchedPlans;
1119
+ if (sortByRef.current) {
1120
+ processedPlans = [...processedPlans].sort(sortByRef.current);
1121
+ }
1122
+ setPlans(processedPlans);
1123
+ setError(null);
1124
+ if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1125
+ const firstPaidIndex = processedPlans.findIndex((plan) => plan.price && plan.price > 0);
1126
+ setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1127
+ }
1128
+ } catch (err) {
1129
+ setError(err instanceof Error ? err : new Error("Failed to load plans"));
1130
+ } finally {
1131
+ setLoading(false);
1132
+ }
1133
+ return;
1061
1134
  }
1062
- return;
1063
- }
1064
- if (cached?.promise) {
1065
1135
  try {
1066
1136
  setLoading(true);
1067
- const fetchedPlans = await cached.promise;
1137
+ setError(null);
1138
+ const fetchPromise = fetcherRef.current(agentRef);
1139
+ plansCache.set(agentRef, {
1140
+ plans: [],
1141
+ timestamp: now,
1142
+ promise: fetchPromise
1143
+ });
1144
+ const fetchedPlans = await fetchPromise;
1145
+ plansCache.set(agentRef, {
1146
+ plans: fetchedPlans,
1147
+ timestamp: now,
1148
+ promise: null
1149
+ });
1068
1150
  let processedPlans = filterRef.current ? fetchedPlans.filter(filterRef.current) : fetchedPlans;
1069
1151
  if (sortByRef.current) {
1070
1152
  processedPlans = [...processedPlans].sort(sortByRef.current);
1071
1153
  }
1072
1154
  setPlans(processedPlans);
1073
- setError(null);
1074
1155
  if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1075
- const firstPaidIndex = processedPlans.findIndex(
1076
- (plan) => plan.price && plan.price > 0
1077
- );
1156
+ const firstPaidIndex = processedPlans.findIndex((plan) => plan.price && plan.price > 0);
1078
1157
  setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1079
1158
  }
1080
1159
  } catch (err) {
1160
+ plansCache.delete(agentRef);
1081
1161
  setError(err instanceof Error ? err : new Error("Failed to load plans"));
1082
1162
  } finally {
1083
1163
  setLoading(false);
1084
1164
  }
1085
- return;
1086
- }
1087
- try {
1088
- setLoading(true);
1089
- setError(null);
1090
- const fetchPromise = fetcherRef.current(agentRef);
1091
- plansCache.set(agentRef, {
1092
- plans: [],
1093
- timestamp: now,
1094
- promise: fetchPromise
1095
- });
1096
- const fetchedPlans = await fetchPromise;
1097
- plansCache.set(agentRef, {
1098
- plans: fetchedPlans,
1099
- timestamp: now,
1100
- promise: null
1101
- });
1102
- let processedPlans = filterRef.current ? fetchedPlans.filter(filterRef.current) : fetchedPlans;
1103
- if (sortByRef.current) {
1104
- processedPlans = [...processedPlans].sort(sortByRef.current);
1105
- }
1106
- setPlans(processedPlans);
1107
- if (autoSelectFirstPaidRef.current && processedPlans.length > 0) {
1108
- const firstPaidIndex = processedPlans.findIndex(
1109
- (plan) => plan.price && plan.price > 0
1110
- );
1111
- setSelectedPlanIndex(firstPaidIndex >= 0 ? firstPaidIndex : 0);
1112
- }
1113
- } catch (err) {
1114
- plansCache.delete(agentRef);
1115
- setError(err instanceof Error ? err : new Error("Failed to load plans"));
1116
- } finally {
1117
- setLoading(false);
1118
- }
1119
- }, [agentRef]);
1165
+ },
1166
+ [agentRef]
1167
+ );
1120
1168
  (0, import_react7.useEffect)(() => {
1121
1169
  fetchPlans();
1122
1170
  }, [fetchPlans]);
1123
1171
  const selectedPlan = (0, import_react7.useMemo)(() => {
1124
1172
  return plans[selectedPlanIndex] || null;
1125
1173
  }, [plans, selectedPlanIndex]);
1126
- const selectPlan = (0, import_react7.useCallback)((planRef) => {
1127
- const index = plans.findIndex((p) => p.reference === planRef);
1128
- if (index >= 0) {
1129
- setSelectedPlanIndex(index);
1130
- }
1131
- }, [plans]);
1174
+ const selectPlan = (0, import_react7.useCallback)(
1175
+ (planRef) => {
1176
+ const index = plans.findIndex((p) => p.reference === planRef);
1177
+ if (index >= 0) {
1178
+ setSelectedPlanIndex(index);
1179
+ }
1180
+ },
1181
+ [plans]
1182
+ );
1132
1183
  return {
1133
1184
  plans,
1134
1185
  loading,
@@ -1161,19 +1212,25 @@ var PlanSelector = ({
1161
1212
  autoSelectFirstPaid
1162
1213
  });
1163
1214
  const { plans } = plansHook;
1164
- const isPaidPlan = (0, import_react8.useCallback)((planName) => {
1165
- const plan = plans.find((p) => p.name === planName);
1166
- return plan ? (plan.price ?? 0) > 0 && !plan.isFreeTier : true;
1167
- }, [plans]);
1215
+ const isPaidPlan = (0, import_react8.useCallback)(
1216
+ (planName) => {
1217
+ const plan = plans.find((p) => p.name === planName);
1218
+ return plan ? (plan.price ?? 0) > 0 && !plan.isFreeTier : true;
1219
+ },
1220
+ [plans]
1221
+ );
1168
1222
  const activeSubscription = (0, import_react8.useMemo)(() => {
1169
1223
  const activeSubs = subscriptions.filter((sub) => sub.status === "active");
1170
1224
  return activeSubs.sort(
1171
1225
  (a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime()
1172
1226
  )[0] || null;
1173
1227
  }, [subscriptions]);
1174
- const isCurrentPlan = (0, import_react8.useCallback)((planName) => {
1175
- return activeSubscription?.planName === planName;
1176
- }, [activeSubscription]);
1228
+ const isCurrentPlan = (0, import_react8.useCallback)(
1229
+ (planName) => {
1230
+ return activeSubscription?.planName === planName;
1231
+ },
1232
+ [activeSubscription]
1233
+ );
1177
1234
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: children({
1178
1235
  ...plansHook,
1179
1236
  subscriptions,
@@ -1191,10 +1248,11 @@ function useSubscriptionStatus() {
1191
1248
  }, []);
1192
1249
  const subscriptionData = (0, import_react9.useMemo)(() => {
1193
1250
  const cancelledPaidSubscriptions = subscriptions.filter((sub) => {
1194
- const subAny = sub;
1195
- return sub.status === "active" && subAny.cancelledAt && isPaidSubscription2(sub);
1251
+ return sub.status === "active" && sub.cancelledAt && isPaidSubscription2(sub);
1196
1252
  });
1197
- const cancelledSubscription = cancelledPaidSubscriptions.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())[0] || null;
1253
+ const cancelledSubscription = cancelledPaidSubscriptions.sort(
1254
+ (a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime()
1255
+ )[0] || null;
1198
1256
  const shouldShowCancelledNotice = !!cancelledSubscription;
1199
1257
  return {
1200
1258
  cancelledSubscription,