@rango-dev/widget-embedded 0.23.1-next.0 → 0.23.1-next.10

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 (119) hide show
  1. package/dist/components/AppRoutes.d.ts.map +1 -1
  2. package/dist/components/Layout/Layout.styles.d.ts +162 -0
  3. package/dist/components/Layout/Layout.styles.d.ts.map +1 -1
  4. package/dist/components/NoResult/NoResult.d.ts.map +1 -1
  5. package/dist/components/NoResult/NoResult.styles.d.ts.map +1 -1
  6. package/dist/components/Quote/Quote.d.ts.map +1 -1
  7. package/dist/components/Quote/Quote.types.d.ts +2 -0
  8. package/dist/components/Quote/Quote.types.d.ts.map +1 -1
  9. package/dist/components/Quote/QuoteCostDetails.d.ts.map +1 -1
  10. package/dist/components/Quote/{QuoteTrigger .d.ts → QuoteTrigger.d.ts} +1 -1
  11. package/dist/components/Quote/QuoteTrigger.d.ts.map +1 -0
  12. package/dist/components/QuoteWarningsAndErrors/HighValueLossWarningModal.d.ts.map +1 -1
  13. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts +0 -1
  14. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts.map +1 -1
  15. package/dist/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.d.ts.map +1 -1
  16. package/dist/components/Quotes/Quotes.d.ts +4 -0
  17. package/dist/components/Quotes/Quotes.d.ts.map +1 -0
  18. package/dist/components/Quotes/Quotes.styles.d.ts +487 -0
  19. package/dist/components/Quotes/Quotes.styles.d.ts.map +1 -0
  20. package/dist/components/Quotes/Quotes.types.d.ts +9 -0
  21. package/dist/components/Quotes/Quotes.types.d.ts.map +1 -0
  22. package/dist/components/Quotes/SelectStrategy.d.ts +5 -0
  23. package/dist/components/Quotes/SelectStrategy.d.ts.map +1 -0
  24. package/dist/components/Quotes/index.d.ts +2 -0
  25. package/dist/components/Quotes/index.d.ts.map +1 -0
  26. package/dist/components/common/ActivateTabAlert/ActivateTabAlert.d.ts.map +1 -1
  27. package/dist/constants/index.d.ts +1 -0
  28. package/dist/constants/index.d.ts.map +1 -1
  29. package/dist/constants/navigationRoutes.d.ts +0 -1
  30. package/dist/constants/navigationRoutes.d.ts.map +1 -1
  31. package/dist/constants/quote.d.ts +4 -3
  32. package/dist/constants/quote.d.ts.map +1 -1
  33. package/dist/constants/settings.d.ts +6 -0
  34. package/dist/constants/settings.d.ts.map +1 -0
  35. package/dist/containers/ExpandedQuotes/ExpandedQuotes.d.ts +5 -0
  36. package/dist/containers/ExpandedQuotes/ExpandedQuotes.d.ts.map +1 -0
  37. package/dist/containers/ExpandedQuotes/ExpandedQuotes.styles.d.ts +325 -0
  38. package/dist/containers/ExpandedQuotes/ExpandedQuotes.styles.d.ts.map +1 -0
  39. package/dist/containers/ExpandedQuotes/ExpandedQuotes.types.d.ts +9 -0
  40. package/dist/containers/ExpandedQuotes/ExpandedQuotes.types.d.ts.map +1 -0
  41. package/dist/containers/ExpandedQuotes/index.d.ts +2 -0
  42. package/dist/containers/ExpandedQuotes/index.d.ts.map +1 -0
  43. package/dist/containers/Inputs/Inputs.d.ts +4 -0
  44. package/dist/containers/Inputs/Inputs.d.ts.map +1 -0
  45. package/dist/containers/Inputs/Inputs.styles.d.ts +325 -0
  46. package/dist/containers/Inputs/Inputs.styles.d.ts.map +1 -0
  47. package/dist/containers/Inputs/Inputs.types.d.ts +7 -0
  48. package/dist/containers/Inputs/Inputs.types.d.ts.map +1 -0
  49. package/dist/containers/Inputs/index.d.ts +2 -0
  50. package/dist/containers/Inputs/index.d.ts.map +1 -0
  51. package/dist/containers/QuoteInfo/QuoteInfo.d.ts.map +1 -1
  52. package/dist/containers/QuoteInfo/QuoteInfo.types.d.ts +1 -0
  53. package/dist/containers/QuoteInfo/QuoteInfo.types.d.ts.map +1 -1
  54. package/dist/containers/Settings/Lists.d.ts +3 -0
  55. package/dist/containers/Settings/Lists.d.ts.map +1 -0
  56. package/dist/hooks/useMobileDetect.d.ts +3 -0
  57. package/dist/hooks/useMobileDetect.d.ts.map +1 -0
  58. package/dist/hooks/useSwapInput.d.ts.map +1 -1
  59. package/dist/index.d.ts +2 -2
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +2 -2
  62. package/dist/index.js.map +4 -4
  63. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  64. package/dist/pages/Home.d.ts +1 -0
  65. package/dist/pages/Home.d.ts.map +1 -1
  66. package/dist/pages/Routes.d.ts.map +1 -1
  67. package/dist/pages/SettingsPage.d.ts.map +1 -1
  68. package/dist/types/config.d.ts +5 -0
  69. package/dist/types/config.d.ts.map +1 -1
  70. package/dist/utils/common.d.ts +1 -0
  71. package/dist/utils/common.d.ts.map +1 -1
  72. package/package.json +6 -6
  73. package/src/components/AppRoutes.tsx +0 -5
  74. package/src/components/Layout/Layout.styles.ts +12 -7
  75. package/src/components/Layout/Layout.tsx +6 -6
  76. package/src/components/NoResult/NoResult.styles.ts +0 -2
  77. package/src/components/NoResult/NoResult.tsx +1 -0
  78. package/src/components/Quote/Quote.styles.ts +1 -1
  79. package/src/components/Quote/Quote.tsx +4 -2
  80. package/src/components/Quote/Quote.types.ts +2 -0
  81. package/src/components/Quote/QuoteCostDetails.tsx +10 -6
  82. package/src/components/Quote/{QuoteTrigger .tsx → QuoteTrigger.tsx} +3 -16
  83. package/src/components/QuoteWarningsAndErrors/HighValueLossWarningModal.tsx +15 -12
  84. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.ts +0 -1
  85. package/src/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.tsx +16 -13
  86. package/src/components/Quotes/Quotes.styles.ts +18 -0
  87. package/src/components/Quotes/Quotes.tsx +134 -0
  88. package/src/components/Quotes/Quotes.types.ts +9 -0
  89. package/src/components/Quotes/SelectStrategy.tsx +33 -0
  90. package/src/components/Quotes/index.ts +1 -0
  91. package/src/components/common/ActivateTabAlert/ActivateTabAlert.tsx +2 -4
  92. package/src/constants/index.ts +1 -0
  93. package/src/constants/navigationRoutes.ts +0 -1
  94. package/src/constants/quote.ts +22 -7
  95. package/src/constants/settings.ts +5 -0
  96. package/src/containers/ExpandedQuotes/ExpandedQuotes.styles.ts +30 -0
  97. package/src/containers/ExpandedQuotes/ExpandedQuotes.tsx +71 -0
  98. package/src/containers/ExpandedQuotes/ExpandedQuotes.types.ts +9 -0
  99. package/src/containers/ExpandedQuotes/index.ts +1 -0
  100. package/src/containers/Inputs/Inputs.styles.ts +12 -0
  101. package/src/containers/Inputs/Inputs.tsx +165 -0
  102. package/src/containers/Inputs/Inputs.types.ts +7 -0
  103. package/src/containers/Inputs/index.ts +1 -0
  104. package/src/containers/QuoteInfo/QuoteInfo.tsx +2 -0
  105. package/src/containers/QuoteInfo/QuoteInfo.types.ts +1 -0
  106. package/src/containers/Settings/Lists.tsx +265 -0
  107. package/src/hooks/useMobileDetect.ts +21 -0
  108. package/src/hooks/useSwapInput.ts +3 -1
  109. package/src/index.ts +2 -0
  110. package/src/pages/ConfirmSwapPage.tsx +0 -1
  111. package/src/pages/Home.tsx +146 -230
  112. package/src/pages/Routes.tsx +6 -69
  113. package/src/pages/SettingsPage.tsx +6 -184
  114. package/src/types/config.ts +6 -0
  115. package/src/utils/common.ts +3 -0
  116. package/dist/components/Quote/QuoteTrigger .d.ts.map +0 -1
  117. package/dist/pages/ThemePage.d.ts +0 -3
  118. package/dist/pages/ThemePage.d.ts.map +0 -1
  119. package/src/pages/ThemePage.tsx +0 -90
