diff --git a/packages/widget-embedded/src/index.tsx b/packages/widget-embedded/src/index.tsx index f3b4f951c..0f5f824e8 100644 --- a/packages/widget-embedded/src/index.tsx +++ b/packages/widget-embedded/src/index.tsx @@ -12,8 +12,10 @@ const root = createRoot(rootElement); const config: WidgetConfig = { enabledChains: JSON.parse(process.env.LIFI_ENABLED_CHAINS_JSON!), - fromChain: 'eth', - // toChain: 'okt', + fromChain: 'pol', + toChain: 'bsc', + fromToken: '0x0000000000000000000000000000000000000000', + toToken: '0xcc42724c6683b7e57334c4e856f4c9965ed682bd', useInternalWalletManagement: true, containerStyle: { width: 480, diff --git a/packages/widget/src/components/StepActions/StepActions.style.tsx b/packages/widget/src/components/StepActions/StepActions.style.tsx new file mode 100644 index 000000000..2a8896622 --- /dev/null +++ b/packages/widget/src/components/StepActions/StepActions.style.tsx @@ -0,0 +1,43 @@ +import { + StepConnector as MuiStepConnector, + StepContent as MuiStepContent, + StepLabel as MuiStepLabel, +} from '@mui/material'; +import { stepConnectorClasses } from '@mui/material/StepConnector'; +import { stepContentClasses } from '@mui/material/StepContent'; +import { stepLabelClasses } from '@mui/material/StepLabel'; +import { styled } from '@mui/material/styles'; + +export const StepIcon = styled('span')(({ theme }) => ({ + width: 12, + height: 12, + borderRadius: '50%', + border: `2px solid ${theme.palette.grey[300]}`, +})); + +export const StepConnector = styled(MuiStepConnector)(({ theme }) => ({ + marginLeft: theme.spacing(1.875), + [`.${stepConnectorClasses.line}`]: { + minHeight: 8, + borderLeftWidth: 2, + borderColor: theme.palette.grey[300], + }, +})); + +export const StepLabel = styled(MuiStepLabel)(({ theme }) => ({ + padding: 0, + [`.${stepLabelClasses.iconContainer}`]: { + paddingLeft: theme.spacing(1), + paddingRight: theme.spacing(3), + }, +})); + +export const StepContent = styled(MuiStepContent)(({ theme }) => ({ + borderLeft: `2px solid ${theme.palette.grey[300]}`, + marginLeft: theme.spacing(1.875), + paddingLeft: theme.spacing(3.9375), + [`&.${stepContentClasses.last}`]: { + borderLeft: 'none', + paddingLeft: theme.spacing(4.1875), + }, +})); diff --git a/packages/widget/src/components/StepActions/StepActions.tsx b/packages/widget/src/components/StepActions/StepActions.tsx new file mode 100644 index 000000000..59ddc638c --- /dev/null +++ b/packages/widget/src/components/StepActions/StepActions.tsx @@ -0,0 +1,150 @@ +import { LifiStep, Step } from '@lifinance/sdk'; +import { ArrowForward as ArrowForwardIcon } from '@mui/icons-material'; +import { + Avatar, + Box, + Step as MuiStep, + Stepper, + Typography, + TypographyProps, +} from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { useChains } from '../../hooks'; +import LiFiLogo from '../../icons/LiFiLogo.svg'; +import { formatTokenAmount } from '../../utils/format'; +import { + StepConnector, + StepContent, + StepIcon, + StepLabel, +} from './StepActions.style'; +import { StepActionsProps } from './types'; + +export const StepActions: React.FC = ({ + step, + dense, + ...other +}) => { + const StepDetailsLabel = + step.type === 'cross' || step.type === 'lifi' + ? CrossStepDetailsLabel + : SwapStepDetailsLabel; + const isFullView = !dense && (step as LifiStep).includedSteps?.length; + return ( + + + + {step.toolDetails.name[0]} + + + {step.type === 'lifi' + ? 'LI.FI Smart Contract' + : step.toolDetails.name} + + + {isFullView ? ( + } + activeStep={-1} + > + {(step as LifiStep).includedSteps.map((step) => ( + + + + + + + + + ))} + + ) : ( + <> + + + + )} + + ); +}; + +export const StepDetailsContent: React.FC<{ step: Step } & TypographyProps> = ({ + step, + ...other +}) => { + return ( + + {formatTokenAmount( + step.estimate.fromAmount, + step.action.fromToken.decimals, + )}{' '} + {step.action.fromToken.symbol} + + {formatTokenAmount( + step.estimate.toAmount, + step.action.toToken.decimals, + )}{' '} + {step.action.toToken.symbol} + + ); +}; + +export const CrossStepDetailsLabel: React.FC< + { step: Step } & TypographyProps +> = ({ step, ...other }) => { + const { t } = useTranslation(); + const { getChainById } = useChains(); + + return ( + + {t('swapping.crossStepDetails', { + from: getChainById(step.action.fromChainId)?.name, + to: getChainById(step.action.toChainId)?.name, + tool: step.toolDetails.name, + })} + + ); +}; + +export const SwapStepDetailsLabel: React.FC< + { step: Step } & TypographyProps +> = ({ step, ...other }) => { + const { t } = useTranslation(); + return ( + + {t('swapping.swapStepDetails', { + value: step.toolDetails.name, + })} + + ); +}; diff --git a/packages/widget/src/components/StepActions/index.ts b/packages/widget/src/components/StepActions/index.ts new file mode 100644 index 000000000..14084bca5 --- /dev/null +++ b/packages/widget/src/components/StepActions/index.ts @@ -0,0 +1 @@ +export { StepActions } from './StepActions'; diff --git a/packages/widget/src/components/StepActions/types.ts b/packages/widget/src/components/StepActions/types.ts new file mode 100644 index 000000000..957381a0a --- /dev/null +++ b/packages/widget/src/components/StepActions/types.ts @@ -0,0 +1,7 @@ +import { Step } from '@lifinance/sdk'; +import { BoxProps } from '@mui/material'; + +export interface StepActionsProps extends BoxProps { + step: Step; + dense?: boolean; +} diff --git a/packages/widget/src/components/SwapRouteCard/SwapRouteCard.tsx b/packages/widget/src/components/SwapRouteCard/SwapRouteCard.tsx index ee3d1f9e7..4fddd846d 100644 --- a/packages/widget/src/components/SwapRouteCard/SwapRouteCard.tsx +++ b/packages/widget/src/components/SwapRouteCard/SwapRouteCard.tsx @@ -1,15 +1,15 @@ -import { Box, BoxProps, Typography } from '@mui/material'; +import { Avatar, Box, BoxProps, Typography } from '@mui/material'; import { useTranslation } from 'react-i18next'; +import { formatTokenAmount } from '../../utils/format'; +import { StepActions } from '../StepActions'; import { Card, Label } from './SwapRouteCard.style'; import { SwapRouteCardProps } from './types'; export const SwapRouteCard: React.FC = ({ - amount, - token, - time, - gas, + route, + index, active, - type, + dense, ...other }) => { const { t } = useTranslation(); @@ -17,14 +17,33 @@ export const SwapRouteCard: React.FC = ({ - - {amount} - - - {token} - + + + {route.toToken.symbol[0]} + + + + {formatTokenAmount(route.toAmount, route.toToken.decimals)} + + + {route.toToken.symbol} + + + + {!dense + ? route.steps.map((step) => ) + : null} = ({ > - {gas} + {t(`swap.currency`, { value: route.gasCostUSD })} {t(`swap.gas`)} @@ -41,7 +60,12 @@ export const SwapRouteCard: React.FC = ({ - ~{time} + ~ + {( + route.steps + .map((step) => step.estimate.executionDuration) + .reduce((cumulated, x) => cumulated + x) / 60 + ).toFixed(0)} {t(`swap.minutes`)} diff --git a/packages/widget/src/components/SwapRouteCard/types.ts b/packages/widget/src/components/SwapRouteCard/types.ts index 74872c663..1e88b68f4 100644 --- a/packages/widget/src/components/SwapRouteCard/types.ts +++ b/packages/widget/src/components/SwapRouteCard/types.ts @@ -1,9 +1,9 @@ +import { Route } from '@lifinance/sdk'; + export interface SwapRouteCardProps { - amount: string | number; - token: string; - time: string; - gas: string; - type: 'recommended' | 'fastest' | 'cheapest'; + route: Route; + index: number; + dense?: boolean; active?: boolean; blur?: boolean; } diff --git a/packages/widget/src/components/SwapRoutes/SwapRoutes.tsx b/packages/widget/src/components/SwapRoutes/SwapRoutes.tsx index c37fc40a4..c2518aa15 100644 --- a/packages/widget/src/components/SwapRoutes/SwapRoutes.tsx +++ b/packages/widget/src/components/SwapRoutes/SwapRoutes.tsx @@ -1,10 +1,9 @@ /* eslint-disable react/no-array-index-key */ -import { KeyboardArrowRight as KeyboardArrowRightIcon } from '@mui/icons-material'; -import { Box, BoxProps, IconButton, Skeleton } from '@mui/material'; +import { Box, BoxProps, Skeleton } from '@mui/material'; +import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { useSwapRoutes } from '../../hooks'; -import { formatTokenAmount } from '../../utils/format'; import { routes } from '../../utils/routes'; import { CardContainer, CardTitle } from '../Card'; import { SwapRouteCard } from '../SwapRouteCard'; @@ -15,9 +14,9 @@ export const SwapRoutes: React.FC = ({ mb }) => { const navigate = useNavigate(); const { routes: swapRoutes, isLoading } = useSwapRoutes(); - const handleCardClick = () => { + const handleCardClick = useCallback(() => { navigate(routes.swapRoutes); - }; + }, [navigate]); if (!swapRoutes?.length && !isLoading) { return null; @@ -44,25 +43,16 @@ export const SwapRoutes: React.FC = ({ mb }) => { step.estimate.executionDuration) - .reduce((cumulated, x) => cumulated + x) / 60 - ).toFixed(0)} - type={index === 0 ? 'recommended' : 'fastest'} + minWidth="80%" + route={route} + index={index} active={index === 0} blur={index !== 0} + dense /> ))} - + {/* = ({ mb }) => { > - + */} ); diff --git a/packages/widget/src/hooks/useSwapRoutes.ts b/packages/widget/src/hooks/useSwapRoutes.ts index d8dce52f1..407ddbc1c 100644 --- a/packages/widget/src/hooks/useSwapRoutes.ts +++ b/packages/widget/src/hooks/useSwapRoutes.ts @@ -91,10 +91,10 @@ export const useSwapRoutes = () => { { enabled: isEnabled, refetchIntervalInBackground: true, - refetchInterval: 30_000, - staleTime: 30_000, + refetchInterval: 30000000, + staleTime: 30000000, // TODO: probably should be removed - cacheTime: 30_000, + cacheTime: 30000000, }, ); diff --git a/packages/widget/src/i18n/en/translation.json b/packages/widget/src/i18n/en/translation.json index f735d92f1..9eee72854 100644 --- a/packages/widget/src/i18n/en/translation.json +++ b/packages/widget/src/i18n/en/translation.json @@ -41,7 +41,8 @@ "estimatedTime": "~{{value}} min.", "done": "Done", "networkIsBusy": "Network is busy...", - "crossChainDetails": "{{from}} to {{to}} via {{via}}", + "crossStepDetails": "Bridge {{from}} to {{to}} via {{tool}}", + "swapStepDetails": "Swap on {{value}}", "transactionDetails": "Transaction Details", "process": { "tokenAllowance": { diff --git a/packages/widget/src/pages/SwapRoutesPage/SwapRoutesPage.tsx b/packages/widget/src/pages/SwapRoutesPage/SwapRoutesPage.tsx index d7bac1095..4a4fab51e 100644 --- a/packages/widget/src/pages/SwapRoutesPage/SwapRoutesPage.tsx +++ b/packages/widget/src/pages/SwapRoutesPage/SwapRoutesPage.tsx @@ -3,7 +3,6 @@ import { BoxProps, Skeleton } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { SwapRouteCard } from '../../components/SwapRouteCard'; import { useSwapRoutes } from '../../hooks'; -import { formatTokenAmount } from '../../utils/format'; import { Stack } from './SwapRoutesPage.style'; export const SwapRoutesPage: React.FC = ({ mb }) => { @@ -30,15 +29,8 @@ export const SwapRoutesPage: React.FC = ({ mb }) => { : routes?.map((route, index) => ( step.estimate.executionDuration) - .reduce((cumulated, x) => cumulated + x) / 60 - ).toFixed(0)} - type="recommended" + route={route} + index={index} active={index === 0} /> ))} diff --git a/packages/widget/src/pages/SwappingPage/StepItem.tsx b/packages/widget/src/pages/SwappingPage/StepItem.tsx index 489063fde..451b677de 100644 --- a/packages/widget/src/pages/SwappingPage/StepItem.tsx +++ b/packages/widget/src/pages/SwappingPage/StepItem.tsx @@ -3,10 +3,10 @@ import { Step, TokenAmount } from '@lifinance/sdk'; import { Avatar, Box, Typography } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { CardContainer, CardTitle } from '../../components/Card'; +import { StepActions } from '../../components/StepActions'; import { formatTokenAmount } from '../../utils/format'; import { ExecutionItem } from './ExecutionItem'; import { StepTimer } from './StepTimer'; -import { ToolItem } from './ToolItem'; export const StepItem: React.FC<{ step: Step; @@ -56,7 +56,7 @@ export const StepItem: React.FC<{ ) : null} - + {step.execution?.process.map((process, index) => ( ))} diff --git a/packages/widget/src/pages/SwappingPage/ToolItem.tsx b/packages/widget/src/pages/SwappingPage/ToolItem.tsx deleted file mode 100644 index 986aa97e0..000000000 --- a/packages/widget/src/pages/SwappingPage/ToolItem.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Step } from '@lifinance/sdk'; -import { ArrowForward as ArrowForwardIcon } from '@mui/icons-material'; -import { Avatar, Box, Typography } from '@mui/material'; -import { useTranslation } from 'react-i18next'; -import { useChains } from '../../hooks'; -import LiFiLogo from '../../icons/LiFiLogo.svg'; -import { formatTokenAmount } from '../../utils/format'; - -export const ToolItem: React.FC<{ - step: any; -}> = ({ step }) => { - return ( - - - - {step.toolDetails.name[0]} - - - {step.type === 'lifi' - ? 'LI.FI Smart Contract' - : step.toolDetails.name} - - - - {step.type === 'cross' || step.type === 'lifi' ? ( - - ) : null} - - {formatTokenAmount( - step.estimate.fromAmount, - step.action.fromToken.decimals, - )}{' '} - {step.action.fromToken.symbol} - - {formatTokenAmount( - step.estimate.toAmount, - step.action.toToken.decimals, - )}{' '} - {step.action.toToken.symbol} - - - - ); -}; - -export const CrossChainDetails: React.FC<{ - step: Step; -}> = ({ step }) => { - const { t } = useTranslation(); - const { getChainById } = useChains(); - - return ( - - {t('swapping.crossChainDetails', { - from: getChainById(step.action.fromChainId)?.name, - to: getChainById(step.action.toChainId)?.name, - via: step.tool, - })} - - ); -};