@coin-voyage/paykit 2.3.6-beta.1 → 2.3.6-beta.2
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/assets/icons.d.ts +3 -0
- package/dist/assets/icons.js +3 -0
- package/dist/components/Pages/CardPayment/index.d.ts +1 -0
- package/dist/components/Pages/CardPayment/index.js +214 -0
- package/dist/components/Pages/MobileConnectors/index.js +2 -2
- package/dist/components/Pages/PayToAddress/index.js +2 -2
- package/dist/components/Pages/PayWithToken/index.js +3 -3
- package/dist/components/Pages/SelectChain/index.js +2 -2
- package/dist/components/Pages/SelectMethod/index.js +2 -2
- package/dist/components/Pages/SelectToken/index.js +3 -3
- package/dist/components/contexts/pay/index.d.ts +3 -3
- package/dist/components/pay-button/index.js +1 -1
- package/dist/components/pay-modal/ConnectWithInjector/index.js +2 -2
- package/dist/components/pay-modal/ConnectWithQRCode.js +2 -2
- package/dist/components/pay-modal/index.js +5 -5
- package/dist/components/ui/ConnectorList/index.js +6 -6
- package/dist/components/ui/Modal/ModalPageRenderer.d.ts +3 -3
- package/dist/components/ui/Modal/ModalPageRenderer.js +4 -1
- package/dist/components/ui/Modal/index.d.ts +3 -3
- package/dist/components/ui/Modal/index.js +2 -2
- package/dist/components/ui/Modal/styles.js +21 -0
- package/dist/config/route-config.d.ts +2 -2
- package/dist/config/route-config.js +34 -26
- package/dist/hooks/useChainOptions.js +2 -2
- package/dist/hooks/useDepositAddressQuery.js +5 -1
- package/dist/hooks/useMethodOptions.d.ts +1 -0
- package/dist/hooks/useMethodOptions.js +85 -26
- package/dist/hooks/usePayToAddressChainOptions.js +2 -2
- package/dist/hooks/usePayToAddressTokens.js +2 -2
- package/dist/hooks/usePayWithCard.d.ts +10 -0
- package/dist/hooks/usePayWithCard.js +24 -0
- package/dist/hooks/usePayWithToken.js +19 -10
- package/dist/hooks/usePaymentState.d.ts +4 -4
- package/dist/hooks/usePaymentState.js +9 -2
- package/dist/hooks/useTokenOptions.js +2 -2
- package/dist/hooks/useWalletConnectModal.js +2 -2
- package/dist/hooks/useWalletConnectUri.js +2 -2
- package/dist/providers/paykit-provider.js +139 -122
- package/dist/types/route-config.d.ts +3 -3
- package/dist/types/routes.d.ts +17 -16
- package/dist/types/routes.js +20 -18
- package/dist/types/state.d.ts +2 -2
- package/dist/types.d.ts +4 -0
- package/package.json +5 -3
- package/dist/types/enums.d.ts +0 -4
- package/dist/types/enums.js +0 -5
package/dist/assets/icons.d.ts
CHANGED
|
@@ -28,3 +28,6 @@ export declare const AuthIcon: ({ ...props }: {
|
|
|
28
28
|
export declare const ErrorIcon: ({ ...props }: {
|
|
29
29
|
[x: string]: any;
|
|
30
30
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare const CreditCardIcon: ({ ...props }: {
|
|
32
|
+
[x: string]: any;
|
|
33
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
package/dist/assets/icons.js
CHANGED
|
@@ -41,3 +41,6 @@ export const AuthIcon = ({ ...props }) => (_jsx("div", { ...props, style: {
|
|
|
41
41
|
export const ErrorIcon = ({ ...props }) => {
|
|
42
42
|
return (_jsx("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM6.70711 5.29289C6.31658 4.90237 5.68342 4.90237 5.29289 5.29289C4.90237 5.68342 4.90237 6.31658 5.29289 6.70711L7.58579 9L5.29289 11.2929C4.90237 11.6834 4.90237 12.3166 5.29289 12.7071C5.68342 13.0976 6.31658 13.0976 6.70711 12.7071L9 10.4142L11.2929 12.7071C11.6834 13.0976 12.3166 13.0976 12.7071 12.7071C13.0976 12.3166 13.0976 11.6834 12.7071 11.2929L10.4142 9L12.7071 6.70711C13.0976 6.31658 13.0976 5.68342 12.7071 5.29289C12.3166 4.90237 11.6834 4.90237 11.2929 5.29289L9 7.58579L6.70711 5.29289Z", fill: "currentColor" }) }));
|
|
43
43
|
};
|
|
44
|
+
export const CreditCardIcon = ({ ...props }) => {
|
|
45
|
+
return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", ...props, children: [_jsx("rect", { width: "20", height: "14", x: "2", y: "5", rx: "2" }), _jsx("line", { x1: "2", x2: "22", y1: "10", y2: "10" })] }));
|
|
46
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function CardPayment(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getFiatPaymentData } from "@coin-voyage/shared/common";
|
|
3
|
+
import { PayOrderMode, PayOrderStatus } from "@coin-voyage/shared/types";
|
|
4
|
+
import { loadStripeOnramp } from "@stripe/crypto/pure";
|
|
5
|
+
import { useQuery } from "@tanstack/react-query";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
7
|
+
import { AlertIcon } from "../../../assets/icons";
|
|
8
|
+
import useLocales from "../../../hooks/useLocales";
|
|
9
|
+
import styled from "../../../styles/styled";
|
|
10
|
+
import { ROUTE } from "../../../types/routes";
|
|
11
|
+
import usePayContext from "../../contexts/pay";
|
|
12
|
+
import Button from "../../ui/Button";
|
|
13
|
+
import { ModalBody, ModalContent, ModalH1, PageContent } from "../../ui/Modal/styles";
|
|
14
|
+
import { OrderHeader } from "../../ui/OrderHeader";
|
|
15
|
+
import PoweredByFooter from "../../ui/PoweredByFooter";
|
|
16
|
+
import { Spinner } from "../../ui/Spinner";
|
|
17
|
+
export default function CardPayment() {
|
|
18
|
+
const { triggerResize } = usePayContext();
|
|
19
|
+
const { data, isLoading, error, refetch } = useCardPaymentData();
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
triggerResize();
|
|
22
|
+
}, [triggerResize, isLoading, data?.session_id, data?.client_secret, error]);
|
|
23
|
+
return (_jsxs(PageContent, { children: [_jsx(OrderHeader, { minified: true }), _jsx(CardPaymentContent, { paymentData: data, isLoading: isLoading, error: error instanceof Error ? error : null, onRetry: () => {
|
|
24
|
+
void refetch();
|
|
25
|
+
} }), _jsx(PoweredByFooter, {})] }));
|
|
26
|
+
}
|
|
27
|
+
function CardPaymentContent({ paymentData, isLoading, error, onRetry, }) {
|
|
28
|
+
const locales = useLocales();
|
|
29
|
+
const { paymentState, setRoute } = usePayContext();
|
|
30
|
+
const { payOrder } = paymentState;
|
|
31
|
+
if (!payOrder) {
|
|
32
|
+
return (_jsx(StatusCard, { title: locales.selectPayToAddressWaitingScreen_unavailable_h1, body: "We couldn't load this card payment.", actionLabel: locales.back, onAction: () => setRoute(ROUTE.SELECT_METHOD) }));
|
|
33
|
+
}
|
|
34
|
+
if (payOrder.status === PayOrderStatus.EXPIRED) {
|
|
35
|
+
return _jsx(ExpiredCardPayment, {});
|
|
36
|
+
}
|
|
37
|
+
if (isLoading) {
|
|
38
|
+
return _jsx(StatusCard, { loading: true, title: locales.requesting_payment_h1, body: "Preparing secure Stripe checkout..." });
|
|
39
|
+
}
|
|
40
|
+
if (error || !paymentData) {
|
|
41
|
+
return (_jsx(StatusCard, { warning: true, title: locales.selectPayToAddressWaitingScreen_unavailable_h1, body: error?.message ?? "We couldn't start the Stripe checkout for this order.", actionLabel: locales.tryAgain, onAction: onRetry }));
|
|
42
|
+
}
|
|
43
|
+
return _jsx(StripeOnrampCheckout, { paymentData: paymentData });
|
|
44
|
+
}
|
|
45
|
+
function ExpiredCardPayment() {
|
|
46
|
+
const locales = useLocales();
|
|
47
|
+
const { paymentState, setRoute } = usePayContext();
|
|
48
|
+
const isDeposit = paymentState.payOrder?.mode === PayOrderMode.DEPOSIT;
|
|
49
|
+
return (_jsx(StatusCard, { warning: true, title: locales.payWithTokenScreen_expired_h1, body: locales.payWithTokenScreen_expired_p, actionLabel: isDeposit ? locales.refresh : locales.selectTokenScreen_selectAnotherMethod, onAction: () => {
|
|
50
|
+
if (isDeposit) {
|
|
51
|
+
void paymentState.copyDepositPayOrder();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setRoute(ROUTE.SELECT_METHOD);
|
|
55
|
+
} }));
|
|
56
|
+
}
|
|
57
|
+
function StatusCard({ title, body, actionLabel, onAction, loading = false, warning = false, }) {
|
|
58
|
+
return (_jsxs(ModalContent, { "$center": true, style: {
|
|
59
|
+
marginLeft: 24,
|
|
60
|
+
marginRight: 24,
|
|
61
|
+
paddingTop: 24,
|
|
62
|
+
paddingBottom: 24,
|
|
63
|
+
}, children: [loading ? _jsx(Spinner, {}) : warning ? _jsx(AlertIcon, {}) : null, _jsx(ModalH1, { "$warning": warning, children: title }), _jsx(ModalBody, { children: body }), actionLabel && onAction ? (_jsx(ActionRow, { children: _jsx(Button, { onClick: onAction, children: actionLabel }) })) : null] }));
|
|
64
|
+
}
|
|
65
|
+
function StripeOnrampCheckout({ paymentData }) {
|
|
66
|
+
const { paymentState, mode, triggerResize } = usePayContext();
|
|
67
|
+
const { data: stripeOnramp, isLoading, error, refetch } = useStripeOnramp(paymentData.stripe_publishable_key);
|
|
68
|
+
const refreshOrderRef = useLatestRef(paymentState.refreshOrder);
|
|
69
|
+
const refreshDebounceRef = useRef(null);
|
|
70
|
+
const theme = useMemo(() => {
|
|
71
|
+
return mode === "dark" ? "dark" : "light";
|
|
72
|
+
}, [mode]);
|
|
73
|
+
const handleSessionUpdate = useCallback((status) => {
|
|
74
|
+
if (status === "initialized") {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (refreshDebounceRef.current) {
|
|
78
|
+
window.clearTimeout(refreshDebounceRef.current);
|
|
79
|
+
}
|
|
80
|
+
refreshDebounceRef.current = window.setTimeout(() => {
|
|
81
|
+
void refreshOrderRef.current();
|
|
82
|
+
}, 500);
|
|
83
|
+
}, [refreshOrderRef]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
return () => {
|
|
86
|
+
if (refreshDebounceRef.current) {
|
|
87
|
+
window.clearTimeout(refreshDebounceRef.current);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}, []);
|
|
91
|
+
if (error) {
|
|
92
|
+
return (_jsx(StatusCard, { warning: true, title: "Stripe unavailable", body: error.message, actionLabel: "Try again", onAction: () => {
|
|
93
|
+
void refetch();
|
|
94
|
+
} }));
|
|
95
|
+
}
|
|
96
|
+
return (_jsxs(OnrampShell, { children: [isLoading ? (_jsx(OnrampOverlay, { children: _jsx(Spinner, {}) })) : null, stripeOnramp ? (_jsx(OnrampSession, { stripeOnramp: stripeOnramp, clientSecret: paymentData.client_secret, theme: theme, onUiLoaded: triggerResize, onSessionUpdate: handleSessionUpdate }, paymentData.client_secret)) : null] }));
|
|
97
|
+
}
|
|
98
|
+
function OnrampSession({ stripeOnramp, clientSecret, theme, onUiLoaded, onSessionUpdate, }) {
|
|
99
|
+
const mountNodeRef = useRef(null);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
const mountNode = mountNodeRef.current;
|
|
102
|
+
if (!mountNode) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
mountNode.replaceChildren();
|
|
106
|
+
const session = stripeOnramp.createSession({
|
|
107
|
+
clientSecret,
|
|
108
|
+
appearance: theme ? { theme } : undefined,
|
|
109
|
+
});
|
|
110
|
+
const handleUiLoaded = () => {
|
|
111
|
+
onUiLoaded?.();
|
|
112
|
+
};
|
|
113
|
+
const handleSessionUpdated = (event) => {
|
|
114
|
+
onSessionUpdate?.(event.payload.session.status);
|
|
115
|
+
};
|
|
116
|
+
session.addEventListener("onramp_ui_loaded", handleUiLoaded);
|
|
117
|
+
session.addEventListener("onramp_session_updated", handleSessionUpdated);
|
|
118
|
+
session.mount(mountNode);
|
|
119
|
+
return () => {
|
|
120
|
+
session.removeEventListener("onramp_ui_loaded", handleUiLoaded);
|
|
121
|
+
session.removeEventListener("onramp_session_updated", handleSessionUpdated);
|
|
122
|
+
mountNode.replaceChildren();
|
|
123
|
+
};
|
|
124
|
+
}, [clientSecret, onSessionUpdate, onUiLoaded, stripeOnramp, theme]);
|
|
125
|
+
return _jsx(OnrampMount, { ref: mountNodeRef });
|
|
126
|
+
}
|
|
127
|
+
function useCardPaymentData() {
|
|
128
|
+
const { paymentState } = usePayContext();
|
|
129
|
+
const { payOrder, payWithCard } = paymentState;
|
|
130
|
+
const paymentData = getFiatPaymentData(payOrder?.payment);
|
|
131
|
+
const query = useQuery({
|
|
132
|
+
queryKey: ["card-payment", payOrder?.id, paymentData?.session_id ?? null, paymentData?.client_secret ?? null],
|
|
133
|
+
enabled: Boolean(payOrder?.id) && !paymentData,
|
|
134
|
+
retry: false,
|
|
135
|
+
refetchOnWindowFocus: false,
|
|
136
|
+
queryFn: async () => {
|
|
137
|
+
if (!payOrder) {
|
|
138
|
+
throw new Error("Missing pay order");
|
|
139
|
+
}
|
|
140
|
+
if (paymentData) {
|
|
141
|
+
return paymentData;
|
|
142
|
+
}
|
|
143
|
+
const paymentDetails = await payWithCard();
|
|
144
|
+
const fiatPaymentData = getFiatPaymentData(paymentDetails.data);
|
|
145
|
+
if (!fiatPaymentData) {
|
|
146
|
+
throw new Error("Stripe onramp session is unavailable for this pay order");
|
|
147
|
+
}
|
|
148
|
+
return fiatPaymentData;
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
...query,
|
|
153
|
+
data: paymentData ?? query.data,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function useStripeOnramp(publishableKey) {
|
|
157
|
+
return useQuery({
|
|
158
|
+
queryKey: ["stripe-onramp", publishableKey],
|
|
159
|
+
enabled: Boolean(publishableKey),
|
|
160
|
+
staleTime: Infinity,
|
|
161
|
+
retry: false,
|
|
162
|
+
queryFn: async () => {
|
|
163
|
+
if (!publishableKey) {
|
|
164
|
+
throw new Error("Missing Stripe publishable key.");
|
|
165
|
+
}
|
|
166
|
+
const instance = await getStripeOnrampPromise(publishableKey);
|
|
167
|
+
if (!instance) {
|
|
168
|
+
throw new Error("Stripe Onramp is only available in the browser.");
|
|
169
|
+
}
|
|
170
|
+
return instance;
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const stripeOnrampPromiseCache = new Map();
|
|
175
|
+
function getStripeOnrampPromise(publishableKey) {
|
|
176
|
+
const cached = stripeOnrampPromiseCache.get(publishableKey);
|
|
177
|
+
if (cached) {
|
|
178
|
+
return cached;
|
|
179
|
+
}
|
|
180
|
+
const nextPromise = loadStripeOnramp(publishableKey);
|
|
181
|
+
stripeOnrampPromiseCache.set(publishableKey, nextPromise);
|
|
182
|
+
return nextPromise;
|
|
183
|
+
}
|
|
184
|
+
function useLatestRef(value) {
|
|
185
|
+
const ref = useRef(value);
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
ref.current = value;
|
|
188
|
+
}, [value]);
|
|
189
|
+
return ref;
|
|
190
|
+
}
|
|
191
|
+
const OnrampShell = styled.div `
|
|
192
|
+
position: relative;
|
|
193
|
+
min-height: 480px;
|
|
194
|
+
border-radius: 10px;
|
|
195
|
+
overflow: hidden;
|
|
196
|
+
background: var(--ck-body-background-secondary);
|
|
197
|
+
border: 1px solid var(--ck-body-divider-secondary, var(--ck-body-divider));
|
|
198
|
+
`;
|
|
199
|
+
const OnrampMount = styled.div `
|
|
200
|
+
min-height: 480px;
|
|
201
|
+
`;
|
|
202
|
+
const OnrampOverlay = styled.div `
|
|
203
|
+
position: absolute;
|
|
204
|
+
inset: 0;
|
|
205
|
+
z-index: 1;
|
|
206
|
+
display: flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: center;
|
|
209
|
+
background: color-mix(in srgb, var(--ck-body-background) 88%, transparent);
|
|
210
|
+
`;
|
|
211
|
+
const ActionRow = styled.div `
|
|
212
|
+
width: 100%;
|
|
213
|
+
margin-top: 8px;
|
|
214
|
+
`;
|
|
@@ -6,7 +6,7 @@ import { useWalletConnectModal } from "../../../hooks/useWalletConnectModal";
|
|
|
6
6
|
import { useWalletConnectUri } from "../../../hooks/useWalletConnectUri";
|
|
7
7
|
import { useWallets } from "../../../hooks/useWallets";
|
|
8
8
|
import { walletConfigs } from "../../../lib/config/wallet";
|
|
9
|
-
import {
|
|
9
|
+
import { ROUTE } from "../../../types/routes";
|
|
10
10
|
import usePayContext from "../../contexts/pay";
|
|
11
11
|
import { ModalContent, PageContent } from "../../ui/Modal/styles";
|
|
12
12
|
import { ScrollArea } from "../../ui/ScrollArea";
|
|
@@ -44,7 +44,7 @@ export default function MobileConnectors() {
|
|
|
44
44
|
chainType: connectorChainType,
|
|
45
45
|
open: true,
|
|
46
46
|
walletId,
|
|
47
|
-
route:
|
|
47
|
+
route: ROUTE.CONNECTORS,
|
|
48
48
|
}))}`;
|
|
49
49
|
}
|
|
50
50
|
const uri = wallet.getWalletDeeplink?.(URI, connectorChainType);
|
|
@@ -5,7 +5,7 @@ import { AlertIcon } from "../../../assets/icons";
|
|
|
5
5
|
import { useCountdown } from "../../../hooks/useCountdown";
|
|
6
6
|
import { useDepositAddressQuery } from "../../../hooks/useDepositAddressQuery";
|
|
7
7
|
import useLocales from "../../../hooks/useLocales";
|
|
8
|
-
import {
|
|
8
|
+
import { ROUTE } from "../../../types/routes";
|
|
9
9
|
import usePayContext from "../../contexts/pay";
|
|
10
10
|
import Button from "../../ui/Button";
|
|
11
11
|
import CustomQRCode from "../../ui/CustomQRCode";
|
|
@@ -66,7 +66,7 @@ function DepositFailed() {
|
|
|
66
66
|
const onSelectAnotherMethod = useCallback(() => {
|
|
67
67
|
setPayToAddressChain(undefined);
|
|
68
68
|
setPayToAddressCurrency(undefined);
|
|
69
|
-
setRoute(
|
|
69
|
+
setRoute(ROUTE.ADDRESS_CHAIN_SELECT);
|
|
70
70
|
}, [setRoute, setPayToAddressChain, setPayToAddressCurrency]);
|
|
71
71
|
return (_jsxs(ModalContent, { "$center": true, style: {
|
|
72
72
|
marginLeft: 24,
|
|
@@ -9,7 +9,7 @@ import { chainToLogo } from "../../../assets/chains";
|
|
|
9
9
|
import { AlertIcon, RetryIconCircle } from "../../../assets/icons";
|
|
10
10
|
import useLocales from "../../../hooks/useLocales";
|
|
11
11
|
import styled from "../../../styles/styled";
|
|
12
|
-
import {
|
|
12
|
+
import { ROUTE } from "../../../types/routes";
|
|
13
13
|
import usePayContext from "../../contexts/pay";
|
|
14
14
|
import { RetryButton, RetryIconContainer } from "../../pay-modal/ConnectWithInjector/styles";
|
|
15
15
|
import CircleSpinner from "../../spinners/CircleSpinner";
|
|
@@ -74,7 +74,7 @@ export default function PayWithToken() {
|
|
|
74
74
|
try {
|
|
75
75
|
await executePayment(token);
|
|
76
76
|
setPayState(PayState.RequestSuccessful);
|
|
77
|
-
setTimeout(() => setRoute(
|
|
77
|
+
setTimeout(() => setRoute(ROUTE.CONFIRMATION), 200);
|
|
78
78
|
}
|
|
79
79
|
catch (e) {
|
|
80
80
|
if (e?.name === "ConnectorChainMismatchError") {
|
|
@@ -103,7 +103,7 @@ export default function PayWithToken() {
|
|
|
103
103
|
const onRetry = () => {
|
|
104
104
|
if (isExpired && isDeposit) {
|
|
105
105
|
paymentState.copyDepositPayOrder();
|
|
106
|
-
setRoute(
|
|
106
|
+
setRoute(ROUTE.WALLET_TOKEN_SELECT);
|
|
107
107
|
}
|
|
108
108
|
else if (selectedCurrencyOption) {
|
|
109
109
|
handleTransfer(selectedCurrencyOption);
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useAccount, useAccountDisconnect } from "@coin-voyage/crypto/hooks";
|
|
3
3
|
import { useIsMobile } from "@coin-voyage/shared/hooks";
|
|
4
4
|
import { useChainOptions } from "../../../hooks/useChainOptions";
|
|
5
|
-
import {
|
|
5
|
+
import { ROUTE } from "../../../types/routes";
|
|
6
6
|
import usePayContext from "../../contexts/pay";
|
|
7
7
|
import { PageContent } from "../../ui/Modal/styles";
|
|
8
8
|
import OptionsList from "../../ui/OptionsList";
|
|
@@ -19,7 +19,7 @@ export default function SelectChain() {
|
|
|
19
19
|
const handleClick = (chainType) => {
|
|
20
20
|
disconnect(account);
|
|
21
21
|
paymentState.setConnectorChainType(chainType);
|
|
22
|
-
setRoute(
|
|
22
|
+
setRoute(ROUTE.CONNECTORS);
|
|
23
23
|
};
|
|
24
24
|
const { options } = useChainOptions({
|
|
25
25
|
account,
|
|
@@ -18,9 +18,9 @@ export default function SelectMethod() {
|
|
|
18
18
|
const handleClick = () => {
|
|
19
19
|
disconnect(account);
|
|
20
20
|
};
|
|
21
|
-
const { options } = useMethodOptions({
|
|
21
|
+
const { options, isLoading } = useMethodOptions({
|
|
22
22
|
mode: paymentState.payOrder?.mode,
|
|
23
23
|
onClick: handleClick,
|
|
24
24
|
});
|
|
25
|
-
return (_jsxs(PageContent, { children: [_jsx(OrderHeader, {}), _jsx(OptionsList, { requiredSkeletons:
|
|
25
|
+
return (_jsxs(PageContent, { children: [_jsx(OrderHeader, {}), _jsx(OptionsList, { requiredSkeletons: 3, options: options, isLoading: isLoading }), _jsx(PoweredByFooter, {})] }));
|
|
26
26
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { ROUTE } from "../../../types/routes";
|
|
3
3
|
import { ModalBody, ModalContent, ModalH1, PageContent } from "../../ui/Modal/styles";
|
|
4
4
|
import { useAccount } from "@coin-voyage/crypto/hooks";
|
|
5
5
|
import { useCallback } from "react";
|
|
@@ -12,7 +12,7 @@ import SelectAnotherMethod from "../../ui/SelectAnotherMethod";
|
|
|
12
12
|
export default function SelectToken() {
|
|
13
13
|
const locales = useLocales();
|
|
14
14
|
const { paymentState, allowedWallets, setRoute } = usePayContext();
|
|
15
|
-
const { payOrderQuotes, selectedWallet, connectorChainType, setConnectorChainType, setSelectedCurrencyOption
|
|
15
|
+
const { payOrderQuotes, selectedWallet, connectorChainType, setConnectorChainType, setSelectedCurrencyOption } = paymentState;
|
|
16
16
|
const { account } = useAccount({
|
|
17
17
|
selectedWallet,
|
|
18
18
|
chainType: connectorChainType,
|
|
@@ -23,7 +23,7 @@ export default function SelectToken() {
|
|
|
23
23
|
const onSelectAnotherMethod = useCallback(() => {
|
|
24
24
|
setConnectorChainType(undefined);
|
|
25
25
|
setSelectedCurrencyOption(undefined);
|
|
26
|
-
setRoute(
|
|
26
|
+
setRoute(ROUTE.WALLET_CHAIN_SELECT);
|
|
27
27
|
}, [setConnectorChainType, setSelectedCurrencyOption, setRoute]);
|
|
28
28
|
return (_jsxs(PageContent, { children: [_jsx(OrderHeader, { minified: true, showConnectedWallet: true }), walletDisabled ? (_jsxs(ModalContent, { "$center": true, style: {
|
|
29
29
|
paddingTop: 16,
|
|
@@ -3,7 +3,7 @@ import { WalletPermission } from "@coin-voyage/crypto/types/wallet";
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
import type { PaymentState } from "../../../hooks/usePaymentState";
|
|
5
5
|
import type { CustomTheme, Languages, Mode, PayKitOptions, PayModalOptions, Theme } from "../../../types";
|
|
6
|
-
import type {
|
|
6
|
+
import type { ROUTE } from "../../../types/routes";
|
|
7
7
|
export type PayContextValue = {
|
|
8
8
|
theme: Theme;
|
|
9
9
|
setTheme: React.Dispatch<React.SetStateAction<Theme>>;
|
|
@@ -18,8 +18,8 @@ export type PayContextValue = {
|
|
|
18
18
|
open: boolean;
|
|
19
19
|
setOpen: (open: boolean) => void;
|
|
20
20
|
onSuccess: () => void;
|
|
21
|
-
route:
|
|
22
|
-
setRoute: React.Dispatch<React.SetStateAction<
|
|
21
|
+
route: ROUTE;
|
|
22
|
+
setRoute: React.Dispatch<React.SetStateAction<ROUTE>>;
|
|
23
23
|
errorMessage: string | React.ReactNode | null;
|
|
24
24
|
debugMode?: boolean;
|
|
25
25
|
log: (...props: any) => void;
|
|
@@ -12,7 +12,7 @@ import { getConnectorId } from "@coin-voyage/crypto/lib/utils/connector";
|
|
|
12
12
|
import { detectBrowser } from "@coin-voyage/shared/common";
|
|
13
13
|
import { AlertIcon, RetryIconCircle, TickIcon } from "../../../assets/icons";
|
|
14
14
|
import useLocales from "../../../hooks/useLocales";
|
|
15
|
-
import {
|
|
15
|
+
import { ROUTE } from "../../../types/routes";
|
|
16
16
|
import { isInjectedConnector, isWalletConnectConnector } from "../../../utils";
|
|
17
17
|
import usePayContext from "../../contexts/pay";
|
|
18
18
|
import CircleSpinner from "../../spinners/CircleSpinner";
|
|
@@ -101,7 +101,7 @@ export default function ConnectWithInjector({ forceState }) {
|
|
|
101
101
|
onSuccess(_, variables) {
|
|
102
102
|
if (variables?.connector) {
|
|
103
103
|
setStatus(states.CONNECTED);
|
|
104
|
-
setRoute(
|
|
104
|
+
setRoute(ROUTE.WALLET_TOKEN_SELECT);
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
107
|
});
|
|
@@ -5,7 +5,7 @@ import ScanIconWithLogos from "../../assets/scan-icon-with-logos";
|
|
|
5
5
|
import useLocales from "../../hooks/useLocales";
|
|
6
6
|
import { useWalletConnectModal } from "../../hooks/useWalletConnectModal";
|
|
7
7
|
import { useWalletConnectUri } from "../../hooks/useWalletConnectUri";
|
|
8
|
-
import {
|
|
8
|
+
import { ROUTE } from "../../types/routes";
|
|
9
9
|
import { isWalletConnectConnector } from "../../utils";
|
|
10
10
|
import usePayContext from "../contexts/pay";
|
|
11
11
|
import Button from "../ui/Button";
|
|
@@ -34,6 +34,6 @@ export default function ConnectWithQRCode() {
|
|
|
34
34
|
justifyContent: "center",
|
|
35
35
|
gap: 14,
|
|
36
36
|
}, children: [context.options?.walletConnectCTA !== "modal" && (_jsx(CopyToClipboard, { variant: "button", text: uri, children: context.options?.walletConnectCTA === "link" ? locales.copyToClipboard : locales.copyCode })), context.options?.walletConnectCTA !== "link" && (_jsx(Button, { icon: _jsx(ExternalLinkIcon, {}), onClick: openW3M, disabled: isOpenW3M, waiting: isOpenW3M, children: context.options?.walletConnectCTA === "modal" ? locales.useWalletConnectModal : locales.useModal }))] })), hasApps && (_jsx(_Fragment, { children: _jsx(Button, { onClick: () => {
|
|
37
|
-
context.setRoute(
|
|
37
|
+
context.setRoute(ROUTE.DOWNLOAD);
|
|
38
38
|
}, download: true, children: locales.getWalletName }) }))] }));
|
|
39
39
|
}
|
|
@@ -4,7 +4,7 @@ import { useCallback, useMemo } from "react";
|
|
|
4
4
|
import { routeConfig } from "../../config/route-config";
|
|
5
5
|
import useLocales from "../../hooks/useLocales";
|
|
6
6
|
import { ThemeProvider } from "../../providers/theme/provider";
|
|
7
|
-
import {
|
|
7
|
+
import { ROUTE } from "../../types/routes";
|
|
8
8
|
import { isWalletConnectConnector } from "../../utils";
|
|
9
9
|
import usePayContext from "../contexts/pay";
|
|
10
10
|
import Modal from "../ui/Modal";
|
|
@@ -54,12 +54,12 @@ export function PayModal() {
|
|
|
54
54
|
clearUserSelection();
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
if (typeof config.onBack === "
|
|
58
|
-
|
|
57
|
+
if (typeof config.onBack === "function") {
|
|
58
|
+
config.onBack(actions);
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
61
|
-
config.onBack
|
|
61
|
+
setRoute(config.onBack);
|
|
62
62
|
}
|
|
63
63
|
}, [config, actions, setRoute, clearUserSelection]);
|
|
64
|
-
return (_jsx(ThemeProvider, { theme: theme, customTheme: customTheme, mode: mode, children: _jsx(Modal, { pages: pages, pageId: route, heading: heading, depth: depth, onClose: () => setOpen(false), onInfo: showInfoButton ? () => setRoute(
|
|
64
|
+
return (_jsx(ThemeProvider, { theme: theme, customTheme: customTheme, mode: mode, children: _jsx(Modal, { pages: pages, pageId: route, heading: heading, depth: depth, onClose: () => setOpen(false), onInfo: showInfoButton ? () => setRoute(ROUTE.ABOUT) : undefined, onBack: showBackButton ? onBack : undefined }) }));
|
|
65
65
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { ROUTE } from "../../../types/routes";
|
|
3
3
|
import { ConnectorButton, ConnectorIcon, ConnectorLabel, ConnectorsContainer, RecentlyUsedTag } from "./styles";
|
|
4
4
|
import Alert from "../Alert";
|
|
5
5
|
import { ScrollArea } from "../ScrollArea";
|
|
6
6
|
import { useLastConnector, useUniversalConnect } from "@coin-voyage/crypto/hooks";
|
|
7
7
|
import { isWalletInstalled } from "@coin-voyage/crypto/lib/utils/is-wallet-installed";
|
|
8
|
-
import { useIsMobile } from "@coin-voyage/shared/hooks";
|
|
9
8
|
import { detectBrowser } from "@coin-voyage/shared/common";
|
|
9
|
+
import { useIsMobile } from "@coin-voyage/shared/hooks";
|
|
10
10
|
import { useCallback, useMemo } from "react";
|
|
11
11
|
import useLocales from "../../../hooks/useLocales";
|
|
12
12
|
import { useWalletConnectUri } from "../../../hooks/useWalletConnectUri";
|
|
@@ -48,7 +48,7 @@ const ConnectorItem = ({ wallet, isRecent, walletConnectURI, }) => {
|
|
|
48
48
|
const { connect } = useUniversalConnect({
|
|
49
49
|
onSuccess: (_, variables) => {
|
|
50
50
|
if (variables?.connector) {
|
|
51
|
-
setRoute(
|
|
51
|
+
setRoute(ROUTE.WALLET_TOKEN_SELECT);
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
onError: (error) => {
|
|
@@ -82,7 +82,7 @@ const ConnectorItem = ({ wallet, isRecent, walletConnectURI, }) => {
|
|
|
82
82
|
if (deeplink)
|
|
83
83
|
return;
|
|
84
84
|
if (redirectToMoreWallets) {
|
|
85
|
-
setRoute(
|
|
85
|
+
setRoute(ROUTE.MOBILECONNECTORS);
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
if (shouldConnectImmediately) {
|
|
@@ -92,7 +92,7 @@ const ConnectorItem = ({ wallet, isRecent, walletConnectURI, }) => {
|
|
|
92
92
|
connect({ walletConnector });
|
|
93
93
|
}
|
|
94
94
|
paymentState.setSelectedWallet(wallet);
|
|
95
|
-
setRoute(
|
|
95
|
+
setRoute(ROUTE.CONNECT);
|
|
96
96
|
}, [deeplink, redirectToMoreWallets, shouldConnectImmediately, wallet, paymentState, setRoute, connect]);
|
|
97
|
-
return (_jsxs(ConnectorButton, { type: "button", as: deeplink ? "a" : undefined, href: deeplink, disabled: route !==
|
|
97
|
+
return (_jsxs(ConnectorButton, { type: "button", as: deeplink ? "a" : undefined, href: deeplink, disabled: route !== ROUTE.CONNECTORS, onClick: handleClick, children: [_jsx(ConnectorIcon, { "data-small": wallet.iconShouldShrink, "data-shape": wallet.iconShape, children: wallet.iconConnector ?? wallet.icon }), _jsxs(ConnectorLabel, { children: [isMobile ? (wallet.shortName ?? wallet.name) : wallet.name, !options?.hideRecentBadge && isRecent && _jsx(RecentlyUsedTag, { children: locales.recent })] })] }));
|
|
98
98
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { ROUTE } from "../../../types/routes";
|
|
3
3
|
type ModalPageRendererProps = {
|
|
4
|
-
pages: Record<
|
|
5
|
-
pageId:
|
|
4
|
+
pages: Record<ROUTE, React.ReactNode>;
|
|
5
|
+
pageId: ROUTE;
|
|
6
6
|
currentDepth: number;
|
|
7
7
|
prevDepth: number;
|
|
8
8
|
positionInside?: boolean;
|
|
@@ -3,7 +3,10 @@ import { useEffect } from "react";
|
|
|
3
3
|
import { useTransition } from "react-transition-state";
|
|
4
4
|
import { InnerContainer, PageContainer, PageContents } from "./styles";
|
|
5
5
|
export function ModalPageRenderer({ pages, pageId, currentDepth, prevDepth, positionInside, transitionState, contentRef, rendered, }) {
|
|
6
|
-
return (_jsx(InnerContainer, { children: Object.keys(pages).map((key) =>
|
|
6
|
+
return (_jsx(InnerContainer, { children: Object.keys(pages).map((key) => {
|
|
7
|
+
const routeKey = Number(key);
|
|
8
|
+
return (_jsx(Page, { open: routeKey === pageId, initial: !positionInside && transitionState !== "entered", enterAnim: routeKey === pageId && currentDepth > prevDepth ? "active-scale-up" : "active", exitAnim: routeKey !== pageId && currentDepth < prevDepth ? "exit-scale-down" : "exit", children: _jsx(PageContents, { ref: contentRef, style: { pointerEvents: routeKey === pageId && rendered ? "auto" : "none" }, children: pages[routeKey] }, `inner-${routeKey}`) }, routeKey));
|
|
9
|
+
}) }));
|
|
7
10
|
}
|
|
8
11
|
const Page = ({ children, open, initial, enterAnim, exitAnim }) => {
|
|
9
12
|
const [state, setOpen] = useTransition({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Variants } from "framer-motion";
|
|
2
2
|
import type React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { ROUTE } from "../../../types/routes";
|
|
4
4
|
export declare const contentVariants: Variants;
|
|
5
5
|
type ModalProps = {
|
|
6
|
-
pages: Record<
|
|
7
|
-
pageId:
|
|
6
|
+
pages: Record<ROUTE, React.ReactNode>;
|
|
7
|
+
pageId: ROUTE;
|
|
8
8
|
heading?: string;
|
|
9
9
|
depth?: number;
|
|
10
10
|
positionInside?: boolean;
|
|
@@ -4,7 +4,7 @@ import { FocusTrap, usePrevious } from "@coin-voyage/shared/hooks";
|
|
|
4
4
|
import useLocales from "../../../hooks/useLocales";
|
|
5
5
|
import { useThemeContext } from "../../../providers/theme/provider";
|
|
6
6
|
import { ResetContainer } from "../../../styles";
|
|
7
|
-
import {
|
|
7
|
+
import { ROUTE } from "../../../types/routes";
|
|
8
8
|
import usePayContext from "../../contexts/pay";
|
|
9
9
|
import Portal from "../Portal";
|
|
10
10
|
import { ModalControls } from "./ModalControls";
|
|
@@ -59,7 +59,7 @@ export default function Modal({ pages, pageId, heading, depth = 1, positionInsid
|
|
|
59
59
|
width: "var(--width)",
|
|
60
60
|
zIndex: 9,
|
|
61
61
|
transition: "width 200ms ease",
|
|
62
|
-
} }), _jsxs(BoxContainer, { className: `${rendered && "active"}`, children: [_jsx(ModalDisclaimer, { disclaimer: context.options?.disclaimer, visible: context.route ===
|
|
62
|
+
} }), _jsxs(BoxContainer, { className: `${rendered && "active"}`, children: [_jsx(ModalDisclaimer, { disclaimer: context.options?.disclaimer, visible: context.route === ROUTE.CONNECTORS }), _jsx(ModalErrorBanner, { errorMessage: context.errorMessage, onDismiss: () => context.displayError(null) }), _jsx(ModalControls, { locales: locales, mobile: mobile, inTransition: inTransition, hideQuestionMarkCTA: context.options?.hideQuestionMarkCTA, onClose: onClose, onBack: onBack, onInfo: onInfo }), _jsx(ModalHeadingBar, { heading: heading, routeKey: `${context.route}`, mobile: mobile }), _jsx(ModalPageRenderer, { pages: pages, pageId: pageId, currentDepth: depth, prevDepth: prevDepth, positionInside: positionInside, transitionState: state, contentRef: contentRef, rendered: rendered })] })] })] }) }));
|
|
63
63
|
if (!mounted)
|
|
64
64
|
return null;
|
|
65
65
|
if (positionInside)
|
|
@@ -2,6 +2,8 @@ import { motion } from "framer-motion";
|
|
|
2
2
|
import { keyframes } from "styled-components";
|
|
3
3
|
import defaultTheme from "../../../lib/config/default-theme";
|
|
4
4
|
import styled from "../../../styles/styled";
|
|
5
|
+
const mobileModalMaxHeight = "calc(100vh - 8px)";
|
|
6
|
+
const mobileModalMaxHeightDynamic = "calc(100dvh - 8px)";
|
|
5
7
|
export const ErrorMessage = styled(motion.div) `
|
|
6
8
|
z-index: -1;
|
|
7
9
|
pointer-events: auto;
|
|
@@ -234,6 +236,10 @@ export const BoxContainer = styled(motion.div) `
|
|
|
234
236
|
|
|
235
237
|
&:before {
|
|
236
238
|
width: 100%;
|
|
239
|
+
height: min(var(--height, ${mobileModalMaxHeight}), ${mobileModalMaxHeight});
|
|
240
|
+
height: min(var(--height, ${mobileModalMaxHeightDynamic}), ${mobileModalMaxHeightDynamic});
|
|
241
|
+
max-height: ${mobileModalMaxHeight};
|
|
242
|
+
max-height: ${mobileModalMaxHeightDynamic};
|
|
237
243
|
transition: 0ms height cubic-bezier(0.15, 1.15, 0.6, 1);
|
|
238
244
|
will-change: height;
|
|
239
245
|
}
|
|
@@ -248,9 +254,15 @@ export const ControllerContainer = styled(motion.div) `
|
|
|
248
254
|
transform: translateX(-50%);
|
|
249
255
|
backface-visibility: hidden;
|
|
250
256
|
width: var(--width);
|
|
257
|
+
border-radius: var(--ck-border-radius, 20px) var(--ck-border-radius, 20px) 0 0;
|
|
258
|
+
background: var(--ck-body-background);
|
|
251
259
|
transition: 0.2s ease width;
|
|
252
260
|
pointer-events: auto;
|
|
253
261
|
//border-bottom: 1px solid var(--ck-body-divider);
|
|
262
|
+
|
|
263
|
+
@media only screen and (max-width: ${defaultTheme.mobileWidth}px) {
|
|
264
|
+
border-radius: var(--ck-border-radius, 30px) var(--ck-border-radius, 30px) 0 0;
|
|
265
|
+
}
|
|
254
266
|
`;
|
|
255
267
|
export const InnerContainer = styled(motion.div) `
|
|
256
268
|
position: relative;
|
|
@@ -258,6 +270,15 @@ export const InnerContainer = styled(motion.div) `
|
|
|
258
270
|
height: var(--height);
|
|
259
271
|
transition: 0.2s ease height;
|
|
260
272
|
@media only screen and (max-width: ${defaultTheme.mobileWidth}px) {
|
|
273
|
+
overflow-x: hidden;
|
|
274
|
+
overflow-y: auto;
|
|
275
|
+
height: min(var(--height, ${mobileModalMaxHeight}), ${mobileModalMaxHeight});
|
|
276
|
+
height: min(var(--height, ${mobileModalMaxHeightDynamic}), ${mobileModalMaxHeightDynamic});
|
|
277
|
+
max-height: ${mobileModalMaxHeight};
|
|
278
|
+
max-height: ${mobileModalMaxHeightDynamic};
|
|
279
|
+
overscroll-behavior: contain;
|
|
280
|
+
-webkit-overflow-scrolling: touch;
|
|
281
|
+
touch-action: pan-y;
|
|
261
282
|
transition: 0ms height cubic-bezier(0.15, 1.15, 0.6, 1);
|
|
262
283
|
/* animation-delay: 34ms; */
|
|
263
284
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { RouteConfig } from "../types/route-config";
|
|
2
|
-
import {
|
|
3
|
-
export declare const routeConfig: Record<
|
|
2
|
+
import { ROUTE } from "../types/routes";
|
|
3
|
+
export declare const routeConfig: Record<ROUTE, RouteConfig>;
|