@rango-dev/widget-embedded 0.10.1-next.0 → 0.11.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/components/Layout.d.ts.map +1 -1
  3. package/dist/components/PercentageChange.d.ts +9 -0
  4. package/dist/components/PercentageChange.d.ts.map +1 -0
  5. package/dist/components/RoutesOverview.d.ts +120 -0
  6. package/dist/components/RoutesOverview.d.ts.map +1 -0
  7. package/dist/components/SwapDetailsPlaceholder.d.ts +120 -0
  8. package/dist/components/SwapDetailsPlaceholder.d.ts.map +1 -0
  9. package/dist/components/SwitchFromAndTo.d.ts +3 -2
  10. package/dist/components/SwitchFromAndTo.d.ts.map +1 -1
  11. package/dist/components/TokenInfo.d.ts +18 -0
  12. package/dist/components/TokenInfo.d.ts.map +1 -0
  13. package/dist/components/TokenPreview.d.ts +21 -0
  14. package/dist/components/TokenPreview.d.ts.map +1 -0
  15. package/dist/index.js +1 -1
  16. package/dist/index.js.map +4 -4
  17. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  18. package/dist/pages/Home.d.ts.map +1 -1
  19. package/dist/pages/SwapDetailsPage.d.ts.map +1 -1
  20. package/dist/utils/numbers.d.ts.map +1 -1
  21. package/package.json +8 -8
  22. package/src/components/Layout.tsx +65 -12
  23. package/src/components/PercentageChange.tsx +33 -0
  24. package/src/components/RoutesOverview.tsx +57 -0
  25. package/src/components/SwapDetailsPlaceholder.tsx +47 -0
  26. package/src/components/SwitchFromAndTo.tsx +4 -34
  27. package/src/components/TokenInfo.tsx +329 -0
  28. package/src/components/TokenPreview.tsx +187 -0
  29. package/src/languages/en.json +14 -0
  30. package/src/languages/tr.json +11 -0
  31. package/src/pages/ConfirmSwapPage.tsx +9 -20
  32. package/src/pages/Home.tsx +144 -101
  33. package/src/pages/SwapDetailsPage.tsx +2 -5
  34. package/src/utils/numbers.ts +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmSwapPage.d.ts","sourceRoot":"","sources":["../../src/pages/ConfirmSwapPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AA0CnD,wBAAgB,eAAe,CAAC,EAC9B,wBAAwB,GACzB,EAAE;IACD,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,qBA0NA"}
