@hot-labs/kit 1.1.0-beta.3 → 1.1.0-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.
- package/build/OmniConnector.d.ts +1 -0
- package/build/OmniConnector.js.map +1 -1
- package/build/core/Intents.d.ts +18 -0
- package/build/core/Intents.js +19 -2
- package/build/core/Intents.js.map +1 -1
- package/build/core/api.d.ts +16 -1
- package/build/core/api.js +14 -4
- package/build/core/api.js.map +1 -1
- package/build/cosmos/connector.d.ts +2 -2
- package/build/cosmos/connector.js +15 -19
- package/build/cosmos/connector.js.map +1 -1
- package/build/cosmos/wallet.js.map +1 -1
- package/build/exchange.js +1 -5
- package/build/exchange.js.map +1 -1
- package/build/ui/Popup.d.ts +1 -1
- package/build/ui/Popup.js +1 -1
- package/build/ui/Popup.js.map +1 -1
- package/build/ui/payment/Payment.d.ts +7 -15
- package/build/ui/payment/Payment.js +45 -56
- package/build/ui/payment/Payment.js.map +1 -1
- package/build/ui/payment/Stepper.d.ts +13 -0
- package/build/ui/payment/Stepper.js +22 -0
- package/build/ui/payment/Stepper.js.map +1 -0
- package/build/ui/router.d.ts +6 -3
- package/build/ui/router.js +7 -7
- package/build/ui/router.js.map +1 -1
- package/package.json +1 -1
- package/src/OmniConnector.ts +1 -0
- package/src/core/Intents.ts +20 -2
- package/src/core/api.ts +26 -4
- package/src/cosmos/connector.ts +20 -24
- package/src/cosmos/wallet.ts +0 -1
- package/src/exchange.ts +2 -5
- package/src/ui/Popup.tsx +7 -4
- package/src/ui/payment/Payment.tsx +77 -102
- package/src/ui/payment/Stepper.tsx +50 -0
- package/src/ui/router.tsx +15 -12
package/src/ui/Popup.tsx
CHANGED
|
@@ -22,7 +22,7 @@ interface PopupProps {
|
|
|
22
22
|
widget?: boolean;
|
|
23
23
|
children: React.ReactNode;
|
|
24
24
|
header?: React.ReactNode;
|
|
25
|
-
onClose
|
|
25
|
+
onClose?: () => void;
|
|
26
26
|
style?: React.CSSProperties;
|
|
27
27
|
mobileFullscreen?: boolean;
|
|
28
28
|
}
|
|
@@ -57,9 +57,12 @@ const Popup = ({ widget, children, header, onClose, style, mobileFullscreen }: P
|
|
|
57
57
|
<ModalContent ref={contentRef} $mobileFullscreen={mobileFullscreen} style={{ opacity: 0, transform: "translateY(20px)", transition: "all 0.2s ease-in-out" }}>
|
|
58
58
|
{header && (
|
|
59
59
|
<ModalHeader>
|
|
60
|
-
|
|
61
|
-
<
|
|
62
|
-
|
|
60
|
+
{onClose != null && (
|
|
61
|
+
<button onClick={onClose} style={{ position: "absolute", right: 16, top: 16 }}>
|
|
62
|
+
<CloseIcon />
|
|
63
|
+
</button>
|
|
64
|
+
)}
|
|
65
|
+
|
|
63
66
|
{header}
|
|
64
67
|
</ModalHeader>
|
|
65
68
|
)}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { observer } from "mobx-react-lite";
|
|
2
|
-
import
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
3
|
|
|
4
|
+
import { WalletIcon } from "../icons/wallet";
|
|
5
|
+
import { PopupButton, PopupOption, PopupOptionInfo } from "../styles";
|
|
4
6
|
import { Commitment, formatter, Intents } from "../../core";
|
|
5
7
|
import { Recipient } from "../../core/recipient";
|
|
6
8
|
import { Network } from "../../core/chains";
|
|
@@ -15,15 +17,15 @@ import { HotConnector } from "../../HotConnector";
|
|
|
15
17
|
import Popup from "../Popup";
|
|
16
18
|
|
|
17
19
|
import { TokenCard, TokenIcon } from "./TokenCard";
|
|
18
|
-
import {
|
|
19
|
-
import { WalletIcon } from "../icons/wallet";
|
|
20
|
+
import { HorizontalStepper } from "./Stepper";
|
|
20
21
|
import { Loader } from "./Profile";
|
|
21
22
|
|
|
22
23
|
interface PaymentProps {
|
|
23
24
|
intents: Intents;
|
|
24
25
|
connector: HotConnector;
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
payload?: Record<string, any>;
|
|
27
|
+
onReject: (message: string) => void;
|
|
28
|
+
onSuccess: (task: { paymentId: string; tx: string }) => void;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
const animations = {
|
|
@@ -32,56 +34,9 @@ const animations = {
|
|
|
32
34
|
loading: "https://hex.exchange/loading.json",
|
|
33
35
|
};
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
label: string;
|
|
37
|
-
completed?: boolean;
|
|
38
|
-
active?: boolean;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface StepperProps {
|
|
42
|
-
steps: Step[];
|
|
43
|
-
currentStep: number;
|
|
44
|
-
style?: React.CSSProperties;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const HorizontalStepper: React.FC<StepperProps> = ({ steps, currentStep, style }) => {
|
|
48
|
-
return (
|
|
49
|
-
<div style={{ padding: "0 32px 32px", display: "flex", alignItems: "center", width: "100%", margin: "16px 0", ...style }}>
|
|
50
|
-
{steps.map((step, idx) => {
|
|
51
|
-
const isCompleted = idx < currentStep;
|
|
52
|
-
const isActive = idx === currentStep;
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<React.Fragment key={idx}>
|
|
56
|
-
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
57
|
-
<div
|
|
58
|
-
style={{
|
|
59
|
-
width: 16,
|
|
60
|
-
height: 16,
|
|
61
|
-
position: "relative",
|
|
62
|
-
borderRadius: "50%",
|
|
63
|
-
border: isActive || isCompleted ? "2px solid #ffffff" : "2px solid #a0a0a0",
|
|
64
|
-
background: isCompleted ? "#ffffff" : "#333",
|
|
65
|
-
display: "flex",
|
|
66
|
-
alignItems: "center",
|
|
67
|
-
justifyContent: "center",
|
|
68
|
-
transition: "all 0.2s",
|
|
69
|
-
zIndex: 1,
|
|
70
|
-
}}
|
|
71
|
-
>
|
|
72
|
-
<p style={{ fontSize: 16, color: "#fff", opacity: isActive ? 1 : 0.5, position: "absolute", top: 24, width: 100 }}>{step.label}</p>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
|
|
76
|
-
{idx < steps.length - 1 && <div style={{ transition: "background 0.2s", flex: 1, height: 2, background: idx < currentStep ? "#ffffff" : "#333", margin: "0 6px", borderRadius: 24, minWidth: 24 }} />}
|
|
77
|
-
</React.Fragment>
|
|
78
|
-
);
|
|
79
|
-
})}
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
82
|
-
};
|
|
37
|
+
const PAY_SLIPPAGE = 0.002;
|
|
83
38
|
|
|
84
|
-
export const Payment = observer(({ connector, intents,
|
|
39
|
+
export const Payment = observer(({ connector, intents, payload, onReject, onSuccess }: PaymentProps) => {
|
|
85
40
|
useState(() => {
|
|
86
41
|
fetch(animations.loading);
|
|
87
42
|
fetch(animations.success);
|
|
@@ -97,8 +52,8 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
97
52
|
token?: Token;
|
|
98
53
|
wallet?: OmniWallet;
|
|
99
54
|
commitment?: Commitment;
|
|
100
|
-
review?: BridgeReview;
|
|
101
|
-
|
|
55
|
+
review?: BridgeReview | "direct";
|
|
56
|
+
data?: { paymentId: string; tx: string };
|
|
102
57
|
step?: "selectToken" | "sign" | "transfer" | "success" | "error" | "loading";
|
|
103
58
|
success?: boolean;
|
|
104
59
|
loading?: boolean;
|
|
@@ -112,25 +67,36 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
112
67
|
const selectToken = async (from: Token, wallet?: OmniWallet) => {
|
|
113
68
|
if (!wallet) return;
|
|
114
69
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
70
|
+
// Set signer as payer wallet if not set another
|
|
71
|
+
if (!intents.signer) intents.attachWallet(wallet);
|
|
72
|
+
|
|
73
|
+
if (from.id === need.id) {
|
|
74
|
+
return setFlow({ token: from, wallet, review: "direct", step: "sign" });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
setFlow({ token: from, wallet, review: undefined, step: "sign" });
|
|
79
|
+
const review = await connector.exchange.reviewSwap({
|
|
80
|
+
recipient: Recipient.fromWallet(intents.signer)!,
|
|
81
|
+
amount: needAmount + (needAmount * BigInt(Math.floor(PAY_SLIPPAGE * 1000))) / BigInt(1000),
|
|
82
|
+
slippage: PAY_SLIPPAGE,
|
|
83
|
+
sender: wallet,
|
|
84
|
+
refund: wallet,
|
|
85
|
+
type: "exactOut",
|
|
86
|
+
to: need,
|
|
87
|
+
from,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
setFlow({ token: from, wallet, review, step: "sign" });
|
|
91
|
+
} catch {
|
|
92
|
+
setFlow({ token: from, wallet, error: true, step: "sign" });
|
|
93
|
+
}
|
|
128
94
|
};
|
|
129
95
|
|
|
130
96
|
const signStep = async () => {
|
|
131
97
|
try {
|
|
132
98
|
setFlow((t) => (t ? { ...t, step: "sign", loading: true } : null));
|
|
133
|
-
const commitment = await intents.
|
|
99
|
+
const commitment = await intents.sign();
|
|
134
100
|
setFlow((t) => (t ? { ...t, step: "transfer", commitment, loading: false } : null));
|
|
135
101
|
} catch (error) {
|
|
136
102
|
console.error(error);
|
|
@@ -144,19 +110,17 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
144
110
|
const commitment = flow?.commitment;
|
|
145
111
|
if (!commitment) throw new Error("Commitment not found");
|
|
146
112
|
if (!flow?.review) throw new Error("Review not found");
|
|
147
|
-
|
|
148
113
|
setFlow((t) => (t ? { ...t, step: "loading" } : null));
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
} else {
|
|
156
|
-
const hash = await Intents.publish([commitment]);
|
|
157
|
-
setFlow((t) => (t ? { ...t, step: "success", loading: false, success: true } : null));
|
|
158
|
-
return { hash };
|
|
114
|
+
|
|
115
|
+
// make swap if need
|
|
116
|
+
let depositAddress: string | undefined;
|
|
117
|
+
if (flow.review != "direct") {
|
|
118
|
+
const result = await connector.exchange.makeSwap(flow.review, { log: () => {} });
|
|
119
|
+
depositAddress = typeof result.review?.qoute === "object" ? result.review?.qoute?.depositAddress : undefined;
|
|
159
120
|
}
|
|
121
|
+
|
|
122
|
+
const data = await api.yieldIntentCall({ depositAddress, commitment, payload });
|
|
123
|
+
setFlow((t) => (t ? { ...t, step: "success", loading: false, success: true, data } : null));
|
|
160
124
|
} catch (error) {
|
|
161
125
|
console.error(error);
|
|
162
126
|
setFlow((t) => (t ? { ...t, step: "error", loading: false, error } : null));
|
|
@@ -166,13 +130,13 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
166
130
|
|
|
167
131
|
if (flow?.step === "success") {
|
|
168
132
|
return (
|
|
169
|
-
<Popup
|
|
133
|
+
<Popup header={<p>{title}</p>}>
|
|
170
134
|
<div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
|
|
171
135
|
{/* @ts-expect-error: dotlottie-wc is not typed */}
|
|
172
136
|
<dotlottie-wc key="success" src={animations.success} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
|
|
173
137
|
<p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Payment successful</p>
|
|
174
138
|
</div>
|
|
175
|
-
<PopupButton style={{ marginTop: "auto" }} onClick={() =>
|
|
139
|
+
<PopupButton style={{ marginTop: "auto" }} onClick={() => onSuccess(flow.data!)}>
|
|
176
140
|
Continue
|
|
177
141
|
</PopupButton>
|
|
178
142
|
</Popup>
|
|
@@ -181,7 +145,7 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
181
145
|
|
|
182
146
|
if (flow?.step === "loading") {
|
|
183
147
|
return (
|
|
184
|
-
<Popup
|
|
148
|
+
<Popup header={<p>{title}</p>}>
|
|
185
149
|
<div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
|
|
186
150
|
{/* @ts-expect-error: dotlottie-wc is not typed */}
|
|
187
151
|
<dotlottie-wc key="loading" src={animations.loading} speed="1" style={{ marginTop: -64, width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
|
|
@@ -193,14 +157,14 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
193
157
|
|
|
194
158
|
if (flow?.step === "error") {
|
|
195
159
|
return (
|
|
196
|
-
<Popup
|
|
160
|
+
<Popup header={<p>{title}</p>}>
|
|
197
161
|
<div style={{ width: "100%", height: 400, gap: 8, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
|
|
198
162
|
{/* @ts-expect-error: dotlottie-wc is not typed */}
|
|
199
163
|
<dotlottie-wc key="error" src={animations.failed} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
|
|
200
164
|
<p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Payment failed</p>
|
|
201
|
-
<p style={{ fontSize: 14 }}>{flow.error?.toString?.() ?? "Unknown error"}</p>
|
|
165
|
+
<p style={{ fontSize: 14, width: "80%", textAlign: "center", overflowY: "auto", lineBreak: "anywhere" }}>{flow.error?.toString?.() ?? "Unknown error"}</p>
|
|
202
166
|
</div>
|
|
203
|
-
<PopupButton onClick={() =>
|
|
167
|
+
<PopupButton onClick={() => onReject(flow.error?.toString?.() ?? "Unknown error")}>Close</PopupButton>
|
|
204
168
|
</Popup>
|
|
205
169
|
);
|
|
206
170
|
}
|
|
@@ -209,7 +173,7 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
209
173
|
if (!flow.token) return null;
|
|
210
174
|
if (!flow.wallet) return null;
|
|
211
175
|
return (
|
|
212
|
-
<Popup onClose={
|
|
176
|
+
<Popup onClose={() => onReject("closed")} header={<p>{title}</p>}>
|
|
213
177
|
<HorizontalStepper steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={2} />
|
|
214
178
|
|
|
215
179
|
<PopupOption style={{ marginTop: 8 }}>
|
|
@@ -222,8 +186,8 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
222
186
|
|
|
223
187
|
{flow.review ? (
|
|
224
188
|
<div style={{ paddingRight: 4, marginLeft: "auto", alignItems: "flex-end" }}>
|
|
225
|
-
<p style={{ textAlign: "right", fontSize: 20 }}>{flow.token.readable(flow.review?.amountIn ?? 0)}</p>
|
|
226
|
-
<p style={{ textAlign: "right", fontSize: 14, color: "#c6c6c6" }}>${flow.token.readable(flow.review?.amountIn ?? 0n, flow.token.usd)}</p>
|
|
189
|
+
<p style={{ textAlign: "right", fontSize: 20 }}>{flow.token.readable(flow.review === "direct" ? needAmount : flow.review?.amountIn ?? 0)}</p>
|
|
190
|
+
<p style={{ textAlign: "right", fontSize: 14, color: "#c6c6c6" }}>${flow.token.readable(flow.review === "direct" ? needAmount : flow.review?.amountIn ?? 0n, flow.token.usd)}</p>
|
|
227
191
|
</div>
|
|
228
192
|
) : (
|
|
229
193
|
<div style={{ paddingRight: 4, marginLeft: "auto", alignItems: "flex-end" }}>
|
|
@@ -232,7 +196,7 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
232
196
|
)}
|
|
233
197
|
</PopupOption>
|
|
234
198
|
|
|
235
|
-
<PopupButton style={{ marginTop: 24 }} disabled={!flow?.review} onClick={
|
|
199
|
+
<PopupButton style={{ marginTop: 24 }} disabled={!flow?.review} onClick={confirmPaymentStep}>
|
|
236
200
|
{flow?.loading ? "Confirming..." : "Confirm payment"}
|
|
237
201
|
</PopupButton>
|
|
238
202
|
</Popup>
|
|
@@ -243,7 +207,7 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
243
207
|
if (!flow.token) return null;
|
|
244
208
|
if (!flow.wallet) return null;
|
|
245
209
|
return (
|
|
246
|
-
<Popup onClose={
|
|
210
|
+
<Popup onClose={() => onReject("closed")} header={<p>{title}</p>}>
|
|
247
211
|
<HorizontalStepper steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={1} />
|
|
248
212
|
|
|
249
213
|
<PopupOption style={{ marginTop: 8 }}>
|
|
@@ -256,40 +220,51 @@ export const Payment = observer(({ connector, intents, onClose, onConfirm }: Pay
|
|
|
256
220
|
|
|
257
221
|
{flow.review ? (
|
|
258
222
|
<div style={{ paddingRight: 4, marginLeft: "auto", alignItems: "flex-end" }}>
|
|
259
|
-
<p style={{ textAlign: "right", fontSize: 20 }}>{flow.token.readable(flow.review?.amountIn ?? 0)}</p>
|
|
260
|
-
<p style={{ textAlign: "right", fontSize: 14, color: "#c6c6c6" }}>${flow.token.readable(flow.review?.amountIn ?? 0n, flow.token.usd)}</p>
|
|
223
|
+
<p style={{ textAlign: "right", fontSize: 20 }}>{flow.token.readable(flow.review === "direct" ? needAmount : flow.review?.amountIn ?? 0)}</p>
|
|
224
|
+
<p style={{ textAlign: "right", fontSize: 14, color: "#c6c6c6" }}>${flow.token.readable(flow.review === "direct" ? needAmount : flow.review?.amountIn ?? 0n, flow.token.usd)}</p>
|
|
261
225
|
</div>
|
|
262
226
|
) : (
|
|
263
227
|
<div style={{ paddingRight: 4, marginLeft: "auto", alignItems: "flex-end" }}>
|
|
264
|
-
|
|
228
|
+
{flow.error ? (
|
|
229
|
+
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Failed" style={{ display: "block", margin: "0 auto" }}>
|
|
230
|
+
<circle cx="14" cy="14" r="13" stroke="#E74C3C" strokeWidth="2" />
|
|
231
|
+
<path d="M9 9l10 10M19 9l-10 10" stroke="#E74C3C" strokeWidth="2.5" strokeLinecap="round" />
|
|
232
|
+
</svg>
|
|
233
|
+
) : (
|
|
234
|
+
<Loader />
|
|
235
|
+
)}
|
|
265
236
|
</div>
|
|
266
237
|
)}
|
|
267
238
|
</PopupOption>
|
|
268
239
|
|
|
269
|
-
|
|
270
|
-
{
|
|
271
|
-
|
|
240
|
+
{flow.error ? (
|
|
241
|
+
<PopupButton style={{ marginTop: 24 }} onClick={() => setFlow(null)}>
|
|
242
|
+
Select another token
|
|
243
|
+
</PopupButton>
|
|
244
|
+
) : (
|
|
245
|
+
<PopupButton style={{ marginTop: 24 }} disabled={!flow?.review} onClick={signStep}>
|
|
246
|
+
{flow?.loading ? "Signing..." : flow?.review ? "Sign review" : "Quoting..."}
|
|
247
|
+
</PopupButton>
|
|
248
|
+
)}
|
|
272
249
|
</Popup>
|
|
273
250
|
);
|
|
274
251
|
}
|
|
275
252
|
|
|
276
253
|
return (
|
|
277
|
-
<Popup onClose={
|
|
254
|
+
<Popup onClose={() => onReject("closed")} header={<p>{title}</p>}>
|
|
278
255
|
<HorizontalStepper steps={[{ label: "Select" }, { label: "Review" }, { label: "Confirm" }]} currentStep={0} />
|
|
279
256
|
|
|
280
257
|
{connector.walletsTokens.map(({ token, wallet, balance }) => {
|
|
281
|
-
if (token.id === need.id) return null;
|
|
282
258
|
const availableBalance = token.float(balance) - token.reserve;
|
|
283
259
|
|
|
284
260
|
if (need.originalChain === Network.Gonka || need.originalChain === Network.Juno) {
|
|
285
261
|
if (token.id === need.id) return null;
|
|
286
262
|
if (token.originalAddress !== need.originalAddress) return null;
|
|
287
|
-
|
|
288
263
|
if (availableBalance < need.float(needAmount)) return null;
|
|
289
264
|
return <TokenCard key={token.id} token={token} onSelect={selectToken} hot={connector} wallet={wallet} />;
|
|
290
265
|
}
|
|
291
266
|
|
|
292
|
-
if (availableBalance * token.usd <= need.usd * need.float(needAmount)) return null;
|
|
267
|
+
if (availableBalance * token.usd <= need.usd * need.float(needAmount) * (1 + PAY_SLIPPAGE)) return null;
|
|
293
268
|
return <TokenCard key={token.id} token={token} onSelect={selectToken} hot={connector} wallet={wallet} />;
|
|
294
269
|
})}
|
|
295
270
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
interface Step {
|
|
4
|
+
label: string;
|
|
5
|
+
completed?: boolean;
|
|
6
|
+
active?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface StepperProps {
|
|
10
|
+
steps: Step[];
|
|
11
|
+
currentStep: number;
|
|
12
|
+
style?: React.CSSProperties;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const HorizontalStepper: React.FC<StepperProps> = ({ steps, currentStep, style }) => {
|
|
16
|
+
return (
|
|
17
|
+
<div style={{ padding: "0 32px 32px", display: "flex", alignItems: "center", width: "100%", margin: "16px 0", ...style }}>
|
|
18
|
+
{steps.map((step, idx) => {
|
|
19
|
+
const isCompleted = idx < currentStep;
|
|
20
|
+
const isActive = idx === currentStep;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<React.Fragment key={idx}>
|
|
24
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
25
|
+
<div
|
|
26
|
+
style={{
|
|
27
|
+
width: 16,
|
|
28
|
+
height: 16,
|
|
29
|
+
position: "relative",
|
|
30
|
+
borderRadius: "50%",
|
|
31
|
+
border: isActive || isCompleted ? "2px solid #ffffff" : "2px solid #a0a0a0",
|
|
32
|
+
background: isCompleted ? "#ffffff" : "#333",
|
|
33
|
+
display: "flex",
|
|
34
|
+
alignItems: "center",
|
|
35
|
+
justifyContent: "center",
|
|
36
|
+
transition: "all 0.2s",
|
|
37
|
+
zIndex: 1,
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<p style={{ fontSize: 16, color: "#fff", opacity: isActive ? 1 : 0.5, position: "absolute", top: 24, width: 100 }}>{step.label}</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
{idx < steps.length - 1 && <div style={{ transition: "background 0.2s", flex: 1, height: 2, background: idx < currentStep ? "#ffffff" : "#333", margin: "0 6px", borderRadius: 24, minWidth: 24 }} />}
|
|
45
|
+
</React.Fragment>
|
|
46
|
+
);
|
|
47
|
+
})}
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
package/src/ui/router.tsx
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
import { HotConnector } from "../HotConnector";
|
|
2
2
|
import { OmniConnector } from "../OmniConnector";
|
|
3
|
-
import { BridgeReview } from "../exchange";
|
|
4
|
-
import { Token } from "../core/token";
|
|
5
3
|
import { OmniWallet } from "../OmniWallet";
|
|
4
|
+
|
|
5
|
+
import { BridgeReview } from "../exchange";
|
|
6
6
|
import { WalletType } from "../core/chains";
|
|
7
7
|
import { Recipient } from "../core/recipient";
|
|
8
8
|
import { Intents } from "../core/Intents";
|
|
9
|
+
import { Token } from "../core/token";
|
|
9
10
|
|
|
10
11
|
import { present } from "./Popup";
|
|
12
|
+
import { SelectTokenPopup } from "./payment/SelectToken";
|
|
13
|
+
import { SelectRecipient } from "./payment/SelectRecipient";
|
|
14
|
+
import { SelectSender } from "./payment/SelectSender";
|
|
15
|
+
import { BridgeProps } from "./payment/Bridge";
|
|
11
16
|
import { Payment } from "./payment/Payment";
|
|
12
|
-
import { LogoutPopup } from "./connect/LogoutPopup";
|
|
13
|
-
import { Bridge } from "./payment/Bridge";
|
|
14
17
|
import { Profile } from "./payment/Profile";
|
|
15
|
-
import {
|
|
18
|
+
import { Bridge } from "./payment/Bridge";
|
|
19
|
+
|
|
20
|
+
import { LogoutPopup } from "./connect/LogoutPopup";
|
|
16
21
|
import { WalletPicker } from "./connect/WalletPicker";
|
|
17
|
-
import { BridgeProps } from "./payment/Bridge";
|
|
18
22
|
import { Connector } from "./connect/ConnectWallet";
|
|
19
|
-
import { SelectSender } from "./payment/SelectSender";
|
|
20
|
-
import { SelectRecipient } from "./payment/SelectRecipient";
|
|
21
23
|
import { WCRequest } from "./connect/WCRequest";
|
|
22
24
|
|
|
23
|
-
export const openPayment = (connector: HotConnector, intents: Intents) => {
|
|
24
|
-
return new Promise<
|
|
25
|
+
export const openPayment = (connector: HotConnector, intents: Intents, payload?: Record<string, any>) => {
|
|
26
|
+
return new Promise<{ paymentId: string; tx: string }>((resolve, reject) => {
|
|
25
27
|
present((close) => (
|
|
26
28
|
<Payment //
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
onReject={() => (close(), reject(new Error("User rejected")))}
|
|
30
|
+
onSuccess={(task) => (close(), resolve(task))}
|
|
29
31
|
connector={connector}
|
|
30
32
|
intents={intents}
|
|
33
|
+
payload={payload}
|
|
31
34
|
/>
|
|
32
35
|
));
|
|
33
36
|
});
|