@@ -13,14 +13,12 @@ export function ActivateTabAlert(props: PropTypes) {
13
13
  variant="contained"
14
14
  size="xxsmall"
15
15
  type="warning">
16
- {i18n.t('Activate')}
16
+ {i18n.t('Activate this tab')}
17
17
  </Button>
18
18
  }
19
19
  type="warning"
20
20
  variant="alarm"
21
- title={i18n.t(
22
- 'Another tab is open and handles transactions. You can activate this tab.'
23
- )}
21
+ title={i18n.t('Another tab is open and handles transactions.')}
24
22
  />
25
23
  );
26
24
  }
@@ -6,5 +6,6 @@ export const SCANNER_BASE_URL = 'https://scan.rango.exchange';
6
6
 
7
7
  export const WIDGET_UI_ID = {
8
8
  SWAP_BOX_ID: 'rango-swap-box',
9
+ EXPANDED_BOX_ID: 'rango-expanded-box',
9
10
  ...UI_ID,
10
11
  };
@@ -5,7 +5,6 @@ export const navigationRoutes = {
5
5
  blockchains: 'blockchains',
6
6
  settings: 'settings',
7
7
  liquiditySources: 'liquidity-sources',
8
- themes: 'themes',
9
8
  bridges: 'bridges',
10
9
  exchanges: 'exchanges',
11
10
  languages: 'languages',
@@ -22,13 +22,28 @@ export type FeesGroup = {
22
22
  nonePayable: { [key in NameOfFees]?: SwapFee[] };
23
23
  };
24
24
 
25
- export const ROUTE_SORTING_STRATEGY: { [key in PreferenceType]: string } = {
26
- SPEED: i18n.t('Fastest Transfer'),
27
- NET_OUTPUT: i18n.t('Maximum Return'),
28
- FEE: i18n.t('Lowest Fee'),
29
- PRICE: i18n.t('Maximum Output'),
30
- SMART: i18n.t('Smart Routing'),
31
- };
25
+ export const ROUTE_STRATEGY: { value: PreferenceType; label: string }[] = [
26
+ {
27
+ value: 'SMART',
28
+ label: i18n.t('Smart Routing'),
29
+ },
30
+ {
31
+ value: 'FEE',
32
+ label: i18n.t('Lowest Fee'),
33
+ },
34
+ {
35
+ value: 'SPEED',
36
+ label: i18n.t('Fastest Transfer'),
37
+ },
38
+ {
39
+ value: 'NET_OUTPUT',
40
+ label: i18n.t('Maximum Return'),
41
+ },
42
+ {
43
+ value: 'PRICE',
44
+ label: i18n.t('Maximum Output'),
45
+ },
46
+ ];
32
47
 
33
48
  export const HIGH_PRIORITY_TAGS: TagValue[] = [
34
49
  'RECOMMENDED',
@@ -0,0 +1,5 @@
1
+ export enum ThemeModeEnum {
2
+ DARK = 'dark',
3
+ LIGHT = 'light',
4
+ AUTO = 'auto',
5
+ }
@@ -0,0 +1,30 @@
1
+ import { darkTheme, styled } from '@rango-dev/ui';
2
+
3
+ export const Container = styled('div', {
4
+ transition: 'width 0.2s, opacity 0.2s, margin-left 0.2s',
5
+ height: '700px',
6
+ width: '390px',
7
+ opacity: 1,
8
+ marginLeft: '$16',
9
+ backgroundColor: '$neutral100',
10
+ [`.${darkTheme} &`]: {
11
+ backgroundColor: '$neutral300',
12
+ },
13
+ '&.is-hidden': {
14
+ width: 0,
15
+ opacity: 0,
16
+ marginLeft: 0,
17
+ },
18
+ });
19
+
20
+ export const Content = styled('div', {
21
+ position: 'relative',
22
+ overflow: 'hidden',
23
+ padding: '$20',
24
+ flexGrow: 1,
25
+ display: 'flex',
26
+ flexDirection: 'column',
27
+ overflowY: 'auto',
28
+ borderRadius: '$primary',
29
+ backgroundColor: '$background',
30
+ });
@@ -0,0 +1,71 @@
1
+ import type { PropTypes } from './ExpandedQuotes.types';
2
+
3
+ import { i18n } from '@lingui/core';
4
+ import { Header } from '@rango-dev/ui';
5
+ import React, { useEffect, useState } from 'react';
6
+
7
+ import { HeaderButtons } from '../../components/HeaderButtons';
8
+ import { LayoutContainer } from '../../components/Layout/Layout.styles';
9
+ import { Quotes } from '../../components/Quotes';
10
+ import { SelectStrategy } from '../../components/Quotes/SelectStrategy';
11
+ import { WIDGET_UI_ID } from '../../constants';
12
+ import { getExpanded } from '../../utils/common';
13
+
14
+ import { Container, Content } from './ExpandedQuotes.styles';
15
+
16
+ export const TIME_TO_CLOSE_OPEN_EXPANDED = 100;
17
+
18
+ export function ExpandedQuotes(props: PropTypes) {
19
+ const { fetch, loading, onClickOnQuote, onClickRefresh, isVisible } = props;
20
+ const [isDelayedVisible, setIsDelayedVisible] = useState(false);
21
+ const containerClass = isDelayedVisible ? '' : 'is-hidden';
22
+
23
+ useEffect(() => {
24
+ let timeout: ReturnType<typeof setTimeout> | null = null;
25
+
26
+ if (isVisible) {
27
+ timeout = setTimeout(() => {
28
+ setIsDelayedVisible(true);
29
+ }, TIME_TO_CLOSE_OPEN_EXPANDED);
30
+ } else {
31
+ setIsDelayedVisible(false);
32
+ if (timeout) {
33
+ clearTimeout(timeout);
34
+ }
35
+ }
36
+
37
+ return () => {
38
+ if (timeout) {
39
+ clearTimeout(timeout);
40
+ }
41
+ };
42
+ }, [isVisible]);
43
+
44
+ return (
45
+ <Container
46
+ className={`${containerClass} ${LayoutContainer()}`}
47
+ id={WIDGET_UI_ID.EXPANDED_BOX_ID}>
48
+ <Header
49
+ title={i18n.t('Routes')}
50
+ suffix={
51
+ <>
52
+ <SelectStrategy container={getExpanded()} />
53
+ <HeaderButtons
54
+ onClickRefresh={onClickRefresh}
55
+ hidden={['history', 'notifications', 'settings']}
56
+ />
57
+ </>
58
+ }
59
+ />
60
+ <Content>
61
+ <Quotes
62
+ showModalFee={false}
63
+ fetch={fetch}
64
+ hasSort={false}
65
+ loading={loading}
66
+ onClickOnQuote={onClickOnQuote}
67
+ />
68
+ </Content>
69
+ </Container>
70
+ );
71
+ }
@@ -0,0 +1,9 @@
1
+ import type { SelectedQuote } from '../../types';
2
+
3
+ export type PropTypes = {
4
+ loading: boolean;
5
+ onClickOnQuote: (quote: SelectedQuote) => void;
6
+ fetch: (shouldChangeSelectedQuote?: boolean) => void;
7
+ onClickRefresh?: () => void;
8
+ isVisible: boolean;
9
+ };
@@ -0,0 +1 @@
1
+ export { ExpandedQuotes } from './ExpandedQuotes';
@@ -0,0 +1,12 @@
1
+ import { styled } from '@rango-dev/ui';
2
+
3
+ export const Container = styled('div', {
4
+ display: 'flex',
5
+ flexDirection: 'column',
6
+ gap: '$5',
7
+ alignSelf: 'stretch',
8
+ });
9
+
10
+ export const FromContainer = styled('div', {
11
+ position: 'relative',
12
+ });
@@ -0,0 +1,165 @@
1
+ import type { PropTypes } from './Inputs.types';
2
+
3
+ import { i18n } from '@lingui/core';
4
+ import { SwapInput } from '@rango-dev/ui';
5
+ import React from 'react';
6
+
7
+ import { SwitchFromAndToButton } from '../../components/SwitchFromAndTo';
8
+ import { errorMessages } from '../../constants/errors';
9
+ import {
10
+ PERCENTAGE_CHANGE_MAX_DECIMALS,
11
+ PERCENTAGE_CHANGE_MIN_DECIMALS,
12
+ TOKEN_AMOUNT_MAX_DECIMALS,
13
+ TOKEN_AMOUNT_MIN_DECIMALS,
14
+ USD_VALUE_MAX_DECIMALS,
15
+ USD_VALUE_MIN_DECIMALS,
16
+ } from '../../constants/routing';
17
+ import { useQuoteStore } from '../../store/quote';
18
+ import { useWalletsStore } from '../../store/wallets';
19
+ import { getContainer } from '../../utils/common';
20
+ import { formatTooltipNumbers, numberToString } from '../../utils/numbers';
21
+ import { getPriceImpact, getPriceImpactLevel } from '../../utils/quote';
22
+ import { canComputePriceImpact } from '../../utils/swap';
23
+ import { formatBalance, isFetchingBalance } from '../../utils/wallets';
24
+
25
+ import { Container, FromContainer } from './Inputs.styles';
26
+
27
+ export function Inputs(props: PropTypes) {
28
+ const { fetchingQuote, fetchMetaStatus, onClickToken } = props;
29
+ const {
30
+ fromToken,
31
+ fromBlockchain,
32
+ toToken,
33
+ toBlockchain,
34
+ setInputAmount,
35
+ inputAmount,
36
+ inputUsdValue,
37
+ outputAmount,
38
+ outputUsdValue,
39
+ selectedQuote,
40
+ } = useQuoteStore();
41
+ const { connectedWallets, getBalanceFor } = useWalletsStore();
42
+
43
+ const fromTokenBalance = fromToken ? getBalanceFor(fromToken) : null;
44
+
45
+ const fromTokenFormattedBalance =
46
+ formatBalance(fromTokenBalance)?.amount ?? '0';
47
+
48
+ const tokenBalanceReal =
49
+ !!fromBlockchain && !!fromToken
50
+ ? numberToString(fromTokenBalance?.amount, fromTokenBalance?.decimals)
51
+ : '0';
52
+
53
+ const fetchingBalance =
54
+ !!fromBlockchain &&
55
+ isFetchingBalance(connectedWallets, fromBlockchain.name);
56
+
57
+ const priceImpactInputCanNotBeComputed = !canComputePriceImpact(
58
+ selectedQuote,
59
+ inputAmount,
60
+ inputUsdValue
61
+ );
62
+
63
+ const priceImpactOutputCanNotBeComputed = !canComputePriceImpact(
64
+ selectedQuote,
65
+ inputAmount,
66
+ outputUsdValue
67
+ );
68
+
69
+ const percentageChange =
70
+ !inputUsdValue || !outputUsdValue || !outputUsdValue.gt(0)
71
+ ? null
72
+ : getPriceImpact(inputUsdValue.toString(), outputUsdValue.toString());
73
+ return (
74
+ <Container>
75
+ <FromContainer>
76
+ <SwapInput
77
+ label={i18n.t('From')}
78
+ mode="From"
79
+ onInputChange={setInputAmount}
80
+ balance={fromTokenFormattedBalance}
81
+ chain={{
82
+ displayName: fromBlockchain?.displayName || '',
83
+ image: fromBlockchain?.logo || '',
84
+ }}
85
+ token={{
86
+ displayName: fromToken?.symbol || '',
87
+ image: fromToken?.image || '',
88
+ }}
89
+ onClickToken={() => onClickToken('from')}
90
+ price={{
91
+ value: inputAmount,
92
+ usdValue: priceImpactInputCanNotBeComputed
93
+ ? undefined
94
+ : numberToString(
95
+ inputUsdValue,
96
+ USD_VALUE_MIN_DECIMALS,
97
+ USD_VALUE_MAX_DECIMALS
98
+ ),
99
+ realUsdValue: priceImpactInputCanNotBeComputed
100
+ ? undefined
101
+ : formatTooltipNumbers(inputUsdValue),
102
+ error: priceImpactInputCanNotBeComputed
103
+ ? errorMessages().unknownPriceError.impactTitle
104
+ : undefined,
105
+ }}
106
+ disabled={fetchMetaStatus === 'failed'}
107
+ loading={fetchMetaStatus === 'loading'}
108
+ loadingBalance={fetchingBalance}
109
+ tooltipContainer={getContainer()}
110
+ onSelectMaxBalance={() => {
111
+ if (fromTokenFormattedBalance !== '0') {
112
+ setInputAmount(tokenBalanceReal.split(',').join(''));
113
+ }
114
+ }}
115
+ />
116
+ <SwitchFromAndToButton />
117
+ </FromContainer>
118
+ <SwapInput
119
+ sharpBottomStyle={!!selectedQuote || fetchingQuote}
120
+ label={i18n.t('To')}
121
+ mode="To"
122
+ fetchingQuote={fetchingQuote}
123
+ chain={{
124
+ displayName: toBlockchain?.displayName || '',
125
+ image: toBlockchain?.logo || '',
126
+ }}
127
+ token={{
128
+ displayName: toToken?.symbol || '',
129
+ image: toToken?.image || '',
130
+ }}
131
+ percentageChange={numberToString(
132
+ getPriceImpact(inputUsdValue, outputUsdValue),
133
+ PERCENTAGE_CHANGE_MIN_DECIMALS,
134
+ PERCENTAGE_CHANGE_MAX_DECIMALS
135
+ )}
136
+ warningLevel={getPriceImpactLevel(percentageChange ?? 0)}
137
+ price={{
138
+ value: numberToString(
139
+ outputAmount,
140
+ TOKEN_AMOUNT_MIN_DECIMALS,
141
+ TOKEN_AMOUNT_MAX_DECIMALS
142
+ ),
143
+ usdValue: priceImpactOutputCanNotBeComputed
144
+ ? undefined
145
+ : numberToString(
146
+ outputUsdValue,
147
+ USD_VALUE_MIN_DECIMALS,
148
+ USD_VALUE_MAX_DECIMALS
149
+ ),
150
+ realValue: formatTooltipNumbers(outputAmount),
151
+ realUsdValue: priceImpactOutputCanNotBeComputed
152
+ ? undefined
153
+ : formatTooltipNumbers(outputUsdValue),
154
+ error: priceImpactOutputCanNotBeComputed
155
+ ? errorMessages().unknownPriceError.impactTitle
156
+ : undefined,
157
+ }}
158
+ onClickToken={() => onClickToken('to')}
159
+ disabled={fetchMetaStatus === 'failed'}
160
+ loading={fetchMetaStatus === 'loading'}
161
+ tooltipContainer={getContainer()}
162
+ />
163
+ </Container>
164
+ );
165
+ }
@@ -0,0 +1,7 @@
1
+ import type { FetchStatus } from '../../store/slices/data';
2
+
3
+ export type PropTypes = {
4
+ fetchingQuote: boolean;
5
+ fetchMetaStatus: FetchStatus;
6
+ onClickToken: (mode: 'from' | 'to') => void;
7
+ };
@@ -0,0 +1 @@
1
+ export { Inputs } from './Inputs';
@@ -22,6 +22,7 @@ export function QuoteInfo(props: PropTypes) {
22
22
  expanded = false,
23
23
  tagHidden,
24
24
  onClick,
25
+ showModalFee,
25
26
  selected,
26
27
  onClickAllRoutes,
27
28
  } = props;
@@ -57,6 +58,7 @@ export function QuoteInfo(props: PropTypes) {
57
58
  <Quote
58
59
  quote={quote}
59
60
  error={error}
61
+ showModalFee={showModalFee}
60
62
  warning={warning}
61
63
  tagHidden={tagHidden}
62
64
  selected={selected}
@@ -13,4 +13,5 @@ export type PropTypes = {
13
13
  expanded?: boolean;
14
14
  onClickAllRoutes?: () => void;
15
15
  selected?: boolean;
16
+ showModalFee?: boolean;
16
17
  };
@@ -0,0 +1,265 @@
1
+ import type { ThemeMode } from '../../store/slices/settings';
2
+ import type { ListPropTypes, SvgIconProps } from '@rango-dev/ui';
3
+
4
+ import { i18n } from '@lingui/core';
5
+ import {
6
+ AutoThemeIcon,
7
+ BridgeIcon,
8
+ ChevronRightIcon,
9
+ DarkModeIcon,
10
+ Divider,
11
+ DoneIcon,
12
+ ExchangeIcon,
13
+ InfoIcon,
14
+ LanguageIcon,
15
+ LightModeIcon,
16
+ List,
17
+ ListItem,
18
+ ListItemButton,
19
+ Skeleton,
20
+ styled,
21
+ Switch,
22
+ Tabs,
23
+ Tooltip,
24
+ Typography,
25
+ } from '@rango-dev/ui';
26
+ import React from 'react';
27
+ import { useNavigate } from 'react-router-dom';
28
+
29
+ import { SlippageTooltipContainer as TooltipContainer } from '../../components/Slippage/Slippage.styles';
30
+ import { navigationRoutes } from '../../constants/navigationRoutes';
31
+ import { ThemeModeEnum } from '../../constants/settings';
32
+ import { useAppStore } from '../../store/AppStore';
33
+ import { getContainer } from '../../utils/common';
34
+ import { getUniqueSwappersGroups, isFeatureHidden } from '../../utils/settings';
35
+
36
+ const ThemeSection = styled('div', {
37
+ width: '202px',
38
+ height: '$40',
39
+ });
40
+
41
+ const themesList = [
42
+ {
43
+ id: ThemeModeEnum.LIGHT,
44
+ icon: <LightModeIcon color="black" size={16} />,
45
+ tooltip: (
46
+ <Typography size="xsmall" variant="body">
47
+ {i18n.t('Light')}
48
+ </Typography>
49
+ ),
50
+ },
51
+ {
52
+ id: ThemeModeEnum.DARK,
53
+ icon: <DarkModeIcon color="black" size={16} />,
54
+ tooltip: (
55
+ <Typography size="xsmall" variant="body">
56
+ {i18n.t('Dark')}
57
+ </Typography>
58
+ ),
59
+ },
60
+ {
61
+ id: ThemeModeEnum.AUTO,
62
+ icon: <AutoThemeIcon color="black" size={16} />,
63
+ tooltip: (
64
+ <Typography size="xsmall" variant="body">
65
+ {i18n.t('Auto')}
66
+ </Typography>
67
+ ),
68
+ },
69
+ ];
70
+
71
+ const getThemeIcon = (theme: ThemeMode) => {
72
+ const iconProps: SvgIconProps = { color: 'gray', size: 12 };
73
+
74
+ switch (theme) {
75
+ case 'auto':
76
+ return <AutoThemeIcon {...iconProps} />;
77
+ case 'dark':
78
+ return <DarkModeIcon {...iconProps} />;
79
+ default:
80
+ return <LightModeIcon {...iconProps} />;
81
+ }
82
+ };
83
+
84
+ export function SettingsLists() {
85
+ const navigate = useNavigate();
86
+ const { theme: themeConfig } = useAppStore().config;
87
+ const { setTheme, theme } = useAppStore();
88
+
89
+ const fetchStatus = useAppStore().fetchStatus;
90
+ const swappers = useAppStore().swappers();
91
+ const disabledLiquiditySources = useAppStore().getDisabledLiquiditySources();
92
+ const {
93
+ config: { features },
94
+ } = useAppStore();
95
+ const isThemeHidden = isFeatureHidden('theme', features);
96
+ const isLiquidityHidden = isFeatureHidden('liquiditySource', features);
97
+ const isLanguageHidden = isFeatureHidden('language', features);
98
+
99
+ const infiniteApprove = useAppStore().infiniteApprove;
100
+ const toggleInfiniteApprove = useAppStore().toggleInfiniteApprove;
101
+
102
+ const supportedUniqueSwappersGroups = getUniqueSwappersGroups(
103
+ swappers,
104
+ disabledLiquiditySources
105
+ );
106
+
107
+ const bridgeSources = supportedUniqueSwappersGroups.filter(
108
+ (uniqueItem) =>
109
+ uniqueItem.type === 'BRIDGE' || uniqueItem.type === 'AGGREGATOR'
110
+ );
111
+
112
+ const totalBridgeSources = bridgeSources.length;
113
+ const totalSelectedBridgeSources = bridgeSources.filter(
114
+ (uniqueItem) => uniqueItem.selected
115
+ ).length;
116
+
117
+ const exchangeSources = supportedUniqueSwappersGroups.filter(
118
+ (uniqueItem) => uniqueItem.type === 'DEX'
119
+ );
120
+
121
+ const totalExchangeSources = exchangeSources.length;
122
+ const totalSelectedExchangeSources = exchangeSources.filter(
123
+ (uniqueItem) => uniqueItem.selected
124
+ ).length;
125
+
126
+ const handleEndItem = (totalSelected: number, total: number) => {
127
+ switch (fetchStatus) {
128
+ case 'loading':
129
+ return <Skeleton variant="text" size="medium" width={50} />;
130
+ case 'failed':
131
+ return (
132
+ <Typography variant="body" size="medium" color="$error500">
133
+ {i18n.t('Loading failed')}
134
+ </Typography>
135
+ );
136
+ default:
137
+ return (
138
+ <Typography variant="body" size="medium">
139
+ {`${totalSelected} / ${total}`}
140
+ </Typography>
141
+ );
142
+ }
143
+ };
144
+
145
+ const bridgeItem = {
146
+ id: 'bridge-item',
147
+ title: (
148
+ <Typography variant="title" size="xmedium">
149
+ {i18n.t('Enabled bridges')}
150
+ </Typography>
151
+ ),
152
+ end: (
153
+ <>
154
+ {handleEndItem(totalSelectedBridgeSources, totalBridgeSources)}
155
+ <Divider direction="horizontal" size={8} />
156
+ <ChevronRightIcon color="black" />
157
+ </>
158
+ ),
159
+ onClick: () => navigate(navigationRoutes.bridges),
160
+ start: <BridgeIcon color="gray" size={12} />,
161
+ };
162
+
163
+ const exchangeItem = {
164
+ id: 'exchange-item',
165
+ title: (
166
+ <Typography variant="title" size="xmedium">
167
+ {i18n.t('Enabled exchanges')}
168
+ </Typography>
169
+ ),
170
+ end: (
171
+ <>
172
+ {handleEndItem(totalSelectedExchangeSources, totalExchangeSources)}
173
+ <Divider direction="horizontal" size={8} />
174
+ <ChevronRightIcon color="gray" />
175
+ </>
176
+ ),
177
+ start: <ExchangeIcon color="gray" size={12} />,
178
+ onClick: () => navigate(navigationRoutes.exchanges),
179
+ };
180
+
181
+ const languageItem = {
182
+ id: 'language-item',
183
+ title: (
184
+ <Typography variant="title" size="xmedium">
185
+ {i18n.t('Language')}
186
+ </Typography>
187
+ ),
188
+ start: <LanguageIcon color="gray" size={12} />,
189
+ end: <ChevronRightIcon color="gray" />,
190
+ onClick: () => navigate(navigationRoutes.languages),
191
+ };
192
+
193
+ const infiniteApprovalItem = {
194
+ id: 'infinite-approval-item',
195
+ title: (
196
+ <>
197
+ <Typography variant="title" size="xmedium">
198
+ {i18n.t('Infinite approval')}
199
+ </Typography>
200
+ <Divider direction="horizontal" size={4} />
201
+ <Tooltip
202
+ side="top"
203
+ sideOffset={4}
204
+ container={getContainer()}
205
+ content={
206
+ <TooltipContainer>
207
+ <Typography variant="label" size="medium" color="neutral700">
208
+ {i18n.t(
209
+ "Enabling the 'Infinite approval' mode grants unrestricted access to smart contracts of DEXes/Bridges, allowing them to utilize the approved token amount without limitations."
210
+ )}
211
+ </Typography>
212
+ </TooltipContainer>
213
+ }>
214
+ <InfoIcon color="gray" />
215
+ </Tooltip>
216
+ </>
217
+ ),
218
+ start: <DoneIcon color="gray" size={12} />,
219
+ end: <Switch checked={infiniteApprove} />,
220
+ onClick: toggleInfiniteApprove,
221
+ };
222
+
223
+ const themeItem = {
224
+ id: 'theme-item',
225
+ type: <ListItem />,
226
+ title: (
227
+ <Typography variant="title" size="xmedium">
228
+ {i18n.t('Theme')}
229
+ </Typography>
230
+ ),
231
+ end: (
232
+ <ThemeSection>
233
+ <Tabs
234
+ container={getContainer()}
235
+ items={themesList}
236
+ value={theme}
237
+ onChange={(item) => setTheme(item.id as ThemeMode)}
238
+ type="primary"
239
+ borderRadius="small"
240
+ />
241
+ </ThemeSection>
242
+ ),
243
+ start: getThemeIcon(theme),
244
+ };
245
+
246
+ const settingItems: ListPropTypes['items'] = isLiquidityHidden
247
+ ? []
248
+ : [bridgeItem, exchangeItem];
249
+
250
+ if (!isLanguageHidden) {
251
+ settingItems.push(languageItem);
252
+ }
253
+ settingItems.push(infiniteApprovalItem);
254
+
255
+ if (!themeConfig?.singleTheme && !isThemeHidden) {
256
+ settingItems.push(themeItem);
257
+ }
258
+
259
+ return (
260
+ <List
261
+ type={<ListItemButton hasDivider id="_" onClick={() => console.log()} />}
262
+ items={settingItems}
263
+ />
264
+ );
265
+ }