Skip to content

Commit

Permalink
feat: revamped settings page
Browse files Browse the repository at this point in the history
  • Loading branch information
chybisov committed Feb 14, 2023
1 parent 8eab2f7 commit 1b87761
Show file tree
Hide file tree
Showing 31 changed files with 352 additions and 348 deletions.
1 change: 1 addition & 0 deletions packages/widget-playground/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const widgetBaseConfig: WidgetConfig = {
buildSwapUrl: true,
// disabledUI: ['toAddress', 'fromAmount', 'toToken', 'fromToken'],
// requiredUI: ['toAddress'],
// slippage: 0.003,
sdkConfig: {
// apiUrl: 'https://staging.li.quest/v1/',
defaultRouteOptions: {
Expand Down
9 changes: 9 additions & 0 deletions packages/widget/src/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { NotFound } from './components/NotFound';
import { ActiveSwapsPage } from './pages/ActiveSwapsPage';
import { MainPage } from './pages/MainPage';
import { SelectChainPage } from './pages/SelectChainPage';
import { SelectEnabledToolsPage } from './pages/SelectEnabledToolsPage';
import { SelectTokenPage } from './pages/SelectTokenPage';
import { SelectWalletPage } from './pages/SelectWalletPage';
import { SettingsPage } from './pages/SettingsPage';
Expand All @@ -22,6 +23,14 @@ export const AppRoutes = () => {
path: navigationRoutes.settings,
element: <SettingsPage />,
},
{
path: `${navigationRoutes.settings}/${navigationRoutes.bridges}`,
element: <SelectEnabledToolsPage type="Bridges" />,
},
{
path: `${navigationRoutes.settings}/${navigationRoutes.exchanges}`,
element: <SelectEnabledToolsPage type="Exchanges" />,
},
{
path: navigationRoutes.fromToken,
element: <SelectTokenPage formType="from" />,
Expand Down
4 changes: 4 additions & 0 deletions packages/widget/src/components/Header/NavigationHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export const NavigationHeader: React.FC = () => {
return t(`header.selectWallet`);
case navigationRoutes.settings:
return t(`header.settings`);
case navigationRoutes.bridges:
return t(`settings.enabledBridges`);
case navigationRoutes.exchanges:
return t(`settings.enabledExchanges`);
case navigationRoutes.swapHistory:
return t(`header.swapHistory`);
case navigationRoutes.fromToken:
Expand Down
12 changes: 12 additions & 0 deletions packages/widget/src/components/ListItemButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ListItemButton as MuiListItemButton } from '@mui/material';
import { styled } from '@mui/material/styles';
import { getContrastAlphaColor } from '../utils';

export const ListItemButton = styled(MuiListItemButton)(({ theme }) => ({
borderRadius: theme.shape.borderRadius,
paddingLeft: theme.spacing(1.5),
height: 56,
'&:hover': {
backgroundColor: getContrastAlphaColor(theme, '4%'),
},
}));
9 changes: 9 additions & 0 deletions packages/widget/src/components/ListItemText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ListItemText as MuiListItemText } from '@mui/material';
import { listItemTextClasses } from '@mui/material/ListItemText';
import { styled } from '@mui/material/styles';

export const ListItemText = styled(MuiListItemText)(({ theme }) => ({
[`.${listItemTextClasses.primary}`]: {
fontWeight: 400,
},
}));
1 change: 1 addition & 0 deletions packages/widget/src/components/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const Select = styled(MuiSelect, {
},
[`.${selectClasses.icon}`]: {
right: 10,
color: theme.palette.text.primary,
},
[`.${listItemIconClasses.root}`]: {
minWidth: 38,
Expand Down
13 changes: 3 additions & 10 deletions packages/widget/src/components/TokenList/TokenList.style.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import {
ListItem as MuiListItem,
ListItemButton as MuiListItemButton,
} from '@mui/material';
import { ListItem as MuiListItem } from '@mui/material';
import { listItemSecondaryActionClasses } from '@mui/material/ListItemSecondaryAction';
import { listItemTextClasses } from '@mui/material/ListItemText';
import { styled } from '@mui/material/styles';
import { getContrastAlphaColor } from '../../utils';
import { ListItemButton as ListItemButtonBase } from '../ListItemButton';

export const ListItemButton = styled(MuiListItemButton)(({ theme }) => ({
borderRadius: theme.shape.borderRadius,
export const ListItemButton = styled(ListItemButtonBase)(({ theme }) => ({
paddingLeft: theme.spacing(1.5),
paddingRight: theme.spacing(1.5),
height: 64,
width: '100%',
'&:hover': {
backgroundColor: getContrastAlphaColor(theme, '4%'),
},
}));

export const ListItem = styled(MuiListItem)(({ theme }) => ({
Expand Down
2 changes: 1 addition & 1 deletion packages/widget/src/config/env.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export const env = {
LIFI_API_URL: 'https://li.quest/v1/', // 'https://developkub.li.finance/v1/',
LIFI_API_URL: 'https://li.quest/v1/', // 'https://develop.li.quest/v1/',
};
69 changes: 29 additions & 40 deletions packages/widget/src/hooks/useTools.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,42 @@
/* eslint-disable no-underscore-dangle */
import type { Bridge, Exchange } from '@lifi/sdk';
import type { ToolsResponse } from '@lifi/sdk';
import { useQuery } from '@tanstack/react-query';
import { useMemo } from 'react';
import { isItemAllowed, useLiFi, useWidgetConfig } from '../providers';
import { useSettingsStoreContext } from '../stores';

interface WidgetBridge extends Omit<Bridge, 'key'> {
key: string;
}

type FormattedTool<T, K extends keyof T> = Record<string, Pick<T, K>>;

export const useTools = () => {
const lifi = useLiFi();
const { bridges, exchanges } = useWidgetConfig();
const settingsStoreContext = useSettingsStoreContext();
const { data } = useQuery(['tools'], () => lifi.getTools(), {
onSuccess(data) {
const { initializeTools } = settingsStoreContext.getState();
initializeTools(
'Bridges',
data.bridges
.filter((bridge) => isItemAllowed(bridge.key, bridges))
.map((bridge) => bridge.key),
);
initializeTools(
'Exchanges',
data.exchanges
.filter((exchange) => isItemAllowed(exchange.key, exchanges))
.map((exchange) => exchange.key),
);
const { data } = useQuery(
['tools'],
async (): Promise<ToolsResponse> => {
const tools = await lifi.getTools();
return {
bridges: tools.bridges.filter((bridge) =>
isItemAllowed(bridge.key, bridges),
),
exchanges: tools.exchanges.filter((exchange) =>
isItemAllowed(exchange.key, exchanges),
),
};
},
{
onSuccess(data) {
const { initializeTools } = settingsStoreContext.getState();
initializeTools(
'Bridges',
data.bridges.map((bridge) => bridge.key),
);
initializeTools(
'Exchanges',
data.exchanges.map((exchange) => exchange.key),
);
},
refetchInterval: 180000,
staleTime: 180000,
},
refetchInterval: 180000,
staleTime: 180000,
});

const formattedTools = useMemo(
() => ({
bridges: data?.bridges.reduce((bridges, bridge) => {
bridges[bridge.key] = bridge;
return bridges;
}, {} as FormattedTool<WidgetBridge, 'key' | 'name' | 'logoURI'>),
exchanges: data?.exchanges.reduce((exchanges, exchange) => {
exchanges[exchange.key] = exchange;
return exchanges;
}, {} as FormattedTool<Exchange, 'key' | 'name' | 'logoURI'>),
}),
[data?.bridges, data?.exchanges],
);

return { tools: data, formattedTools };
return { tools: data };
};
12 changes: 8 additions & 4 deletions packages/widget/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"contactSupport": "Contact support",
"continue": "Continue",
"copyAddress": "Copy address",
"viewOnExplorer": "View on explorer",
"dark": "Dark",
"delete": "Delete",
"disconnect": "Disconnect",
Expand All @@ -19,6 +18,8 @@
"ok": "Ok",
"okay": "Okay",
"removeSwap": "Remove swap",
"reset": "Reset",
"resetSettings": "Reset settings",
"restartSwap": "Restart swap",
"reviewGasSwap": "Review gas swap",
"reviewSwap": "Review swap",
Expand All @@ -27,7 +28,8 @@
"startGasSwap": "Start gas swap",
"startSwap": "Start swap",
"swap": "Swap",
"tryAgain": "Try again"
"tryAgain": "Try again",
"viewOnExplorer": "View on explorer"
},
"format": {
"currency": "{{value, currency(currency: USD)}}",
Expand Down Expand Up @@ -201,15 +203,17 @@
"highValueLoss": "The value of the received tokens is significantly lower than the swapped tokens and transaction cost.",
"insufficientFunds": "You don't have enough funds to execute the swap.",
"insufficientGas": "You need to add at least:",
"rateChanged": "The exchange rate has changed. By continuing the swap, you'll accept the new rate."
"rateChanged": "The exchange rate has changed. By continuing the swap, you'll accept the new rate.",
"resetSettings": "This will reset your route priority, slippage, gas price, enabled bridges and exchanges."
},
"title": {
"deleteActiveSwaps": "Delete all active swaps?",
"deleteSwap": "Delete this swap?",
"deleteSwapHistory": "Delete swap history?",
"highValueLoss": "High value loss",
"insufficientGas": "Insufficient gas",
"rateChanged": "Rate changed"
"rateChanged": "Rate changed",
"resetSettings": "Reset settings?"
}
}
},
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { ExtendedChain } from '@lifi/sdk';
import { Avatar, Container, List, ListItemAvatar } from '@mui/material';
import { useChainSelect } from '../../components/ChainSelect';
import { ListItemButton } from '../../components/ListItemButton';
import { ListItemText } from '../../components/ListItemText';
import { useTokenSelect } from '../../components/TokenList';
import { useNavigateBack } from '../../hooks';
import { ListItemButton, ListItemText } from './SelectChainPage.style';
import type { SelectChainPageProps } from './types';

export const SelectChainPage: React.FC<SelectChainPageProps> = ({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { styled } from '@mui/material/styles';
import { ListItemButton as ListItemButtonBase } from '../../components/ListItemButton';

export const ListItemButton = styled(ListItemButtonBase)(({ theme }) => ({
paddingRight: theme.spacing(1),
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {
CheckBox,
CheckBoxOutlineBlankOutlined,
CheckBoxOutlined,
IndeterminateCheckBoxOutlined,
} from '@mui/icons-material';
import {
Avatar,
Container,
IconButton,
List,
ListItemAvatar,
} from '@mui/material';
import { useHeaderActionStore } from '../../components/Header';

import { useEffect } from 'react';
import { shallow } from 'zustand/shallow';
import { ListItemText } from '../../components/ListItemText';
import { useTools } from '../../hooks';
import { useSettingsStore } from '../../stores';
import { ListItemButton } from './SelectEnabledToolsPage.style';

export const SelectEnabledToolsPage: React.FC<{
type: 'Bridges' | 'Exchanges';
}> = ({ type }) => {
const typeKey = type.toLowerCase() as 'bridges' | 'exchanges';
const { tools } = useTools();
const [enabledTools, setTools] = useSettingsStore(
(state) => [state[`enabled${type}`], state.setTools],
shallow,
);

const handleClick = (key: string) => {
if (!tools) {
return;
}
const toolKeys = tools[typeKey].map((tool) => tool.key);
if (enabledTools?.includes(key)) {
setTools(
type,
enabledTools.filter((toolKey) => toolKey !== key),
toolKeys,
);
} else {
setTools(type, [...enabledTools, key], toolKeys);
}
};

useEffect(() => {
const allToolsSelected = tools?.[typeKey].length === enabledTools.length;
const toggleCheckboxes = () => {
if (!tools) {
return;
}
const toolKeys = tools[typeKey].map((tool) => tool.key);
if (allToolsSelected) {
setTools(type, [], toolKeys);
} else {
setTools(type, toolKeys, toolKeys);
}
};
return useHeaderActionStore.getState().setAction(
<IconButton size="medium" edge="end" onClick={toggleCheckboxes}>
{allToolsSelected ? (
<CheckBoxOutlined />
) : enabledTools.length ? (
<IndeterminateCheckBoxOutlined />
) : (
<CheckBoxOutlineBlankOutlined />
)}
</IconButton>,
);
}, [enabledTools.length, setTools, tools, type, typeKey]);

return (
<Container disableGutters>
<List
sx={{
paddingLeft: 1.5,
paddingRight: 1.5,
}}
>
{tools?.[typeKey].map((tool) => (
<ListItemButton
key={tool.name}
onClick={() => handleClick(tool.key)}
disableRipple
>
<ListItemAvatar>
<Avatar src={tool.logoURI} alt={tool.name}>
{tool.name[0]}
</Avatar>
</ListItemAvatar>
<ListItemText primary={tool.name} />
{enabledTools?.includes(tool.key) ? (
<CheckBox color="primary" />
) : (
<CheckBoxOutlineBlankOutlined />
)}
</ListItemButton>
))}
</List>
</Container>
);
};
1 change: 1 addition & 0 deletions packages/widget/src/pages/SelectEnabledToolsPage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './SelectEnabledToolsPage';
Loading

0 comments on commit 1b87761

Please sign in to comment.