@coin-voyage/paykit 2.4.5-beta.3 → 2.4.5-beta.4

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.
@@ -1,6 +1,8 @@
1
+ import type { StripeOnramp } from "@stripe/crypto/types";
2
+ import { type ReactNode } from "react";
1
3
  export default function CardPayment(): import("react/jsx-runtime").JSX.Element;
2
- export declare const CryptoElements: ({ stripeOnramp, children }: {
3
- stripeOnramp: any;
4
- children: any;
4
+ export declare const CryptoElements: ({ stripeOnramp, children, }: {
5
+ stripeOnramp: StripeOnramp | Promise<StripeOnramp | null>;
6
+ children: ReactNode;
5
7
  }) => import("react/jsx-runtime").JSX.Element;
6
- export declare const useStripeOnramp: () => any;
8
+ export declare const useStripeOnrampContext: () => StripeOnramp | null | undefined;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { getFiatPaymentData } from "@coin-voyage/shared/payment";
3
3
  import { PayOrderMode, PayOrderStatus } from "@coin-voyage/shared/types";
4
+ import { loadStripeOnramp } from "@stripe/crypto";
4
5
  import { useQuery } from "@tanstack/react-query";
5
6
  import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
6
7
  import { AlertIcon } from "../../../assets/icons";
@@ -14,11 +15,7 @@ import { OrderHeader } from "../../ui/OrderHeader";
14
15
  import PoweredByFooter from "../../ui/PoweredByFooter";
15
16
  import { Spinner } from "../../ui/Spinner";
16
17
  export default function CardPayment() {
17
- const { triggerResize } = usePayContext();
18
18
  const { data, isLoading, error, refetch } = useCardPaymentData();
19
- useEffect(() => {
20
- triggerResize();
21
- }, [triggerResize, isLoading, data?.session_id, data?.client_secret, error]);
22
19
  return (_jsxs(PageContent, { children: [_jsx(OrderHeader, { minified: true }), _jsx(CardPaymentContent, { paymentData: data, isLoading: isLoading, error: error instanceof Error ? error : null, onRetry: () => {
23
20
  void refetch();
24
21
  } }), _jsx(PoweredByFooter, {})] }));
@@ -66,33 +63,13 @@ function StatusCard({ title, body, actionLabel, onAction, loading = false, warni
66
63
  }
67
64
  function StripeOnrampCheckout({ paymentData }) {
68
65
  const { mode, triggerResize } = usePayContext();
69
- //const { data: stripeOnramp, isLoading, error, refetch } = useStripeOnramp(paymentData.stripe_publishable_key)
66
+ const { data: stripeOnramp, isLoading, error, refetch } = useLoadStripeOnramp(paymentData.stripe_publishable_key);
70
67
  const refreshDebounceRef = useRef(null);
71
68
  const appearance = useMemo(() => {
72
69
  return {
73
- theme: mode === "dark" ? "night" : "stripe",
74
- variables: {
75
- colorBackground: "var(--ck-body-background-secondary)",
76
- },
70
+ theme: mode === "dark" ? "dark" : "light",
77
71
  };
78
72
  }, [mode]);
79
- // const handleSessionUpdate = useCallback(
80
- // (status: OnrampSessionStatus) => {
81
- // if (status === lastStatusRef.current) return
82
- // lastStatusRef.current = status
83
- // const shouldRefresh = status === "fulfillment_complete" || status === "rejected"
84
- // if (!shouldRefresh) {
85
- // return
86
- // }
87
- // if (refreshDebounceRef.current) {
88
- // window.clearTimeout(refreshDebounceRef.current)
89
- // }
90
- // refreshDebounceRef.current = window.setTimeout(() => {
91
- // void refreshOrderRef.current()
92
- // }, 500)
93
- // },
94
- // [refreshOrderRef]
95
- // )
96
73
  useEffect(() => {
97
74
  return () => {
98
75
  if (refreshDebounceRef.current) {
@@ -100,23 +77,18 @@ function StripeOnrampCheckout({ paymentData }) {
100
77
  }
101
78
  };
102
79
  }, []);
103
- // if (error) {
104
- // return (
105
- // <StatusCard
106
- // warning
107
- // title="Stripe unavailable"
108
- // body={error.message}
109
- // actionLabel="Try again"
110
- // onAction={() => {
111
- // void refetch()
112
- // }}
113
- // />
114
- // )
115
- // }
116
- return (_jsx(OnrampShell, { children: paymentData.client_secret ? (_jsx(OnrampElement, { id: "onramp-element", clientSecret: paymentData.client_secret, appearance: appearance, onReady: triggerResize })) : (_jsx(OnrampOverlay, { children: _jsx(Spinner, {}) })) }));
80
+ useEffect(() => {
81
+ triggerResize();
82
+ }, [error, isLoading, stripeOnramp, triggerResize]);
83
+ if (error) {
84
+ return (_jsx(StatusCard, { warning: true, title: "Stripe unavailable", body: error.message, actionLabel: "Try again", onAction: () => {
85
+ void refetch();
86
+ } }));
87
+ }
88
+ return (_jsxs(OnrampShell, { children: [isLoading ? (_jsx(OnrampOverlay, { children: _jsx(Spinner, {}) })) : null, paymentData.client_secret && stripeOnramp ? (_jsx(CryptoElements, { stripeOnramp: stripeOnramp, children: _jsx(OnrampElement, { id: "onramp-element", clientSecret: paymentData.client_secret, appearance: appearance, onReady: triggerResize }) })) : (_jsx(OnrampOverlay, { children: _jsx(Spinner, {}) }))] }));
117
89
  }
118
90
  function OnrampElement({ clientSecret, appearance, onReady, onChange, ...props }) {
119
- const stripeOnramp = useStripeOnramp();
91
+ const stripeOnramp = useStripeOnrampContext();
120
92
  const onrampElementRef = useRef(null);
121
93
  const [session, setSession] = useState();
122
94
  const appearanceJSON = JSON.stringify(appearance);
@@ -138,7 +110,7 @@ function OnrampElement({ clientSecret, appearance, onReady, onChange, ...props }
138
110
  }, [appearanceJSON, clientSecret, stripeOnramp]);
139
111
  useOnrampSessionListener("onramp_ui_loaded", session, onReady);
140
112
  useOnrampSessionListener("onramp_session_updated", session, onChange);
141
- return _jsx("div", { ...props, ref: onrampElementRef });
113
+ return _jsx(OnrampMount, { ...props, ref: onrampElementRef });
142
114
  }
143
115
  function useCardPaymentData() {
144
116
  const { paymentState } = usePayContext();
@@ -169,10 +141,39 @@ function useCardPaymentData() {
169
141
  data: paymentData ?? query.data,
170
142
  };
171
143
  }
144
+ const stripeOnrampPromises = new Map();
145
+ function getStripeOnramp(publishableKey) {
146
+ const existingPromise = stripeOnrampPromises.get(publishableKey);
147
+ if (existingPromise) {
148
+ return existingPromise;
149
+ }
150
+ const stripeOnrampPromise = loadStripeOnramp(publishableKey).catch((error) => {
151
+ stripeOnrampPromises.delete(publishableKey);
152
+ throw error;
153
+ });
154
+ stripeOnrampPromises.set(publishableKey, stripeOnrampPromise);
155
+ return stripeOnrampPromise;
156
+ }
157
+ function useLoadStripeOnramp(publishableKey) {
158
+ return useQuery({
159
+ queryKey: ["stripe-onramp", publishableKey],
160
+ enabled: Boolean(publishableKey),
161
+ staleTime: Infinity,
162
+ retry: 1,
163
+ refetchOnWindowFocus: false,
164
+ queryFn: async () => {
165
+ const stripeOnramp = await getStripeOnramp(publishableKey);
166
+ if (!stripeOnramp) {
167
+ throw new Error("Stripe checkout can only be loaded in a browser.");
168
+ }
169
+ return stripeOnramp;
170
+ },
171
+ });
172
+ }
172
173
  // ReactContext to simplify access of StripeOnramp object
173
174
  const CryptoElementsContext = createContext(null);
174
175
  CryptoElementsContext.displayName = "CryptoElementsContext";
175
- export const CryptoElements = ({ stripeOnramp, children }) => {
176
+ export const CryptoElements = ({ stripeOnramp, children, }) => {
176
177
  const [ctx, setContext] = useState(() => ({
177
178
  onramp: null,
178
179
  }));
@@ -180,7 +181,7 @@ export const CryptoElements = ({ stripeOnramp, children }) => {
180
181
  let isMounted = true;
181
182
  Promise.resolve(stripeOnramp).then((onramp) => {
182
183
  if (onramp && isMounted) {
183
- setContext((ctx) => (ctx.onramp ? ctx : { onramp }));
184
+ setContext((ctx) => (ctx.onramp === onramp ? ctx : { onramp }));
184
185
  }
185
186
  });
186
187
  return () => {
@@ -190,7 +191,7 @@ export const CryptoElements = ({ stripeOnramp, children }) => {
190
191
  return _jsx(CryptoElementsContext.Provider, { value: ctx, children: children });
191
192
  };
192
193
  // React hook to get StripeOnramp from context
193
- export const useStripeOnramp = () => {
194
+ export const useStripeOnrampContext = () => {
194
195
  const context = useContext(CryptoElementsContext);
195
196
  return context?.onramp;
196
197
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coin-voyage/paykit",
3
3
  "description": "Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.",
4
- "version": "2.4.5-beta.3",
4
+ "version": "2.4.5-beta.4",
5
5
  "private": false,
6
6
  "sideEffects": false,
7
7
  "author": "Lars <lars@coinvoyage.io>",