@0xsquid/deposit-widget 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +4062 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.esm.js +4042 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/types/DepositWidget.d.ts +7 -0
- package/dist/types/components/ViewTransition.d.ts +7 -0
- package/dist/types/components/shared/buttons/button.d.ts +3 -0
- package/dist/types/components/shared/icons/types.d.ts +3 -0
- package/dist/types/components/shared/icons/user-round.d.ts +2 -0
- package/dist/types/components/shared/navigation/base-navbar.d.ts +3 -0
- package/dist/types/components/shared/navigation/sub-navbar.d.ts +6 -0
- package/dist/types/components/token-badge-icon.d.ts +6 -0
- package/dist/types/components/token-list-item.d.ts +13 -0
- package/dist/types/components/view-container.d.ts +1 -0
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/hooks/ui/useMainCTAButtonState.d.ts +8 -0
- package/dist/types/hooks/use-auto-select-token.d.ts +1 -0
- package/dist/types/hooks/use-deposit-route.d.ts +7 -0
- package/dist/types/hooks/use-token-selection.d.ts +5 -0
- package/dist/types/hooks/use-transaction-history.d.ts +6 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/services/assets-service.d.ts +6 -0
- package/dist/types/services/wallet-history/format.d.ts +10 -0
- package/dist/types/services/wallet-history/format.test.d.ts +1 -0
- package/dist/types/services/wallet-history/get-main-explorer-url.d.ts +23 -0
- package/dist/types/services/wallet-history/get-wallet-history.d.ts +2 -0
- package/dist/types/services/wallet-history/types.d.ts +66 -0
- package/dist/types/services/wallet-history/validation.d.ts +2 -0
- package/dist/types/store/use-deposit-store.d.ts +9 -0
- package/dist/types/store/use-input-mode.d.ts +5 -0
- package/dist/types/store/useRouter.d.ts +12 -0
- package/dist/types/types.d.ts +43 -0
- package/dist/types/utils/format-date.d.ts +2 -0
- package/dist/types/utils/format-date.test.d.ts +1 -0
- package/dist/types/utils/transaction.d.ts +10 -0
- package/dist/types/views/connect-wallet/connect-wallet-view.d.ts +6 -0
- package/dist/types/views/connect-wallet/wallet-list-item.d.ts +9 -0
- package/dist/types/views/main/amount-input.d.ts +10 -0
- package/dist/types/views/main/connect-prompt.d.ts +1 -0
- package/dist/types/views/main/deposit-amount-input.d.ts +1 -0
- package/dist/types/views/main/deposit-form.d.ts +1 -0
- package/dist/types/views/main/main-cta-button.d.ts +1 -0
- package/dist/types/views/main/main-view.d.ts +1 -0
- package/dist/types/views/main/navbar/actions.d.ts +1 -0
- package/dist/types/views/main/navbar/icon.d.ts +1 -0
- package/dist/types/views/main/navbar/navbar.d.ts +1 -0
- package/dist/types/views/main/navbar/title.d.ts +10 -0
- package/dist/types/views/main/recipient/account.d.ts +14 -0
- package/dist/types/views/main/recipient/recipient.d.ts +1 -0
- package/dist/types/views/main/token-selector.d.ts +1 -0
- package/dist/types/views/qr-code.d.ts +1 -0
- package/dist/types/views/render-view.d.ts +3 -0
- package/dist/types/views/select-chain/chain-type-meta.d.ts +7 -0
- package/dist/types/views/select-chain/select-chain-view.d.ts +6 -0
- package/dist/types/views/select-token.d.ts +1 -0
- package/dist/types/views/transaction-history/activity-list-item.d.ts +4 -0
- package/dist/types/views/transaction-history/transaction-history-view.d.ts +1 -0
- package/dist/types/views/transaction-progress/helpers.d.ts +14 -0
- package/dist/types/views/transaction-progress/transaction-progress-view.d.ts +1 -0
- package/dist/types/views/transaction-progress/use-transaction-progress.d.ts +17 -0
- package/package.json +99 -0
- package/src/DepositWidget.tsx +158 -0
- package/src/compiled-tailwind.css +6100 -0
- package/src/components/ViewTransition.tsx +81 -0
- package/src/components/shared/buttons/button.tsx +17 -0
- package/src/components/shared/icons/types.ts +3 -0
- package/src/components/shared/icons/user-round.tsx +21 -0
- package/src/components/shared/navigation/base-navbar.tsx +15 -0
- package/src/components/shared/navigation/sub-navbar.tsx +46 -0
- package/src/components/token-badge-icon.tsx +31 -0
- package/src/components/token-list-item.tsx +84 -0
- package/src/components/view-container.tsx +16 -0
- package/src/constants.ts +1 -0
- package/src/css.d.ts +4 -0
- package/src/fonts/DMSans-Variable.woff2 +0 -0
- package/src/hooks/ui/useMainCTAButtonState.ts +143 -0
- package/src/hooks/use-auto-select-token.ts +65 -0
- package/src/hooks/use-deposit-route.ts +58 -0
- package/src/hooks/use-token-selection.ts +17 -0
- package/src/hooks/use-transaction-history.ts +198 -0
- package/src/index.ts +3 -0
- package/src/services/assets-service.ts +21 -0
- package/src/services/wallet-history/format.test.ts +63 -0
- package/src/services/wallet-history/format.ts +128 -0
- package/src/services/wallet-history/get-main-explorer-url.ts +74 -0
- package/src/services/wallet-history/get-wallet-history.ts +24 -0
- package/src/services/wallet-history/types.ts +66 -0
- package/src/services/wallet-history/validation.ts +60 -0
- package/src/store/use-deposit-store.ts +20 -0
- package/src/store/use-input-mode.ts +10 -0
- package/src/store/useRouter.ts +49 -0
- package/src/tailwind.css +16 -0
- package/src/types.ts +39 -0
- package/src/utils/format-date.test.ts +32 -0
- package/src/utils/format-date.ts +25 -0
- package/src/utils/transaction.ts +39 -0
- package/src/views/connect-wallet/connect-wallet-view.tsx +147 -0
- package/src/views/connect-wallet/wallet-list-item.tsx +69 -0
- package/src/views/main/amount-input.tsx +272 -0
- package/src/views/main/connect-prompt.tsx +47 -0
- package/src/views/main/deposit-amount-input.tsx +42 -0
- package/src/views/main/deposit-form.tsx +13 -0
- package/src/views/main/main-cta-button.tsx +14 -0
- package/src/views/main/main-view.tsx +24 -0
- package/src/views/main/navbar/actions.tsx +25 -0
- package/src/views/main/navbar/icon.tsx +11 -0
- package/src/views/main/navbar/navbar.tsx +16 -0
- package/src/views/main/navbar/title.tsx +64 -0
- package/src/views/main/recipient/account.tsx +81 -0
- package/src/views/main/recipient/recipient.tsx +64 -0
- package/src/views/main/token-selector.tsx +77 -0
- package/src/views/qr-code.tsx +14 -0
- package/src/views/render-view.tsx +28 -0
- package/src/views/select-chain/chain-type-meta.ts +37 -0
- package/src/views/select-chain/select-chain-view.tsx +97 -0
- package/src/views/select-token.tsx +227 -0
- package/src/views/transaction-history/activity-list-item.tsx +87 -0
- package/src/views/transaction-history/transaction-history-view.tsx +58 -0
- package/src/views/transaction-progress/helpers.tsx +93 -0
- package/src/views/transaction-progress/transaction-progress-view.tsx +217 -0
- package/src/views/transaction-progress/use-transaction-progress.ts +112 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useSwap } from "@0xsquid/react-hooks";
|
|
2
|
+
import {
|
|
3
|
+
useDepositStore,
|
|
4
|
+
useIsPaymentMode,
|
|
5
|
+
usePaymentAmount,
|
|
6
|
+
} from "../../store/use-deposit-store";
|
|
7
|
+
import { buildTitleLabel } from "./navbar/title";
|
|
8
|
+
|
|
9
|
+
export function ConnectPrompt() {
|
|
10
|
+
const isPaymentMode = useIsPaymentMode();
|
|
11
|
+
const logoUrl = useDepositStore((s) => s.config?.integrator.logoUrl);
|
|
12
|
+
const name = useDepositStore((s) => s.config?.integrator.name);
|
|
13
|
+
const paymentAmount = usePaymentAmount();
|
|
14
|
+
const { toToken } = useSwap();
|
|
15
|
+
|
|
16
|
+
const label = buildTitleLabel({
|
|
17
|
+
isPaymentMode,
|
|
18
|
+
paymentAmount,
|
|
19
|
+
tokenSymbol: toToken?.symbol,
|
|
20
|
+
tokenUsdPrice: toToken?.usdPrice,
|
|
21
|
+
name,
|
|
22
|
+
});
|
|
23
|
+
const purposeCopy = `To ${isPaymentMode ? "pay" : "deposit crypto"} you'll need to connect your wallet first.`;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className="tw-flex tw-pt-3 tw-pb-8 tw-px-4 tw-flex-col tw-justify-end tw-items-center tw-gap-4 tw-flex-1 tw-self-stretch tw-relative">
|
|
27
|
+
<div className="tw-w-32">
|
|
28
|
+
{logoUrl && <img className="tw-rounded-full tw-w-full" src={logoUrl} />}
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div className="tw-flex tw-pt-2 tw-pb-4 tw-flex-col tw-justify-end tw-items-center tw-gap-4 tw-self-center">
|
|
32
|
+
<span className="tw-text-grey-100 tw-font-medium tw-text-2xl tw-leading-3">
|
|
33
|
+
{label}
|
|
34
|
+
</span>
|
|
35
|
+
|
|
36
|
+
<span className="tw-text-center tw-text-material-light-average tw-font-medium tw-leading-6 tw-text-lg tw-text-balance">
|
|
37
|
+
{purposeCopy}
|
|
38
|
+
</span>
|
|
39
|
+
|
|
40
|
+
{/* TODO: add link? remove? */}
|
|
41
|
+
<span className="tw-text-material-light-thick tw-font-medium tw-leading-3 tw-text-lg">
|
|
42
|
+
Learn more
|
|
43
|
+
</span>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { convertTokenAmountToUSD, useSwap } from "@0xsquid/react-hooks";
|
|
2
|
+
import { useDepositRoute } from "../../hooks/use-deposit-route";
|
|
3
|
+
import { useTokenSelection } from "../../hooks/use-token-selection";
|
|
4
|
+
import {
|
|
5
|
+
useIsPaymentMode,
|
|
6
|
+
usePaymentAmount,
|
|
7
|
+
} from "../../store/use-deposit-store";
|
|
8
|
+
import { AmountInput } from "./amount-input";
|
|
9
|
+
|
|
10
|
+
export function DepositAmountInput() {
|
|
11
|
+
const { token, balance } = useTokenSelection();
|
|
12
|
+
const { fromAmount, fromAmountChanged, toToken } = useSwap();
|
|
13
|
+
const isPaymentMode = useIsPaymentMode();
|
|
14
|
+
const paymentAmount = usePaymentAmount();
|
|
15
|
+
const { quotedSourceAmount, routeErrorMessage, showLoading } =
|
|
16
|
+
useDepositRoute();
|
|
17
|
+
|
|
18
|
+
const displayedAmount = isPaymentMode ? quotedSourceAmount : fromAmount;
|
|
19
|
+
|
|
20
|
+
const forcedUsdDisplay =
|
|
21
|
+
isPaymentMode && paymentAmount && toToken?.usdPrice
|
|
22
|
+
? convertTokenAmountToUSD(paymentAmount, toToken.usdPrice)
|
|
23
|
+
: undefined;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<AmountInput
|
|
27
|
+
onAmountChange={fromAmountChanged}
|
|
28
|
+
balance={balance}
|
|
29
|
+
forcedAmount={displayedAmount}
|
|
30
|
+
forcedUsdDisplay={forcedUsdDisplay}
|
|
31
|
+
allowMaxButton={!isPaymentMode}
|
|
32
|
+
readOnly={isPaymentMode}
|
|
33
|
+
loading={isPaymentMode && showLoading}
|
|
34
|
+
errorMessage={routeErrorMessage}
|
|
35
|
+
token={{
|
|
36
|
+
decimals: token?.decimals ?? 0,
|
|
37
|
+
symbol: token?.symbol ?? "",
|
|
38
|
+
price: token?.usdPrice ?? 0,
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DepositAmountInput } from "./deposit-amount-input";
|
|
2
|
+
import { Recipient } from "./recipient/recipient";
|
|
3
|
+
import { TokenSelector } from "./token-selector";
|
|
4
|
+
|
|
5
|
+
export function DepositForm() {
|
|
6
|
+
return (
|
|
7
|
+
<div className="tw-flex tw-pb-3 tw-pt-1 tw-flex-col tw-items-center tw-flex-1 tw-self-stretch tw-gap-2 tw-px-1">
|
|
8
|
+
<TokenSelector />
|
|
9
|
+
<DepositAmountInput />
|
|
10
|
+
<Recipient />
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Button } from "../../components/shared/buttons/button";
|
|
2
|
+
import { useMainCTAButtonState } from "../../hooks/ui/useMainCTAButtonState";
|
|
3
|
+
|
|
4
|
+
export function MainCTAButton() {
|
|
5
|
+
const { label, onClick, disabled } = useMainCTAButtonState();
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<footer className="tw-flex tw-h-16 tw-p-2 tw-items-start tw-shrink-0 tw-self-stretch">
|
|
9
|
+
<Button onClick={onClick} disabled={disabled}>
|
|
10
|
+
{label}
|
|
11
|
+
</Button>
|
|
12
|
+
</footer>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cn } from "@0xsquid/ui";
|
|
2
|
+
import { useWallet } from "@0xsquid/react-hooks";
|
|
3
|
+
import { ConnectPrompt } from "./connect-prompt";
|
|
4
|
+
import { DepositForm } from "./deposit-form";
|
|
5
|
+
import { MainCTAButton } from "./main-cta-button";
|
|
6
|
+
import { NavBar } from "./navbar/navbar";
|
|
7
|
+
import { ViewContainer } from "../../components/view-container";
|
|
8
|
+
|
|
9
|
+
export function MainView() {
|
|
10
|
+
const { connectedWallets } = useWallet();
|
|
11
|
+
const isConnected = connectedWallets.length > 0;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
{isConnected && <NavBar />}
|
|
16
|
+
|
|
17
|
+
<ViewContainer className={cn(!isConnected && "tw-border-t-0")}>
|
|
18
|
+
{isConnected ? <DepositForm /> : <ConnectPrompt />}
|
|
19
|
+
|
|
20
|
+
<MainCTAButton />
|
|
21
|
+
</ViewContainer>
|
|
22
|
+
</>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ClockOutlineIcon, IconButton } from "@0xsquid/ui";
|
|
2
|
+
import { useWallet } from "@0xsquid/react-hooks";
|
|
3
|
+
import { useRouter } from "../../../store/useRouter";
|
|
4
|
+
|
|
5
|
+
export function Actions() {
|
|
6
|
+
const push = useRouter((s) => s.push);
|
|
7
|
+
const { connectedWallets } = useWallet();
|
|
8
|
+
const isConnected = connectedWallets.length > 0;
|
|
9
|
+
|
|
10
|
+
if (!isConnected) return null;
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className="tw-flex tw-justify-end tw-items-center tw-gap-1">
|
|
14
|
+
<IconButton
|
|
15
|
+
onClick={() => push({ id: "transaction-history" })}
|
|
16
|
+
icon={
|
|
17
|
+
<ClockOutlineIcon
|
|
18
|
+
className="tw-text-material-light-thick"
|
|
19
|
+
size="1.5rem"
|
|
20
|
+
/>
|
|
21
|
+
}
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useDepositStore } from "../../../store/use-deposit-store";
|
|
2
|
+
|
|
3
|
+
export function Icon() {
|
|
4
|
+
const logoUrl = useDepositStore((s) => s.config?.integrator.logoUrl);
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<div className="tw-flex tw-size-10 tw-justify-center tw-items-center tw-rounded-squid-m tw-shadow-icon-light dark:tw-shadow-icon-dark tw-bg-grey-900">
|
|
8
|
+
{logoUrl && <img className="tw-rounded-full" src={logoUrl} />}
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Actions } from "./actions";
|
|
2
|
+
import { BaseNavBar } from "../../../components/shared/navigation/base-navbar";
|
|
3
|
+
import { Icon } from "./icon";
|
|
4
|
+
import { Title } from "./title";
|
|
5
|
+
|
|
6
|
+
export function NavBar() {
|
|
7
|
+
return (
|
|
8
|
+
<BaseNavBar className="tw-justify-between">
|
|
9
|
+
<Icon />
|
|
10
|
+
|
|
11
|
+
<Title />
|
|
12
|
+
|
|
13
|
+
<Actions />
|
|
14
|
+
</BaseNavBar>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
convertTokenAmountToUSD,
|
|
3
|
+
formatUsdAmount,
|
|
4
|
+
useSwap,
|
|
5
|
+
} from "@0xsquid/react-hooks";
|
|
6
|
+
import {
|
|
7
|
+
useDepositStore,
|
|
8
|
+
useIsPaymentMode,
|
|
9
|
+
usePaymentAmount,
|
|
10
|
+
} from "../../../store/use-deposit-store";
|
|
11
|
+
|
|
12
|
+
export function Title() {
|
|
13
|
+
const name = useDepositStore((s) => s.config?.integrator.name);
|
|
14
|
+
const isPaymentMode = useIsPaymentMode();
|
|
15
|
+
const paymentAmount = usePaymentAmount();
|
|
16
|
+
const { toToken } = useSwap();
|
|
17
|
+
|
|
18
|
+
const label = buildTitleLabel({
|
|
19
|
+
isPaymentMode,
|
|
20
|
+
paymentAmount,
|
|
21
|
+
tokenSymbol: toToken?.symbol,
|
|
22
|
+
tokenUsdPrice: toToken?.usdPrice,
|
|
23
|
+
name,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="tw-flex tw-py-1 tw-px-2 tw-items-center tw-gap-1 tw-flex-1 tw-self-stretch">
|
|
28
|
+
<span className="tw-text-grey-100 tw-text-lg tw-font-squid-main tw-font-medium">
|
|
29
|
+
{label}
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface TitleLabelInput {
|
|
36
|
+
isPaymentMode: boolean;
|
|
37
|
+
paymentAmount: string | null;
|
|
38
|
+
tokenSymbol: string | undefined;
|
|
39
|
+
tokenUsdPrice: number | undefined;
|
|
40
|
+
name: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function buildTitleLabel({
|
|
44
|
+
isPaymentMode,
|
|
45
|
+
paymentAmount,
|
|
46
|
+
tokenSymbol,
|
|
47
|
+
tokenUsdPrice,
|
|
48
|
+
name,
|
|
49
|
+
}: TitleLabelInput): string {
|
|
50
|
+
if (!isPaymentMode) return name ? `Deposit to ${name}` : "Deposit";
|
|
51
|
+
|
|
52
|
+
if (paymentAmount && tokenSymbol) {
|
|
53
|
+
const usdValue = tokenUsdPrice
|
|
54
|
+
? convertTokenAmountToUSD(paymentAmount, tokenUsdPrice)
|
|
55
|
+
: null;
|
|
56
|
+
|
|
57
|
+
const amount = usdValue
|
|
58
|
+
? formatUsdAmount(usdValue)
|
|
59
|
+
: `${paymentAmount} ${tokenSymbol}`;
|
|
60
|
+
return name ? `Pay ${amount} to ${name}` : `Pay ${amount}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return name ? `Pay ${name}` : "Pay";
|
|
64
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { cn, PowerIcon } from "@0xsquid/ui";
|
|
2
|
+
import { UserRoundIcon } from "../../../components/shared/icons/user-round";
|
|
3
|
+
|
|
4
|
+
interface AccountProps {
|
|
5
|
+
direction: "from" | "to";
|
|
6
|
+
name: string;
|
|
7
|
+
address: string;
|
|
8
|
+
icon?: string;
|
|
9
|
+
onDisconnect?: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Account({
|
|
13
|
+
direction,
|
|
14
|
+
address,
|
|
15
|
+
name,
|
|
16
|
+
icon,
|
|
17
|
+
onDisconnect,
|
|
18
|
+
}: AccountProps) {
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
{direction === "from" && (
|
|
22
|
+
<Avatar icon={icon} onDisconnect={onDisconnect} />
|
|
23
|
+
)}
|
|
24
|
+
|
|
25
|
+
<div
|
|
26
|
+
className={cn(
|
|
27
|
+
"tw-flex tw-flex-col tw-justify-center tw-gap-2 tw-flex-1 tw-self-stretch",
|
|
28
|
+
|
|
29
|
+
direction === "from" ? "tw-items-start" : "tw-items-end",
|
|
30
|
+
)}
|
|
31
|
+
>
|
|
32
|
+
<span className="tw-text-grey-100 tw-text-lg tw-leading-3">{name}</span>
|
|
33
|
+
|
|
34
|
+
<span className="tw-text-material-light-thick tw-text-sm tw-leading-3 tw-whitespace-nowrap">
|
|
35
|
+
{address}
|
|
36
|
+
</span>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
{direction === "to" && <Avatar icon={icon} />}
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface AvatarProps {
|
|
45
|
+
icon?: string;
|
|
46
|
+
onDisconnect?: () => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function Avatar({ icon, onDisconnect }: AvatarProps) {
|
|
50
|
+
const Wrapper = onDisconnect ? "button" : "div";
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Wrapper
|
|
54
|
+
onClick={onDisconnect}
|
|
55
|
+
className={cn(
|
|
56
|
+
"tw-group/avatar tw-relative tw-flex tw-size-squid-xl tw-justify-center tw-items-center tw-aspect-square tw-rounded-full tw-shadow-icon-light dark:tw-shadow-icon-dark tw-transition-colors tw-duration-200",
|
|
57
|
+
icon ? "tw-overflow-hidden" : "tw-p-2 tw-bg-grey-100 tw-text-grey-900",
|
|
58
|
+
onDisconnect && "hover:tw-bg-grey-300",
|
|
59
|
+
)}
|
|
60
|
+
>
|
|
61
|
+
{icon ? (
|
|
62
|
+
<img src={icon} alt="" className="tw-size-full tw-object-cover" />
|
|
63
|
+
) : (
|
|
64
|
+
<UserRoundIcon
|
|
65
|
+
size="1.3rem"
|
|
66
|
+
className={cn(
|
|
67
|
+
"tw-transition-all tw-duration-200",
|
|
68
|
+
onDisconnect &&
|
|
69
|
+
"group-hover/account:tw-scale-75 group-hover/account:tw-blur-sm group-hover/account:tw-opacity-0 group-focus-within/account:tw-scale-75 group-focus-within/account:tw-blur-sm group-focus-within/account:tw-opacity-0",
|
|
70
|
+
)}
|
|
71
|
+
/>
|
|
72
|
+
)}
|
|
73
|
+
{onDisconnect && (
|
|
74
|
+
<PowerIcon
|
|
75
|
+
size="1.25rem"
|
|
76
|
+
className="tw-absolute tw-scale-75 tw-blur-sm tw-opacity-0 tw-transition-all tw-duration-200 group-hover/account:tw-scale-100 group-hover/account:tw-blur-0 group-hover/account:tw-opacity-100 group-focus-within/account:tw-scale-100 group-focus-within/account:tw-blur-0 group-focus-within/account:tw-opacity-100"
|
|
77
|
+
/>
|
|
78
|
+
)}
|
|
79
|
+
</Wrapper>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatHash,
|
|
3
|
+
useMultiChainWallet,
|
|
4
|
+
useSquidChains,
|
|
5
|
+
useWallet,
|
|
6
|
+
} from "@0xsquid/react-hooks";
|
|
7
|
+
import { ChevronRightIcon } from "@0xsquid/ui";
|
|
8
|
+
import { useTokenSelection } from "../../../hooks/use-token-selection";
|
|
9
|
+
import { useDepositStore } from "../../../store/use-deposit-store";
|
|
10
|
+
import { Account } from "./account";
|
|
11
|
+
|
|
12
|
+
export function Recipient() {
|
|
13
|
+
const { chain } = useTokenSelection();
|
|
14
|
+
const { connectedAddress } = useMultiChainWallet(chain);
|
|
15
|
+
const fromAddress = connectedAddress.address;
|
|
16
|
+
const { disconnectWallet } = useWallet();
|
|
17
|
+
const config = useDepositStore((s) => s.config);
|
|
18
|
+
const { findChain } = useSquidChains();
|
|
19
|
+
|
|
20
|
+
const handleDisconnect = () => {
|
|
21
|
+
if (chain?.chainType) {
|
|
22
|
+
void disconnectWallet(chain.chainType);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const fromLabel = fromAddress
|
|
27
|
+
? formatHash({ hash: fromAddress, chainType: chain?.chainType })
|
|
28
|
+
: "Not connected";
|
|
29
|
+
|
|
30
|
+
const toLabel = config
|
|
31
|
+
? formatHash({
|
|
32
|
+
hash: config.destinationAddress,
|
|
33
|
+
chainType: findChain(config.destinationToken.chainId)?.chainType,
|
|
34
|
+
})
|
|
35
|
+
: "";
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div className="tw-flex tw-h-squid-xl tw-items-center tw-gap-2 tw-w-full tw-px-3">
|
|
39
|
+
<div className="tw-group/account tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0 tw-self-stretch">
|
|
40
|
+
<Account
|
|
41
|
+
direction="from"
|
|
42
|
+
name="You"
|
|
43
|
+
address={fromLabel}
|
|
44
|
+
onDisconnect={fromAddress ? handleDisconnect : undefined}
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div className="tw-flex tw-items-center tw-text-material-light-thick -tw-space-x-4 tw-shrink-0">
|
|
49
|
+
<ChevronRightIcon className="tw-opacity-33" />
|
|
50
|
+
<ChevronRightIcon className="tw-opacity-66" />
|
|
51
|
+
<ChevronRightIcon className="" />
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div className="tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0 tw-self-stretch">
|
|
55
|
+
<Account
|
|
56
|
+
direction="to"
|
|
57
|
+
name={config?.integrator.name ?? "Recipient"}
|
|
58
|
+
address={toLabel}
|
|
59
|
+
icon={config?.integrator.logoUrl}
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatTokenAmount,
|
|
3
|
+
formatUsdAmount,
|
|
4
|
+
getTokenImage,
|
|
5
|
+
} from "@0xsquid/react-hooks";
|
|
6
|
+
import { ChevronDownSmallIcon, PlusIcon, UserInputType } from "@0xsquid/ui";
|
|
7
|
+
import { TokenBadgeIcon } from "../../components/token-badge-icon";
|
|
8
|
+
import { useTokenSelection } from "../../hooks/use-token-selection";
|
|
9
|
+
import { useInputMode } from "../../store/use-input-mode";
|
|
10
|
+
import { useRouter } from "../../store/useRouter";
|
|
11
|
+
|
|
12
|
+
export function TokenSelector() {
|
|
13
|
+
const push = useRouter((s) => s.push);
|
|
14
|
+
const { token, chain, balance } = useTokenSelection();
|
|
15
|
+
const inputMode = useInputMode((s) => s.mode);
|
|
16
|
+
|
|
17
|
+
const isUsdMode = inputMode === UserInputType.USD;
|
|
18
|
+
const balanceNum = +balance;
|
|
19
|
+
const formattedBalance =
|
|
20
|
+
balanceNum > 0
|
|
21
|
+
? isUsdMode
|
|
22
|
+
? formatUsdAmount(balanceNum * (token?.usdPrice ?? 0))
|
|
23
|
+
: formatTokenAmount(balance, { exact: false })
|
|
24
|
+
: undefined;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<button
|
|
28
|
+
onClick={() => push({ id: "select-token" })}
|
|
29
|
+
className="tw-flex tw-gap-2 tw-items-center tw-self-stretch hover:tw-bg-material-light-thin tw-px-3 tw-py-1.5 tw-rounded-3xl"
|
|
30
|
+
>
|
|
31
|
+
{/* Token icon */}
|
|
32
|
+
{token && chain ? (
|
|
33
|
+
<TokenBadgeIcon
|
|
34
|
+
tokenSrc={getTokenImage(token)}
|
|
35
|
+
chainSrc={chain.chainIconURI}
|
|
36
|
+
/>
|
|
37
|
+
) : (
|
|
38
|
+
<span className="tw-text-grey-900 tw-text-lg tw-leading-3 tw-flex tw-items-center tw-justify-center tw-size-squid-xl tw-bg-royal-500 tw-rounded-full">
|
|
39
|
+
<PlusIcon size="1.6rem" />
|
|
40
|
+
</span>
|
|
41
|
+
)}
|
|
42
|
+
|
|
43
|
+
<div className="tw-flex tw-flex-col tw-items-start tw-justify-center tw-gap-2 tw-self-stretch tw-flex-1">
|
|
44
|
+
{token ? (
|
|
45
|
+
<>
|
|
46
|
+
<span className="tw-text-grey-100 tw-text-lg tw-font-medium tw-leading-3">
|
|
47
|
+
{token.name}
|
|
48
|
+
</span>
|
|
49
|
+
<div className="tw-flex tw-justify-center tw-items-center tw-gap-1">
|
|
50
|
+
{formattedBalance && (
|
|
51
|
+
<span className="tw-text-sm tw-text-material-light-thick tw-leading-3">
|
|
52
|
+
{formattedBalance}
|
|
53
|
+
</span>
|
|
54
|
+
)}
|
|
55
|
+
|
|
56
|
+
<span className="tw-text-sm tw-text-material-light-average tw-leading-3">
|
|
57
|
+
{token.symbol}
|
|
58
|
+
</span>
|
|
59
|
+
</div>
|
|
60
|
+
</>
|
|
61
|
+
) : (
|
|
62
|
+
<span className="tw-text-grey-100 tw-text-lg tw-font-medium tw-leading-3">
|
|
63
|
+
Select a token
|
|
64
|
+
</span>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<span className="tw-size-8 tw-flex tw-items-center tw-justify-center">
|
|
69
|
+
<ChevronDownSmallIcon
|
|
70
|
+
className="tw-text-material-light-thick"
|
|
71
|
+
size="1.6rem"
|
|
72
|
+
strokeWidth="1.2"
|
|
73
|
+
/>
|
|
74
|
+
</span>
|
|
75
|
+
</button>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SubNavBar } from "../components/shared/navigation/sub-navbar";
|
|
2
|
+
|
|
3
|
+
export function QrCodeView() {
|
|
4
|
+
return (
|
|
5
|
+
<>
|
|
6
|
+
<SubNavBar title="QR Code" />
|
|
7
|
+
<div className="tw-flex tw-flex-1 tw-items-center tw-justify-center tw-self-stretch">
|
|
8
|
+
<span className="tw-text-grey-100 tw-text-lg tw-font-medium">
|
|
9
|
+
QR Code
|
|
10
|
+
</span>
|
|
11
|
+
</div>
|
|
12
|
+
</>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { WidgetView } from "../types";
|
|
3
|
+
import { ConnectWalletView } from "./connect-wallet/connect-wallet-view";
|
|
4
|
+
import { TransactionProgressView } from "./transaction-progress/transaction-progress-view";
|
|
5
|
+
import { MainView } from "./main/main-view";
|
|
6
|
+
import { QrCodeView } from "./qr-code";
|
|
7
|
+
import { SelectChainView } from "./select-chain/select-chain-view";
|
|
8
|
+
import { SelectTokenView } from "./select-token";
|
|
9
|
+
import { TransactionHistoryView } from "./transaction-history/transaction-history-view";
|
|
10
|
+
|
|
11
|
+
export function renderView(view: WidgetView): React.ReactElement {
|
|
12
|
+
switch (view.id) {
|
|
13
|
+
case "main":
|
|
14
|
+
return <MainView />;
|
|
15
|
+
case "connect-wallet":
|
|
16
|
+
return <ConnectWalletView chainType={view.chainType} />;
|
|
17
|
+
case "select-chain":
|
|
18
|
+
return <SelectChainView wallet={view.wallet} />;
|
|
19
|
+
case "qr-code":
|
|
20
|
+
return <QrCodeView />;
|
|
21
|
+
case "select-token":
|
|
22
|
+
return <SelectTokenView />;
|
|
23
|
+
case "transaction-history":
|
|
24
|
+
return <TransactionHistoryView />;
|
|
25
|
+
case "transaction-progress":
|
|
26
|
+
return <TransactionProgressView />;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ChainType } from "@0xsquid/squid-types";
|
|
2
|
+
|
|
3
|
+
interface ChainTypeMeta {
|
|
4
|
+
name: string;
|
|
5
|
+
icon: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const CHAIN_TYPE_META: Record<ChainType, ChainTypeMeta> = {
|
|
9
|
+
[ChainType.EVM]: {
|
|
10
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/ethereum.webp",
|
|
11
|
+
name: "Ethereum",
|
|
12
|
+
},
|
|
13
|
+
[ChainType.COSMOS]: {
|
|
14
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/squid-brand-assets/custom-chain-icons/cosmos.webp",
|
|
15
|
+
name: "Cosmos",
|
|
16
|
+
},
|
|
17
|
+
[ChainType.BTC]: {
|
|
18
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/bitcoin.webp",
|
|
19
|
+
name: "Bitcoin",
|
|
20
|
+
},
|
|
21
|
+
[ChainType.SOLANA]: {
|
|
22
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/solana.webp",
|
|
23
|
+
name: "Solana",
|
|
24
|
+
},
|
|
25
|
+
[ChainType.SUI]: {
|
|
26
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/sui.webp",
|
|
27
|
+
name: "Sui",
|
|
28
|
+
},
|
|
29
|
+
[ChainType.XRPL]: {
|
|
30
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/xrpl.webp",
|
|
31
|
+
name: "XRPL",
|
|
32
|
+
},
|
|
33
|
+
[ChainType.STELLAR]: {
|
|
34
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/stellar.webp",
|
|
35
|
+
name: "Stellar",
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { ConnectingWalletStatus, useWallet } from "@0xsquid/react-hooks";
|
|
3
|
+
import type { Wallet } from "@0xsquid/react-hooks";
|
|
4
|
+
import type { ChainType } from "@0xsquid/squid-types";
|
|
5
|
+
import { Loader } from "@0xsquid/ui";
|
|
6
|
+
import { SubNavBar } from "../../components/shared/navigation/sub-navbar";
|
|
7
|
+
import { useRouter } from "../../store/useRouter";
|
|
8
|
+
import { CHAIN_TYPE_META } from "./chain-type-meta";
|
|
9
|
+
|
|
10
|
+
interface SelectChainViewProps {
|
|
11
|
+
wallet: Wallet;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function SelectChainView({ wallet }: SelectChainViewProps) {
|
|
15
|
+
const popToRoot = useRouter((s) => s.popToRoot);
|
|
16
|
+
const { connectWallet, connectingWalletState } = useWallet();
|
|
17
|
+
const [connectingChainType, setConnectingChainType] =
|
|
18
|
+
useState<ChainType | null>(null);
|
|
19
|
+
|
|
20
|
+
if (!wallet.isMultiChain) return null;
|
|
21
|
+
const networks = wallet.supportedNetworks;
|
|
22
|
+
|
|
23
|
+
const isConnecting =
|
|
24
|
+
connectingWalletState.status === ConnectingWalletStatus.CONNECTING &&
|
|
25
|
+
connectingWalletState.wallet?.connectorId === wallet.connectorId;
|
|
26
|
+
|
|
27
|
+
const onChainSelected = async (chainType: ChainType) => {
|
|
28
|
+
setConnectingChainType(chainType);
|
|
29
|
+
try {
|
|
30
|
+
const connected = await connectWallet({
|
|
31
|
+
wallet,
|
|
32
|
+
selectedChainTypes: [chainType],
|
|
33
|
+
});
|
|
34
|
+
if (connected) {
|
|
35
|
+
popToRoot();
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error("Failed to connect wallet:", error);
|
|
39
|
+
setConnectingChainType(null);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<>
|
|
45
|
+
<SubNavBar title="Select network" />
|
|
46
|
+
|
|
47
|
+
<div className="tw-flex tw-flex-col tw-items-center tw-gap-2 tw-px-4 tw-py-5 tw-border-b tw-border-grey-800">
|
|
48
|
+
{wallet.icon && (
|
|
49
|
+
<img
|
|
50
|
+
src={wallet.icon}
|
|
51
|
+
alt={wallet.name}
|
|
52
|
+
className="tw-size-12 tw-rounded-xl"
|
|
53
|
+
/>
|
|
54
|
+
)}
|
|
55
|
+
|
|
56
|
+
<div className="tw-flex tw-flex-col tw-items-center tw-self-stretch">
|
|
57
|
+
<span className="tw-text-material-light-thick tw-text-base tw-text-center">
|
|
58
|
+
{wallet.name} supports multiple ecosystems.
|
|
59
|
+
</span>
|
|
60
|
+
|
|
61
|
+
<span className="tw-text-material-light-thick tw-text-base tw-text-center">
|
|
62
|
+
Select one to connect.
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<ul className="tw-flex tw-flex-col tw-items-start tw-flex-1 tw-self-stretch tw-py-1 tw-overflow-auto">
|
|
68
|
+
{networks.map((network) => {
|
|
69
|
+
const meta = CHAIN_TYPE_META[network.chainType];
|
|
70
|
+
return (
|
|
71
|
+
<li key={network.chainType} className="tw-self-stretch">
|
|
72
|
+
<button
|
|
73
|
+
className="tw-flex tw-min-h-14 tw-h-14 tw-px-4 tw-items-center tw-gap-3 tw-self-stretch tw-w-full hover:tw-bg-material-light-thin"
|
|
74
|
+
disabled={isConnecting}
|
|
75
|
+
onClick={() => onChainSelected(network.chainType)}
|
|
76
|
+
>
|
|
77
|
+
<div className="tw-flex tw-size-squid-xl tw-justify-center tw-items-center tw-aspect-square tw-rounded-xl tw-shadow-icon-light dark:tw-shadow-icon-dark">
|
|
78
|
+
<img
|
|
79
|
+
src={meta.icon}
|
|
80
|
+
alt={meta.name}
|
|
81
|
+
className="tw-size-full tw-rounded-xl"
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
<span className="tw-text-grey-200 tw-text-lg tw-flex-1 tw-text-left">
|
|
85
|
+
{meta.name}
|
|
86
|
+
</span>
|
|
87
|
+
{isConnecting && connectingChainType === network.chainType && (
|
|
88
|
+
<Loader size="20" className="tw-text-grey-100" />
|
|
89
|
+
)}
|
|
90
|
+
</button>
|
|
91
|
+
</li>
|
|
92
|
+
);
|
|
93
|
+
})}
|
|
94
|
+
</ul>
|
|
95
|
+
</>
|
|
96
|
+
);
|
|
97
|
+
}
|