@ensofinance/checkout-widget 0.0.1

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.
Files changed (128) hide show
  1. package/dist/checkout-widget.es.js +52889 -0
  2. package/dist/checkout-widget.es.js.map +1 -0
  3. package/dist/checkout-widget.umd.js +203 -0
  4. package/dist/checkout-widget.umd.js.map +1 -0
  5. package/dist/index.d.ts +23 -0
  6. package/enso-api.yaml +1982 -0
  7. package/orval.config.ts +25 -0
  8. package/package.json +79 -0
  9. package/src/assets/BinanceBadge.svg +4 -0
  10. package/src/assets/CoinbaseIcon.svg +4 -0
  11. package/src/assets/USD Coin (USDC).svg +5 -0
  12. package/src/assets/avecIcon.svg +5 -0
  13. package/src/assets/base.webp +0 -0
  14. package/src/assets/depositIcon.svg +6 -0
  15. package/src/assets/eth.webp +0 -0
  16. package/src/assets/ethMainnetIcon.svg +10 -0
  17. package/src/assets/fail.svg +5 -0
  18. package/src/assets/kraken.png +0 -0
  19. package/src/assets/logo.svg +10 -0
  20. package/src/assets/mastercard.png +0 -0
  21. package/src/assets/metamask.png +0 -0
  22. package/src/assets/rabby.png +0 -0
  23. package/src/assets/success.svg +4 -0
  24. package/src/assets/usdc.webp +0 -0
  25. package/src/assets/usdt.webp +0 -0
  26. package/src/assets/visa.png +0 -0
  27. package/src/assets/visa.webp +0 -0
  28. package/src/components/BridgeFee.tsx +58 -0
  29. package/src/components/ChakraProvider.tsx +372 -0
  30. package/src/components/Checkout.tsx +127 -0
  31. package/src/components/CheckoutModal.tsx +22 -0
  32. package/src/components/CircleTimer.tsx +66 -0
  33. package/src/components/CurrencySwapDisplay.tsx +153 -0
  34. package/src/components/DepositProcessing.tsx +116 -0
  35. package/src/components/ExchangeConfirmSecurity.tsx +110 -0
  36. package/src/components/QuoteParameters.tsx +341 -0
  37. package/src/components/TransactionDetailRow.tsx +124 -0
  38. package/src/components/cards/AssetCard.tsx +167 -0
  39. package/src/components/cards/ExchangeCard.tsx +53 -0
  40. package/src/components/cards/OptionCard.tsx +59 -0
  41. package/src/components/cards/WalletCard.tsx +99 -0
  42. package/src/components/cards/index.ts +6 -0
  43. package/src/components/modal.tsx +83 -0
  44. package/src/components/steps/ExchangeFlow.tsx +1402 -0
  45. package/src/components/steps/InitialStep.tsx +169 -0
  46. package/src/components/steps/QuoteStep.tsx +121 -0
  47. package/src/components/steps/WalletAmountStep.tsx +258 -0
  48. package/src/components/steps/WalletConfirmStep.tsx +404 -0
  49. package/src/components/steps/WalletTokenStep.tsx +128 -0
  50. package/src/components/ui/index.tsx +394 -0
  51. package/src/components/ui/styled.tsx +85 -0
  52. package/src/components/ui/toaster.tsx +43 -0
  53. package/src/components/ui/tooltip.tsx +46 -0
  54. package/src/enso-api/api.ts +173 -0
  55. package/src/enso-api/custom-instance.ts +35 -0
  56. package/src/enso-api/index.ts +5119 -0
  57. package/src/enso-api/model/action.ts +17 -0
  58. package/src/enso-api/model/actionAction.ts +52 -0
  59. package/src/enso-api/model/actionInputs.ts +12 -0
  60. package/src/enso-api/model/actionToBundle.ts +19 -0
  61. package/src/enso-api/model/actionToBundleAction.ts +53 -0
  62. package/src/enso-api/model/actionToBundleArgs.ts +12 -0
  63. package/src/enso-api/model/bundleControllerBundleShortcutTransactionParams.ts +53 -0
  64. package/src/enso-api/model/bundleControllerBundleShortcutTransactionRoutingStrategy.ts +23 -0
  65. package/src/enso-api/model/bundleShortcutTransaction.ts +35 -0
  66. package/src/enso-api/model/bundleShortcutTransactionAmountsOut.ts +15 -0
  67. package/src/enso-api/model/bundleShortcutTransactionFeeAmount.ts +12 -0
  68. package/src/enso-api/model/connectedNetwork.ts +16 -0
  69. package/src/enso-api/model/hop.ts +24 -0
  70. package/src/enso-api/model/hopArgs.ts +12 -0
  71. package/src/enso-api/model/index.ts +70 -0
  72. package/src/enso-api/model/iporControllerIporShortcutTransactionParams.ts +21 -0
  73. package/src/enso-api/model/iporShortcutInput.ts +33 -0
  74. package/src/enso-api/model/iporShortcutTransaction.ts +22 -0
  75. package/src/enso-api/model/lZDestinationTokenData.ts +19 -0
  76. package/src/enso-api/model/lZPoolLookupResponse.ts +26 -0
  77. package/src/enso-api/model/layerZeroControllerGetPoolAddressParams.ts +29 -0
  78. package/src/enso-api/model/network.ts +15 -0
  79. package/src/enso-api/model/networksControllerNetworksParams.ts +21 -0
  80. package/src/enso-api/model/nonTokenizedControllerTokens200.ts +15 -0
  81. package/src/enso-api/model/nonTokenizedControllerTokens200AllOf.ts +16 -0
  82. package/src/enso-api/model/nonTokenizedControllerTokensParams.ts +41 -0
  83. package/src/enso-api/model/nonTokenizedModel.ts +27 -0
  84. package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionParams.ts +64 -0
  85. package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionRoutingStrategy.ts +22 -0
  86. package/src/enso-api/model/paginatedResult.ts +16 -0
  87. package/src/enso-api/model/paginationMeta.ts +27 -0
  88. package/src/enso-api/model/positionModel.ts +77 -0
  89. package/src/enso-api/model/price.ts +20 -0
  90. package/src/enso-api/model/pricesControllerGetPricesParams.ts +17 -0
  91. package/src/enso-api/model/project.ts +15 -0
  92. package/src/enso-api/model/protocol.ts +15 -0
  93. package/src/enso-api/model/protocolModel.ts +26 -0
  94. package/src/enso-api/model/protocolsControllerFindAllParams.ts +21 -0
  95. package/src/enso-api/model/routeShortcutTransaction.ts +33 -0
  96. package/src/enso-api/model/routeShortcutVariableInputs.ts +68 -0
  97. package/src/enso-api/model/routeShortcutVariableInputsRoutingStrategy.ts +27 -0
  98. package/src/enso-api/model/routeShortcutVariableInputsVariableEstimates.ts +14 -0
  99. package/src/enso-api/model/routerControllerRouteShortcutTransactionParams.ts +91 -0
  100. package/src/enso-api/model/routerControllerRouteShortcutTransactionRoutingStrategy.ts +23 -0
  101. package/src/enso-api/model/standard.ts +18 -0
  102. package/src/enso-api/model/standardAction.ts +20 -0
  103. package/src/enso-api/model/standardActionAction.ts +53 -0
  104. package/src/enso-api/model/tokenModel.ts +36 -0
  105. package/src/enso-api/model/tokensControllerTokens200.ts +15 -0
  106. package/src/enso-api/model/tokensControllerTokens200AllOf.ts +16 -0
  107. package/src/enso-api/model/tokensControllerTokensParams.ts +91 -0
  108. package/src/enso-api/model/tokensControllerTokensType.ts +19 -0
  109. package/src/enso-api/model/transaction.ts +17 -0
  110. package/src/enso-api/model/userOperation.ts +28 -0
  111. package/src/enso-api/model/walletApproveTransaction.ts +24 -0
  112. package/src/enso-api/model/walletApproveTransactionTx.ts +15 -0
  113. package/src/enso-api/model/walletBalance.ts +29 -0
  114. package/src/enso-api/model/walletControllerCreateApproveTransactionParams.ts +35 -0
  115. package/src/enso-api/model/walletControllerCreateApproveTransactionRoutingStrategy.ts +23 -0
  116. package/src/enso-api/model/walletControllerWalletBalancesParams.ts +25 -0
  117. package/src/index.ts +17 -0
  118. package/src/store.ts +68 -0
  119. package/src/types/assets.d.ts +29 -0
  120. package/src/types/index.ts +21 -0
  121. package/src/util/common.tsx +324 -0
  122. package/src/util/constants.tsx +213 -0
  123. package/src/util/enso-hooks.tsx +203 -0
  124. package/src/util/index.tsx +68 -0
  125. package/src/util/tx-tracker.tsx +301 -0
  126. package/src/util/wallet.tsx +258 -0
  127. package/tsconfig.json +13 -0
  128. package/vite.config.ts +51 -0