1
+ {"version":3,"file":"ConfirmSwapPage.d.ts","sourceRoot":"","sources":["../../src/pages/ConfirmSwapPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAyCnD,wBAAgB,eAAe,CAAC,EAC9B,wBAAwB,GACzB,EAAE;IACD,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,qBAgNA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Home.d.ts","sourceRoot":"","sources":["../../src/pages/Home.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AA8BzC,wBAAgB,IAAI,sBAgKnB"}
1
+ {"version":3,"file":"Home.d.ts","sourceRoot":"","sources":["../../src/pages/Home.tsx"],"names":[],"mappings":"AAWA,OAAO,KAA8B,MAAM,OAAO,CAAC;AA+DnD,wBAAgB,IAAI,sBA+JnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"SwapDetailsPage.d.ts","sourceRoot":"","sources":["../../src/pages/SwapDetailsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAgC1B,wBAAgB,eAAe,sBAqI9B"}
1
+ {"version":3,"file":"SwapDetailsPage.d.ts","sourceRoot":"","sources":["../../src/pages/SwapDetailsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AA6B1B,wBAAgB,eAAe,sBAqI9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"numbers.d.ts","sourceRoot":"","sources":["../../src/utils/numbers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,eAAO,MAAM,eAAe,MAAO,MAAM,yBAAkB,MAC7B,CAAC;AAE/B,eAAO,MAAM,eAAe,MAAO,MAAM,KAAG,MAM3C,CAAC;AAEF,eAAO,MAAM,cAAc,WACjB,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,gBAChC,MAAM,GAAG,IAAI,gBACb,MAAM,GAAG,IAAI,KACzB,MA6DF,CAAC;AAEF,eAAO,MAAM,qBAAqB,UACzB,SAAS,YACN,MAAM,KACf,MAEF,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,UAAU,KAAG,MAKpD,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQrE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAW5E;AAED,eAAO,MAAM,gBAAgB,SAAU,iBAAiB,GAAG,IAAI,WACc,CAAC;AAE9E,eAAO,MAAM,OAAO,SAAU,iBAAiB,KAAG,MAOnC,CAAC;AAEhB,eAAO,MAAM,YAAY,SAAU,MAAM,cAAc,MAAM,YACF,CAAC;AAE5D,eAAO,MAAM,gBAAgB,UAAW,MAAM,YACd,CAAC"}
1
+ {"version":3,"file":"numbers.d.ts","sourceRoot":"","sources":["../../src/utils/numbers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,eAAO,MAAM,eAAe,MAAO,MAAM,yBAAkB,MAC7B,CAAC;AAC/B,eAAO,MAAM,eAAe,MAAO,MAAM,KAAG,MAM3C,CAAC;AAEF,eAAO,MAAM,cAAc,WACjB,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,gBAChC,MAAM,GAAG,IAAI,gBACb,MAAM,GAAG,IAAI,KACzB,MA6DF,CAAC;AAEF,eAAO,MAAM,qBAAqB,UACzB,SAAS,YACN,MAAM,KACf,MAEF,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,UAAU,KAAG,MAIpD,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQrE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAW5E;AAED,eAAO,MAAM,gBAAgB,SAAU,iBAAiB,GAAG,IAAI,WACc,CAAC;AAE9E,eAAO,MAAM,OAAO,SAAU,iBAAiB,KAAG,MAOnC,CAAC;AAEhB,eAAO,MAAM,YAAY,SAAU,MAAM,cAAc,MAAM,YACF,CAAC;AAE5D,eAAO,MAAM,gBAAgB,UAAW,MAAM,YACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rango-dev/widget-embedded",
3
- "version": "0.10.1-next.0",
3
+ "version": "0.11.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -19,13 +19,13 @@
19
19
  "dependencies": {
20
20
  "@lingui/core": "4.2.1",
21
21
  "@lingui/react": "4.2.1",
22
- "@rango-dev/provider-all": "^0.13.0",
23
- "@rango-dev/queue-manager-core": "^0.13.0",
24
- "@rango-dev/queue-manager-rango-preset": "^0.13.0",
25
- "@rango-dev/queue-manager-react": "^0.13.0",
26
- "@rango-dev/ui": "^0.13.1-next.0",
27
- "@rango-dev/wallets-core": "^0.13.0",
28
- "@rango-dev/wallets-shared": "^0.13.0",
22
+ "@rango-dev/provider-all": "^0.14.0",
23
+ "@rango-dev/queue-manager-core": "^0.14.0",
24
+ "@rango-dev/queue-manager-rango-preset": "^0.14.0",
25
+ "@rango-dev/queue-manager-react": "^0.14.0",
26
+ "@rango-dev/ui": "^0.14.0",
27
+ "@rango-dev/wallets-core": "^0.14.0",
28
+ "@rango-dev/wallets-shared": "^0.14.0",
29
29
  "bignumber.js": "^9.1.1",
30
30
  "copy-to-clipboard": "^3.3.3",
31
31
  "dayjs": "^1.11.7",
@@ -1,6 +1,13 @@
1
+ import {
2
+ Button,
3
+ AddWalletIcon,
4
+ Typography,
5
+ styled,
6
+ Spinner,
7
+ Image,
8
+ } from '@rango-dev/ui';
1
9
  import React, { useEffect } from 'react';
2
10
  import { useNavigate } from 'react-router-dom';
3
- import { HeaderLayout } from '@rango-dev/ui';
4
11
  import { useWallets } from '@rango-dev/wallets-core';
5
12
  import { navigationRoutes } from '../constants/navigationRoutes';
6
13
  import { useUiStore } from '../store/ui';
@@ -13,10 +20,33 @@ import {
13
20
  } from '../utils/wallets';
14
21
  import { removeDuplicateFrom } from '../utils/common';
15
22
  import { WidgetConfig } from '../types';
23
+ import { i18n } from '@lingui/core';
16
24
  import { useBestRouteStore } from '../store/bestRoute';
17
25
  import { useMetaStore } from '../store/meta';
18
26
  import { useSettingsStore } from '../store/settings';
19
27
 
28
+ const Header = styled('div', {
29
+ display: 'flex',
30
+ width: '100%',
31
+ justifyContent: 'end',
32
+ '.balance': {
33
+ display: 'flex',
34
+ },
35
+ });
36
+
37
+ const WalletImages = styled('div', {
38
+ display: 'flex',
39
+ paddingLeft: '12px',
40
+ });
41
+
42
+ const WalletImageContainer = styled('div', {
43
+ marginLeft: -15,
44
+ marginRight: '$6',
45
+ '& img': {
46
+ borderRadius: '50%',
47
+ },
48
+ });
49
+
20
50
  export type LayoutProps = {
21
51
  config?: WidgetConfig;
22
52
  };
@@ -89,17 +119,40 @@ export function Layout({ config }: LayoutProps) {
89
119
 
90
120
  return (
91
121
  <>
92
- <HeaderLayout
93
- loadingStatus={loadingMetaStatus}
94
- connectedWalletsImages={connectedWalletsImages}
95
- connectedWallets={connectedWallets}
96
- totalBalance={totalBalance}
97
- fetchingBalance={fetchingBalance}
98
- onClick={() => {
99
- if (!connectWalletsButtonDisabled) navigate(navigationRoutes.wallets);
100
- }}>
101
- <AppRoutes config={config} />
102
- </HeaderLayout>
122
+ <Header>
123
+ <Button
124
+ size="small"
125
+ suffix={<AddWalletIcon size={20} />}
126
+ variant="ghost"
127
+ flexContent
128
+ loading={loadingMetaStatus === 'loading'}
129
+ disabled={loadingMetaStatus === 'failed'}
130
+ onClick={() => {
131
+ if (!connectWalletsButtonDisabled)
132
+ navigate(navigationRoutes.wallets);
133
+ }}
134
+ prefix={
135
+ connectedWalletsImages?.length ? (
136
+ <WalletImages>
137
+ {connectedWalletsImages.map((walletImage, index) => (
138
+ <WalletImageContainer key={index}>
139
+ <Image src={walletImage} size={24} />
140
+ </WalletImageContainer>
141
+ ))}
142
+ </WalletImages>
143
+ ) : null
144
+ }>
145
+ <div className="balance">
146
+ <Typography variant="body2">
147
+ {!connectedWallets?.length
148
+ ? i18n.t('Connect Wallet')
149
+ : `$${totalBalance || 0}`}
150
+ </Typography>
151
+ {fetchingBalance && <Spinner />}
152
+ </div>
153
+ </Button>
154
+ </Header>
155
+ <AppRoutes config={config} />
103
156
  </>
104
157
  );
105
158
  }
@@ -0,0 +1,33 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import React from 'react';
3
+ import { getPercentageChange } from '../utils/swap';
4
+ import { Typography } from '@rango-dev/ui';
5
+ import { numberToString } from '../utils/numbers';
6
+
7
+ interface PropTypes {
8
+ inputUsdValue: BigNumber | null;
9
+ outputUsdValue: BigNumber | null;
10
+ }
11
+
12
+ export function PercentageChange(props: PropTypes) {
13
+ const { inputUsdValue, outputUsdValue } = props;
14
+
15
+ if (!inputUsdValue || !outputUsdValue || !outputUsdValue.gt(0)) return null;
16
+
17
+ const percentageChange = getPercentageChange(
18
+ inputUsdValue.toNumber(),
19
+ outputUsdValue.toNumber()
20
+ );
21
+
22
+ const showPercentageChange = percentageChange?.lt(0);
23
+
24
+ return (
25
+ <>
26
+ {showPercentageChange && (
27
+ <Typography variant="caption" color="$error500">
28
+ {`(${numberToString(percentageChange, 0, 2)}%)`}
29
+ </Typography>
30
+ )}
31
+ </>
32
+ );
33
+ }
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { styled, ChevronRightIcon, GasIcon, Divider } from '@rango-dev/ui';
3
+ import { BestRouteResponse } from 'rango-sdk';
4
+
5
+ export const Container = styled('div', {
6
+ display: 'flex',
7
+ alignItems: 'center',
8
+ justifyContent: 'space-between',
9
+ padding: '$8',
10
+ borderRadius: '$5',
11
+ backgroundColor: '$neutral100',
12
+ color: '$neutral800',
13
+ fontSize: '$12',
14
+
15
+ '.routes': {
16
+ display: 'flex',
17
+ alignItems: 'center',
18
+ },
19
+ '.fee': {
20
+ display: 'flex',
21
+ alignItems: 'center',
22
+ },
23
+ });
24
+
25
+ interface PropTypes {
26
+ routes: BestRouteResponse | null;
27
+ totalFee?: string;
28
+ }
29
+ function RoutesOverview(props: PropTypes) {
30
+ if (!props.routes) return null;
31
+
32
+ const swaps = props.routes.result?.swaps;
33
+ return (
34
+ <Container>
35
+ <div className="routes">
36
+ {swaps?.map((swap, idx) => {
37
+ const isLast = idx + 1 == swaps.length;
38
+ return (
39
+ <React.Fragment key={idx}>
40
+ <div className="route">{swap.from.symbol}</div>
41
+ <ChevronRightIcon size={12} />
42
+ {isLast ? <div className="route">{swap.to.symbol}</div> : null}
43
+ </React.Fragment>
44
+ );
45
+ })}
46
+ </div>
47
+ {props.totalFee ? (
48
+ <div className="fee">
49
+ <GasIcon size={12} />
50
+ <Divider size={4} direction="horizontal" />${props.totalFee}
51
+ </div>
52
+ ) : null}
53
+ </Container>
54
+ );
55
+ }
56
+
57
+ export default RoutesOverview;
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import { SecondaryPage, Spinner, Alert, styled } from '@rango-dev/ui';
3
+ import { i18n } from '@lingui/core';
4
+
5
+ const PlaceholderContainer = styled('div', { height: '450px' });
6
+
7
+ export const LoaderContainer = styled('div', {
8
+ display: 'flex',
9
+ justifyContent: 'center',
10
+ width: '100%',
11
+ paddingTop: '33%',
12
+ flex: 1,
13
+ });
14
+
15
+ interface PropTypes {
16
+ requestId: string;
17
+ loading: boolean;
18
+ onBack: () => void;
19
+ }
20
+
21
+ export function SwapDetailsPlaceholder(props: PropTypes) {
22
+ const { requestId, loading, onBack } = props;
23
+
24
+ return (
25
+ <SecondaryPage
26
+ title={i18n.t('Swap Details')}
27
+ textField={false}
28
+ onBack={onBack}>
29
+ <PlaceholderContainer>
30
+ {loading ? (
31
+ <LoaderContainer>
32
+ <Spinner size={24} />
33
+ </LoaderContainer>
34
+ ) : (
35
+ <Alert
36
+ type="secondary"
37
+ title={i18n.t(
38
+ 'swapNotFound',
39
+ { requestId },
40
+ { message: 'Swap with request ID = ${requestId} not found.' }
41
+ )}
42
+ />
43
+ )}
44
+ </PlaceholderContainer>
45
+ </SecondaryPage>
46
+ );
47
+ }
@@ -1,10 +1,9 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
- import { useInRouterContext, useSearchParams } from 'react-router-dom';
3
- import { styled, Button, VerticalSwapIcon } from '@rango-dev/ui';
1
+ import { useEffect, useRef } from 'react';
2
+ import { useSearchParams } from 'react-router-dom';
4
3
  import { SearchParams } from '../constants/searchParams';
5
4
  import { useBestRouteStore } from '../store/bestRoute';
6
5
 
7
- function SwithFromAndTo({ count }: { count: number }) {
6
+ export function SwithFromAndTo({ count }: { count: number }) {
8
7
  const firstRender = useRef(true);
9
8
  const [searchParams, setSearchParams] = useSearchParams();
10
9
  const outputAmount = useBestRouteStore.use.outputAmount();
@@ -20,9 +19,7 @@ function SwithFromAndTo({ count }: { count: number }) {
20
19
  ...(toTokenString && { [SearchParams.FROM_TOKEN]: toTokenString }),
21
20
  ...(fromChainString && { [SearchParams.TO_CHAIN]: fromChainString }),
22
21
  ...(fromTokenString && { [SearchParams.TO_TOKEN]: fromTokenString }),
23
- ...(outputAmount && {
24
- [SearchParams.FROM_AMOUNT]: outputAmount.toString(),
25
- }),
22
+ ...(outputAmount && { [SearchParams.FROM_AMOUNT]: outputAmount.toString() }),
26
23
  });
27
24
  } else {
28
25
  firstRender.current = false;
@@ -31,30 +28,3 @@ function SwithFromAndTo({ count }: { count: number }) {
31
28
 
32
29
  return null;
33
30
  }
34
-
35
- const SwitchButtonContainer = styled('div', {
36
- position: 'absolute',
37
- bottom: '-12px',
38
- left: '50%',
39
- transform: 'translate(-50%, 10%)',
40
- });
41
-
42
- export function SwithFromAndToButton() {
43
- const switchFromAndTo = useBestRouteStore.use.switchFromAndTo();
44
- const isRouterInContext = useInRouterContext();
45
- const [count, setCount] = useState(0);
46
-
47
- return (
48
- <SwitchButtonContainer>
49
- <Button
50
- variant="ghost"
51
- onClick={() => {
52
- switchFromAndTo();
53
- setCount((prev) => prev + 1);
54
- }}>
55
- <VerticalSwapIcon size={32} />
56
- {isRouterInContext && <SwithFromAndTo count={count} />}
57
- </Button>
58
- </SwitchButtonContainer>
59
- );
60
- }
@@ -0,0 +1,329 @@
1
+ import React from 'react';
2
+ import {
3
+ AngleDownIcon,
4
+ Button,
5
+ InfoCircleIcon,
6
+ styled,
7
+ TextField,
8
+ Typography,
9
+ Image,
10
+ Divider,
11
+ } from '@rango-dev/ui';
12
+ import { useMetaStore } from '../store/meta';
13
+ import { BlockchainMeta, Token } from 'rango-sdk';
14
+ import { useNavigate } from 'react-router-dom';
15
+ import { useBestRouteStore } from '../store/bestRoute';
16
+ import { numberToString } from '../utils/numbers';
17
+ import BigNumber from 'bignumber.js';
18
+ import { getBalanceFromWallet } from '../utils/wallets';
19
+ import { useWalletsStore } from '../store/wallets';
20
+ import { Trans } from '@lingui/react';
21
+ import { i18n } from '@lingui/core';
22
+ import { PercentageChange } from './PercentageChange';
23
+
24
+ type PropTypes = (
25
+ | {
26
+ type: 'From';
27
+ inputAmount: string;
28
+ onAmountChange: (amount: string) => void;
29
+ }
30
+ | {
31
+ type: 'To';
32
+ outputAmount: BigNumber | null;
33
+ outputUsdValue: BigNumber | null;
34
+ }
35
+ ) & { chain: BlockchainMeta | null; token: Token | null };
36
+
37
+ const Box = styled('div', {
38
+ display: 'flex',
39
+ flexDirection: 'column',
40
+ width: '100%',
41
+ overflow: 'hidden',
42
+ });
43
+
44
+ const Container = styled('div', {
45
+ boxSizing: 'border-box',
46
+ borderRadius: '$5',
47
+ padding: '$8 $16 $16 $16',
48
+
49
+ variants: {
50
+ type: {
51
+ filled: {
52
+ backgroundColor: '$neutral100',
53
+ },
54
+ outlined: {
55
+ border: '1px solid $neutral100',
56
+ backgroundColor: '$surface',
57
+ },
58
+ },
59
+ },
60
+
61
+ defaultVariants: {
62
+ type: 'filled',
63
+ },
64
+
65
+ '.head': {
66
+ display: 'flex',
67
+ justifyContent: 'space-between',
68
+ alignItems: 'center',
69
+ minHeight: '32px',
70
+ },
71
+ '.form': {
72
+ display: 'flex',
73
+ width: '100%',
74
+ padding: '$2 0',
75
+ '.selectors': {
76
+ width: '35%',
77
+
78
+ '._text': {
79
+ whiteSpace: 'nowrap',
80
+ overflow: 'hidden',
81
+ textOverflow: 'ellipsis',
82
+ },
83
+ },
84
+ '.amount': {
85
+ width: '30%',
86
+ },
87
+ },
88
+ '.output-usd': {
89
+ display: 'flex',
90
+ div: {
91
+ display: 'flex',
92
+ paddingLeft: '$8',
93
+ },
94
+ },
95
+ });
96
+
97
+ const Options = styled('div', {
98
+ display: 'flex',
99
+ justifyContent: 'flex-end',
100
+
101
+ '.balance': {
102
+ display: 'flex',
103
+ alignItems: 'center',
104
+ },
105
+ });
106
+
107
+ const ImagePlaceholder = styled('span', {
108
+ width: '24px',
109
+ height: '24px',
110
+ backgroundColor: '$neutral100',
111
+ borderRadius: '99999px',
112
+ });
113
+
114
+ const OutputContainer = styled('div', {
115
+ windth: '100%',
116
+ height: '$48',
117
+ borderRadius: '$5',
118
+ backgroundColor: '$surface',
119
+ border: '1px solid transparent',
120
+ position: 'relative',
121
+ display: 'flex',
122
+ alignItems: 'center',
123
+ paddingLeft: '$8',
124
+ paddingRight: '$8',
125
+ });
126
+
127
+ export function TokenInfo(props: PropTypes) {
128
+ const { type, chain, token } = props;
129
+ const loadingStatus = useMetaStore.use.loadingStatus();
130
+ const fromChain = useBestRouteStore.use.fromChain();
131
+ const toChain = useBestRouteStore.use.toChain();
132
+ const inputUsdValue = useBestRouteStore.use.inputUsdValue();
133
+ const fromToken = useBestRouteStore.use.fromToken();
134
+ const setInputAmount = useBestRouteStore.use.setInputAmount();
135
+ const bestRoute = useBestRouteStore.use.bestRoute();
136
+ const inputAmount = useBestRouteStore.use.inputAmount();
137
+ const connectedWallets = useWalletsStore.use.connectedWallets();
138
+ const fetchingBestRoute = useBestRouteStore.use.loading();
139
+ const navigate = useNavigate();
140
+
141
+ const tokenBalance =
142
+ !!fromChain && !!fromToken
143
+ ? numberToString(
144
+ getBalanceFromWallet(
145
+ connectedWallets,
146
+ fromChain?.name,
147
+ fromToken?.symbol,
148
+ fromToken?.address
149
+ )?.amount || '0',
150
+ 8
151
+ )
152
+ : '0';
153
+
154
+ const tokenBalanceReal =
155
+ !!fromChain && !!fromToken
156
+ ? numberToString(
157
+ getBalanceFromWallet(
158
+ connectedWallets,
159
+ fromChain?.name,
160
+ fromToken?.symbol,
161
+ fromToken?.address
162
+ )?.amount || '0',
163
+ getBalanceFromWallet(
164
+ connectedWallets,
165
+ fromChain?.name,
166
+ fromToken?.symbol,
167
+ fromToken?.address
168
+ )?.decimal
169
+ )
170
+ : '0';
171
+
172
+ const ItemSuffix = (
173
+ <div
174
+ style={{
175
+ display: 'flex',
176
+ justifyContent: 'center',
177
+ alignItems: 'center',
178
+ }}>
179
+ {loadingStatus === 'failed' && <InfoCircleIcon color="error" size={24} />}
180
+ <AngleDownIcon />
181
+ </div>
182
+ );
183
+
184
+ return (
185
+ <Box>
186
+ <Container type={props.type === 'From' ? 'filled' : 'outlined'}>
187
+ <div className="head">
188
+ <Typography variant="body2" color="neutral800">
189
+ {type === 'From' ? (
190
+ <Trans id="swap from" message="From" />
191
+ ) : (
192
+ <Trans id="swap to" message="To" />
193
+ )}
194
+ </Typography>
195
+ {props.type === 'From' ? (
196
+ <Options>
197
+ <div
198
+ className="balance"
199
+ onClick={() => {
200
+ if (tokenBalance !== '0')
201
+ setInputAmount(tokenBalanceReal.split(',').join(''));
202
+ }}>
203
+ <Typography variant="body3" color="neutral600">
204
+ {i18n.t('Balance')}: {tokenBalance} {fromToken?.symbol || ''}
205
+ </Typography>
206
+ <Divider size={4} />
207
+ <Button type="primary" variant="ghost" size="compact">
208
+ <Trans id="maximum amount of asset" message="Max" />
209
+ </Button>
210
+ </div>
211
+ </Options>
212
+ ) : (
213
+ <div className="output-usd">
214
+ <PercentageChange
215
+ inputUsdValue={inputUsdValue}
216
+ outputUsdValue={props.outputUsdValue}
217
+ />
218
+ <div>
219
+ <Typography
220
+ variant="caption"
221
+ color="neutral600">{`$${numberToString(
222
+ props.outputUsdValue
223
+ )}`}</Typography>
224
+ </div>
225
+ </div>
226
+ )}
227
+ </div>
228
+ <div className="form">
229
+ <Button
230
+ className="selectors"
231
+ onClick={() => {
232
+ navigate(`${props.type.toLowerCase()}-chain`);
233
+ }}
234
+ variant="outlined"
235
+ disabled={loadingStatus === 'failed'}
236
+ loading={loadingStatus === 'loading'}
237
+ prefix={
238
+ loadingStatus === 'success' && chain ? (
239
+ <Image src={chain.logo} size={24} />
240
+ ) : (
241
+ <ImagePlaceholder />
242
+ )
243
+ }
244
+ suffix={ItemSuffix}
245
+ align="start"
246
+ size="large">
247
+ {loadingStatus === 'success' && chain
248
+ ? chain.displayName
249
+ : i18n.t('Chain')}
250
+ </Button>
251
+ <Divider size={12} direction="horizontal" />
252
+ <Button
253
+ className="selectors"
254
+ onClick={() => {
255
+ navigate(`${props.type.toLowerCase()}-token`);
256
+ }}
257
+ variant="outlined"
258
+ disabled={
259
+ loadingStatus === 'failed' ||
260
+ (type === 'From' && !fromChain) ||
261
+ (type === 'To' && !toChain)
262
+ }
263
+ loading={loadingStatus === 'loading'}
264
+ prefix={
265
+ loadingStatus === 'success' && token ? (
266
+ <Image src={token.image} size={24} />
267
+ ) : (
268
+ <ImagePlaceholder />
269
+ )
270
+ }
271
+ suffix={ItemSuffix}
272
+ size="large"
273
+ align="start">
274
+ {loadingStatus === 'success' && token
275
+ ? token.symbol
276
+ : i18n.t('Token')}
277
+ </Button>
278
+ <Divider size={12} direction="horizontal" />
279
+ <div className="amount">
280
+ {props.type === 'From' ? (
281
+ <TextField
282
+ type="number"
283
+ size="large"
284
+ autoFocus
285
+ placeholder="0"
286
+ style={{
287
+ position: 'relative',
288
+ backgroundColor: '$background !important',
289
+ }}
290
+ suffix={
291
+ <span
292
+ style={{
293
+ position: 'absolute',
294
+ right: '4px',
295
+ bottom: '2px',
296
+ }}>
297
+ <Typography
298
+ variant="caption"
299
+ color="neutral800">{`$${numberToString(
300
+ inputUsdValue
301
+ )}`}</Typography>
302
+ </span>
303
+ }
304
+ value={props.inputAmount || ''}
305
+ min={0}
306
+ onChange={
307
+ props.type === 'From'
308
+ ? (event) => {
309
+ props.onAmountChange(event.target.value);
310
+ }
311
+ : undefined
312
+ }
313
+ />
314
+ ) : (
315
+ <OutputContainer>
316
+ <Typography variant="h4">
317
+ {fetchingBestRoute && '?'}
318
+ {!!bestRoute?.result &&
319
+ `≈ ${numberToString(props.outputAmount)}`}
320
+ {(!inputAmount || inputAmount === '0') && '0'}
321
+ </Typography>
322
+ </OutputContainer>
323
+ )}
324
+ </div>
325
+ </div>
326
+ </Container>
327
+ </Box>
328
+ );
329
+ }