@@ -0,0 +1,341 @@
1
+ import { useAccount } from "wagmi";
2
+ import {
3
+ Box,
4
+ Flex,
5
+ Icon,
6
+ Image,
7
+ Skeleton,
8
+ Text,
9
+ Table,
10
+ Link,
11
+ } from "@chakra-ui/react";
12
+ import { ExternalLink } from "lucide-react";
13
+ import { useAppDetails, useRouteData, useWalletIcon } from "@/util/enso-hooks";
14
+ import { formatNumber, getChainIcon, normalizeValue } from "@/util";
15
+ import { shortenAddress } from "@/util";
16
+ import { getChainName, Token } from "@/util/common";
17
+ import { Tooltip } from "@/components/ui/tooltip";
18
+ import { getChainEtherscanUrl } from "@/util/common";
19
+ import { MOCK_IMAGE_URL, SupportedChainId } from "@/util/constants";
20
+ import { STARGATE_CHAIN_NAMES } from "@/util/constants";
21
+ import { useAppStore } from "@/store";
22
+ // @ts-ignore
23
+ import BinanceBadge from "../assets/BinanceBadge.svg";
24
+
25
+ export const ERROR_MSG =
26
+ "Swap not found for a required underlying of defi route, please make sure your amount is within an acceptable range";
27
+
28
+ const GECKO_HOSTNAME = "coingecko";
29
+
30
+ // uplift default image quality
31
+ const transformGeckoUrl = (originalUrl: string): string =>
32
+ originalUrl.includes(GECKO_HOSTNAME)
33
+ ? originalUrl.replace("/thumb/", "/large/")
34
+ : originalUrl;
35
+
36
+ const TokenIcon = ({
37
+ token,
38
+ chainId,
39
+ size = 32,
40
+ }: {
41
+ token: Token;
42
+ chainId?: SupportedChainId;
43
+ size?: number;
44
+ }) => (
45
+ <Box
46
+ position="relative"
47
+ borderRadius={"50%"}
48
+ minW={`${size}px`}
49
+ minH={`${size}px`}
50
+ >
51
+ <Box
52
+ borderRadius={"50%"}
53
+ overflow={"hidden"}
54
+ width={`${size}px`}
55
+ height={`${size}px`}
56
+ >
57
+ <img
58
+ src={
59
+ token?.logoURI
60
+ ? transformGeckoUrl(token?.logoURI)
61
+ : MOCK_IMAGE_URL
62
+ }
63
+ title={token?.symbol}
64
+ alt={token?.symbol}
65
+ width={`${size}px`}
66
+ height={`${size}px`}
67
+ />
68
+ </Box>
69
+ {chainId && (
70
+ <Box
71
+ position="absolute"
72
+ bottom="0"
73
+ right={"-2px"}
74
+ width={`${size / 2}px`}
75
+ height={`${size / 2}px`}
76
+ borderRadius="50%"
77
+ overflow="hidden"
78
+ border="1px solid"
79
+ borderColor="bg"
80
+ zIndex="1"
81
+ >
82
+ <img
83
+ src={`https://icons-ckg.pages.dev/stargate-light/networks/${STARGATE_CHAIN_NAMES[chainId]}.svg`}
84
+ alt={`Chain ${chainId}`}
85
+ width="100%"
86
+ height="100%"
87
+ />
88
+ </Box>
89
+ )}
90
+ </Box>
91
+ );
92
+
93
+ const QuoteParameters = () => {
94
+ const { address } = useAccount();
95
+ const { walletIcon, walletDisplayName } = useWalletIcon();
96
+ const { chainIdOut, tokenOutData, tokenInData, amountIn, chainIdIn } =
97
+ useAppDetails();
98
+ const { routeLoading, routeData, routeFetched, routerError } =
99
+ useRouteData();
100
+ const { isCheckout } = useAppStore();
101
+ const showRouteLoading = routeLoading || (!routeFetched && !routerError);
102
+
103
+ const routeErrorMessage: string | null =
104
+ (routeData as any)?.error || (routeData as any)?.statusCode === 500
105
+ ? ERROR_MSG
106
+ : null;
107
+
108
+ const inWalletUrl = getChainEtherscanUrl({
109
+ hash: address,
110
+ chainId: chainIdIn,
111
+ type: "/address",
112
+ });
113
+
114
+ const outWalletUrl = getChainEtherscanUrl({
115
+ hash: address,
116
+ chainId: chainIdOut,
117
+ type: "/address",
118
+ });
119
+
120
+ return (
121
+ <>
122
+ <Table.Root
123
+ key={"line"}
124
+ size="sm"
125
+ variant={"outline"}
126
+ width={"100%"}
127
+ borderRadius={"sm"}
128
+ >
129
+ <Table.Body >
130
+ <Table.Row>
131
+ <Table.Cell>Source</Table.Cell>
132
+ <Table.Cell
133
+ display="flex"
134
+ textAlign="end"
135
+ justifyContent="end"
136
+ >
137
+ <Box
138
+ display="flex"
139
+ gap={"8px"}
140
+ alignItems={"center"}
141
+ >
142
+ {isCheckout ? (
143
+ <>
144
+ <Image
145
+ src={BinanceBadge}
146
+ width={"16px"}
147
+ height={"16px"}
148
+ />
149
+ <Text>Binance</Text>
150
+ </>
151
+ ) : (
152
+ <>
153
+ {typeof walletIcon === "string" ? (
154
+ <Image
155
+ src={walletIcon}
156
+ width={"16px"}
157
+ height={"16px"}
158
+ />
159
+ ) : (
160
+ walletIcon
161
+ )}
162
+ <Tooltip content={walletDisplayName}>
163
+ <Text>
164
+ {address &&
165
+ walletDisplayName +
166
+ " " +
167
+ shortenAddress(
168
+ address,
169
+ true,
170
+ )}
171
+ </Text>
172
+ </Tooltip>
173
+ {inWalletUrl && (
174
+ <Link
175
+ href={inWalletUrl}
176
+ target="_blank"
177
+ >
178
+ <Icon
179
+ as={ExternalLink}
180
+ color="fg.muted"
181
+ width={"16px"}
182
+ height={"16px"}
183
+ />
184
+ </Link>
185
+ )}
186
+ </>
187
+ )}
188
+ </Box>
189
+ </Table.Cell>
190
+ </Table.Row>
191
+
192
+ <Table.Row>
193
+ <Table.Cell>Destination</Table.Cell>
194
+ <Table.Cell
195
+ display="flex"
196
+ textAlign="end"
197
+ justifyContent="end"
198
+ >
199
+ <Skeleton
200
+ loading={showRouteLoading}
201
+ width={showRouteLoading ? "80px" : "auto"}
202
+ >
203
+ <Flex gap={"8px"} alignItems={"center"}>
204
+ <Image
205
+ src={getChainIcon(chainIdOut)}
206
+ width={"16px"}
207
+ height={"16px"}
208
+ />
209
+ <Text>{getChainName(chainIdOut)}</Text>
210
+ {" - "}
211
+ <Tooltip content={walletDisplayName}>
212
+ <Text>
213
+ {address && shortenAddress(address)}
214
+ </Text>
215
+ </Tooltip>
216
+ {outWalletUrl && (
217
+ <Link
218
+ href={outWalletUrl}
219
+ target="_blank"
220
+ >
221
+ <Icon
222
+ as={ExternalLink}
223
+ color="fg.muted"
224
+ width={"16px"}
225
+ height={"16px"}
226
+ />
227
+ </Link>
228
+ )}
229
+ </Flex>
230
+ </Skeleton>
231
+ </Table.Cell>
232
+ </Table.Row>
233
+
234
+ <Table.Row>
235
+ <Table.Cell>Estimated time</Table.Cell>
236
+ <Table.Cell
237
+ display="flex"
238
+ textAlign="end"
239
+ justifyContent="end"
240
+ >
241
+ <Skeleton
242
+ loading={showRouteLoading}
243
+ width={showRouteLoading ? "80px" : "auto"}
244
+ >
245
+ <Text>
246
+ {isCheckout
247
+ ? `~2min`
248
+ : chainIdIn !== chainIdOut
249
+ ? `~1 min`
250
+ : `instant`}
251
+ </Text>
252
+ </Skeleton>
253
+ </Table.Cell>
254
+ </Table.Row>
255
+ </Table.Body>
256
+ </Table.Root>
257
+
258
+ {routeErrorMessage ? (
259
+ <Text fontSize={"xs"} color="error">
260
+ {routeErrorMessage}
261
+ </Text>
262
+ ) : (
263
+ <Table.Root
264
+ key={"line"}
265
+ size="sm"
266
+ variant={"outline"}
267
+ bg="bg.subtle"
268
+ >
269
+ <Table.Body>
270
+ <Table.Row>
271
+ <Table.Cell>You send</Table.Cell>
272
+ <Table.Cell
273
+ display="flex"
274
+ textAlign="end"
275
+ justifyContent="end"
276
+ >
277
+ <Box
278
+ display="flex"
279
+ gap={"8px"}
280
+ alignItems={"center"}
281
+ >
282
+ <Text>
283
+ {formatNumber(
284
+ normalizeValue(
285
+ amountIn,
286
+ tokenInData?.decimals,
287
+ ),
288
+ )}{" "}
289
+ {tokenInData?.symbol}
290
+ </Text>
291
+ <TokenIcon
292
+ token={tokenInData}
293
+ chainId={chainIdIn}
294
+ size={24}
295
+ />
296
+ </Box>
297
+ </Table.Cell>
298
+ </Table.Row>
299
+ <Table.Row>
300
+ <Table.Cell>You receive</Table.Cell>
301
+ <Table.Cell
302
+ display="flex"
303
+ textAlign="end"
304
+ justifyContent="end"
305
+ >
306
+ {" "}
307
+ <Skeleton
308
+ loading={showRouteLoading}
309
+ width={showRouteLoading ? "156px" : "auto"}
310
+ >
311
+ <Box
312
+ display="flex"
313
+ gap={"8px"}
314
+ alignItems={"center"}
315
+ >
316
+ <Text>
317
+ {formatNumber(
318
+ normalizeValue(
319
+ routeData?.amountOut,
320
+ tokenOutData?.decimals,
321
+ ),
322
+ )}{" "}
323
+ {tokenOutData?.symbol}
324
+ </Text>
325
+ <TokenIcon
326
+ token={tokenOutData}
327
+ chainId={chainIdOut}
328
+ size={24}
329
+ />
330
+ </Box>
331
+ </Skeleton>
332
+ </Table.Cell>
333
+ </Table.Row>
334
+ </Table.Body>
335
+ </Table.Root>
336
+ )}
337
+ </>
338
+ );
339
+ };
340
+
341
+ export default QuoteParameters;
@@ -0,0 +1,124 @@
1
+ import { chakra, Flex, Span, Icon, Box, Collapsible } from "@chakra-ui/react";
2
+ import { ChevronDown } from "lucide-react";
3
+ import BridgingFee from "./BridgeFee";
4
+ import { useAppDetails, useRouteData } from "@/util/enso-hooks";
5
+ import { useAppStore } from "@/store";
6
+ import { useState } from "react";
7
+
8
+ export const DetailRowContainer = chakra("div", {
9
+ base: {
10
+ display: "flex",
11
+ justifyContent: "space-between",
12
+ alignItems: "center",
13
+ h: "36px",
14
+ p: "8px 12px",
15
+ borderRadius: "8px",
16
+ bg: "bg",
17
+ w: "100%",
18
+ },
19
+ });
20
+
21
+ export const TransactionDetailRow = () => {
22
+ const { routerData } = useRouteData();
23
+ const { chainIdIn, chainIdOut, isCheckout } = useAppDetails();
24
+ const slippage = useAppStore((state) => state.slippage);
25
+ const [isExpanded, setIsExpanded] = useState(false);
26
+
27
+ const formattedPriceImpact = routerData?.priceImpact
28
+ ? (-routerData?.priceImpact / 100).toFixed(2)
29
+ : "0.00";
30
+
31
+ const detailItems = [
32
+ {
33
+ detail: `${formattedPriceImpact}%`,
34
+ label: "Est. price impact",
35
+ },
36
+ {
37
+ detail: `${slippage / 100}%`,
38
+ label: "Max. slippage",
39
+ },
40
+ {
41
+ detail: isCheckout
42
+ ? `~2min`
43
+ : chainIdIn !== chainIdOut
44
+ ? `~1 min`
45
+ : `instant`,
46
+ label: "Est. processing time",
47
+ },
48
+ ];
49
+
50
+ return (
51
+ <Collapsible.Root
52
+ open={isExpanded}
53
+ onOpenChange={(details) => setIsExpanded(details.open)}
54
+ w={"full"}
55
+ >
56
+ <Box
57
+ width="100%"
58
+ bg="bg.subtle"
59
+ borderRadius="md"
60
+ padding="12px"
61
+ transition="all 0.2s"
62
+ >
63
+ {/* Header - Always visible */}
64
+ <Collapsible.Trigger asChild>
65
+ <Flex
66
+ align="center"
67
+ justify="space-between"
68
+ width="100%"
69
+ cursor="pointer"
70
+ >
71
+ <Flex align="center" gap={2}>
72
+ <Span color="fg.muted" fontSize="sm">
73
+ Transaction details
74
+ </Span>
75
+ <Icon
76
+ as={ChevronDown}
77
+ width="14px"
78
+ height="14px"
79
+ color="fg.muted"
80
+ transform={
81
+ isExpanded
82
+ ? "rotate(180deg)"
83
+ : "rotate(0deg)"
84
+ }
85
+ transition="transform 0.2s ease-in-out"
86
+ />
87
+ </Flex>
88
+ <BridgingFee />
89
+ </Flex>
90
+ </Collapsible.Trigger>
91
+
92
+ {/* Expandable Details with Animation */}
93
+ <Collapsible.Content>
94
+ <Box
95
+ marginTop="12px"
96
+ paddingTop="12px"
97
+ borderTop="1px solid"
98
+ borderColor="border"
99
+ >
100
+ {detailItems.map((item, index) => (
101
+ <Flex
102
+ key={index}
103
+ justify="space-between"
104
+ align="center"
105
+ paddingY="6px"
106
+ >
107
+ <Span fontSize="sm" color="fg.muted">
108
+ {item.label}
109
+ </Span>
110
+ <Span
111
+ fontSize="sm"
112
+ color="fg"
113
+ fontWeight="medium"
114
+ >
115
+ {item.detail}
116
+ </Span>
117
+ </Flex>
118
+ ))}
119
+ </Box>
120
+ </Collapsible.Content>
121
+ </Box>
122
+ </Collapsible.Root>
123
+ );
124
+ };
@@ -0,0 +1,167 @@
1
+ import { FC, PropsWithChildren, ReactElement } from "react";
2
+ import {
3
+ Box,
4
+ chakra,
5
+ Image,
6
+ SkeletonCircle,
7
+ SkeletonText,
8
+ Text,
9
+ } from "@chakra-ui/react";
10
+ import { Card, Tag } from "../ui";
11
+ import { getChainIcon } from "@/util";
12
+
13
+ export const UsdBalance = chakra("p", {
14
+ base: {
15
+ fontWeight: "500",
16
+ fontSize: "14px",
17
+ lineHeight: "20px",
18
+ letterSpacing: "0%",
19
+ color: "fg.muted",
20
+ },
21
+ });
22
+
23
+ // export const CardWrapper = chakra("div", {
24
+ // base: {
25
+ // display: "flex",
26
+ // alignItems: "center",
27
+ // justifyContent: "space-between",
28
+ // padding: "8px 12px",
29
+ // borderRadius: "md",
30
+ // border: "1px solid",
31
+ // borderColor: "border",
32
+ // cursor: "pointer",
33
+ // width: "100%",
34
+ // _hover: {
35
+ // borderColor: "border.emphasized",
36
+ // },
37
+ // },
38
+ // });
39
+
40
+ const AssetCardSkeleton: FC<PropsWithChildren<{ isLoading: boolean }>> = ({
41
+ children,
42
+ isLoading,
43
+ }) => {
44
+ if (isLoading) {
45
+ return (
46
+ <Box
47
+ display="flex"
48
+ alignItems="center"
49
+ justifyContent="space-between"
50
+ gap="1"
51
+ minWidth="320px"
52
+ >
53
+ <Box display="flex" alignItems="center" gap="1">
54
+ <SkeletonCircle size="8" />
55
+ <Box display="flex" flexDirection="column" gap="1">
56
+ <SkeletonText noOfLines={1} width="80px" />
57
+ <SkeletonText noOfLines={1} width="80px" />
58
+ </Box>
59
+ </Box>
60
+ <Box display="flex" alignItems="center" gap="1">
61
+ <SkeletonText noOfLines={1} width="80px" />
62
+ </Box>
63
+ </Box>
64
+ );
65
+ }
66
+
67
+ return children;
68
+ };
69
+
70
+ const AssetCard = ({
71
+ icon,
72
+ title,
73
+ balance,
74
+ usdBalance,
75
+ tag,
76
+ loading,
77
+ selected,
78
+ onClick,
79
+ chainId,
80
+ }: {
81
+ icon?: ReactElement | string;
82
+ title: string;
83
+ balance: string | number;
84
+ usdBalance: string;
85
+ tag: string;
86
+ loading: boolean;
87
+ selected: boolean;
88
+ onClick: () => void;
89
+ chainId: number;
90
+ }) => {
91
+ return (
92
+ <Card
93
+ onClick={onClick}
94
+ selected={selected}
95
+ // borderColor={selected ? "primary" : "border"}
96
+ >
97
+ <AssetCardSkeleton isLoading={loading}>
98
+ <Box
99
+ display="flex"
100
+ alignItems="center"
101
+ justifyContent="space-between"
102
+ gap="1"
103
+ minWidth="320px"
104
+ >
105
+ <Box display="flex" alignItems="center" gap="1">
106
+ <Box
107
+ position={"relative"}
108
+ borderRadius={"full"}
109
+ w={"32px"}
110
+ h={"32px"}
111
+ >
112
+ {icon && (
113
+ <Image
114
+ borderRadius={"full"}
115
+ w={"32px"}
116
+ src={icon as string}
117
+ />
118
+ )}
119
+ {chainId && (
120
+ <Box
121
+ position="absolute"
122
+ bottom="0"
123
+ right="-2px"
124
+ width="16px"
125
+ height="16px"
126
+ borderRadius="50%"
127
+ overflow="hidden"
128
+ border="1px solid"
129
+ borderColor="bg"
130
+ zIndex="1"
131
+ >
132
+ <img
133
+ src={getChainIcon(chainId)}
134
+ alt={`Chain ${chainId}`}
135
+ width="100%"
136
+ height="100%"
137
+ />
138
+ </Box>
139
+ )}
140
+ </Box>
141
+ <Box>
142
+ <Text
143
+ fontWeight="medium"
144
+ color={"fg"}
145
+ whiteSpace={"nowrap"}
146
+ maxWidth={"80px"}
147
+ overflow={"hidden"}
148
+ textOverflow={"ellipsis"}
149
+ >
150
+ {title}
151
+ </Text>
152
+ <Text fontSize="xs" color="fg.muted">
153
+ {balance}
154
+ </Text>
155
+ </Box>
156
+ </Box>
157
+ <Box display="flex" alignItems="center" gap="1">
158
+ {tag && <Tag>{tag}</Tag>}
159
+ <UsdBalance>{usdBalance}</UsdBalance>
160
+ </Box>
161
+ </Box>
162
+ </AssetCardSkeleton>
163
+ </Card>
164
+ );
165
+ };
166
+
167
+ export default AssetCard;
@@ -0,0 +1,53 @@
1
+ import { FC, ReactElement } from "react";
2
+
3
+ import { Card, Tag } from "../ui";
4
+ import { Box, Icon, Image, Text } from "@chakra-ui/react";
5
+ import { CheckIcon } from "lucide-react";
6
+
7
+ export enum IExchangeCardStatus {
8
+ CONNECT = "connect",
9
+ CONNECTED = "connected",
10
+ LOW_BALANCE = "low_balance",
11
+ NONE = "none",
12
+ }
13
+
14
+ type IProps = {
15
+ icon?: ReactElement | string;
16
+ title: string;
17
+ status: IExchangeCardStatus;
18
+ onClick: () => void;
19
+ };
20
+
21
+ const ExchangeCard: FC<IProps> = ({
22
+ icon,
23
+ title,
24
+ status = IExchangeCardStatus.NONE,
25
+ onClick,
26
+ }) => {
27
+ const statusBadge: Record<string, ReactElement | null> = {
28
+ connect: (
29
+ <Text fontSize={"xs"} fontWeight="medium" color="pink">
30
+ Connect
31
+ </Text>
32
+ ),
33
+ low: <Tag>Low Balance</Tag>,
34
+ connected: (
35
+ <Icon as={CheckIcon} color="green" width={"16px"} height={"16px"} />
36
+ ),
37
+ none: null,
38
+ };
39
+
40
+ return (
41
+ <Card onClick={onClick}>
42
+ <Box display="flex" alignItems="center" gap="1">
43
+ {icon && <Image w={"32px"} src={icon as string} />}
44
+ <Box>
45
+ <Card.Title>{title}</Card.Title>
46
+ </Box>
47
+ </Box>
48
+ {statusBadge[status]}
49
+ </Card>
50
+ );
51
+ };
52
+
53
+ export default ExchangeCard;