Skip to content

Commit

Permalink
feat: add estimated and paid gas fees to swap details page
Browse files Browse the repository at this point in the history
  • Loading branch information
chybisov committed Nov 23, 2022
1 parent e1be550 commit be4f613
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 98 deletions.
38 changes: 21 additions & 17 deletions packages/widget/src/components/Step/CircularProgress.style.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Process, Status, Substatus } from '@lifi/sdk';
import type { Status, Substatus } from '@lifi/sdk';
import {
Box,
CircularProgress as MuiCircularProgress,
Expand Down Expand Up @@ -42,22 +42,26 @@ const getStatusColor = (
}
};

export const CircularProgressBox = styled(Box, {
shouldForwardProp: (prop) => prop !== 'process',
})<{ process: Process }>(({ theme, process }) => ({
backgroundColor: !['STARTED', 'PENDING'].includes(process.status)
? getStatusColor(theme, process.status, process.substatus)
: theme.palette.background.paper,
borderStyle: 'solid',
borderColor: getStatusColor(theme, process.status, process.substatus),
borderWidth: ['STARTED', 'PENDING'].includes(process.status) ? 2 : 0,
display: 'grid',
position: 'relative',
placeItems: 'center',
width: 32,
height: 32,
borderRadius: '50%',
}));
export const CircularIcon = styled(Box, {
shouldForwardProp: (prop: string) => !['status', 'substatus'].includes(prop),
})<{ status: Status; substatus?: Substatus }>(
({ theme, status, substatus }) => ({
backgroundColor: ['ACTION_REQUIRED', 'DONE', 'FAILED'].includes(status)
? getStatusColor(theme, status, substatus)
: theme.palette.background.paper,
borderStyle: 'solid',
borderColor: getStatusColor(theme, status, substatus),
borderWidth: !['ACTION_REQUIRED', 'DONE', 'FAILED'].includes(status)
? 2
: 0,
display: 'grid',
position: 'relative',
placeItems: 'center',
width: 32,
height: 32,
borderRadius: '50%',
}),
);

export const CircularProgressPending = styled(MuiCircularProgress)(
({ theme }) => ({
Expand Down
8 changes: 4 additions & 4 deletions packages/widget/src/components/Step/CircularProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import {
} from '@mui/icons-material';
import { darken } from '@mui/material/styles';
import {
CircularProgressBox,
CircularIcon,
CircularProgressPending
} from './CircularProgress.style';

export function CircularProgress({ process }: { process: Process }) {
return (
<CircularProgressBox process={process}>
<CircularIcon status={process.status} substatus={process.substatus}>
{process.status === 'STARTED' || process.status === 'PENDING' ? (
<CircularProgressPending size={32} thickness={3} />
) : null}
Expand All @@ -31,7 +31,7 @@ export function CircularProgress({ process }: { process: Process }) {
sx={(theme) => ({
position: 'absolute',
fontSize: '1rem',
color: darken(theme.palette.warning.main, 0.32)
color: darken(theme.palette.warning.main, 0.32),
})}
/>
) : process.status === 'DONE' ? (
Expand All @@ -52,6 +52,6 @@ export function CircularProgress({ process }: { process: Process }) {
}}
/>
) : null}
</CircularProgressBox>
</CircularIcon>
);
}
45 changes: 45 additions & 0 deletions packages/widget/src/components/Step/GasStepProcess.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Step } from '@lifi/sdk';
import { EvStationOutlined as EvStationIcon } from '@mui/icons-material';
import { Box, Typography } from '@mui/material';
import { useTranslation } from 'react-i18next';
import { CircularIcon } from './CircularProgress.style';

export const GasStepProcess: React.FC<{
step: Step;
}> = ({ step }) => {
const { t } = useTranslation();
const isDone = step.execution?.status === 'DONE';
return (
<Box px={2} py={1}>
<Box
sx={{
display: 'flex',
alignItems: 'center',
}}
>
<CircularIcon status={isDone ? 'DONE' : 'NOT_STARTED'}>
<EvStationIcon
color={isDone ? 'success' : 'inherit'}
sx={{
position: 'absolute',
fontSize: '1rem',
}}
/>
</CircularIcon>
<Typography ml={2} fontSize={14} fontWeight={400}>
{t('format.currency', {
value:
(step.execution?.gasAmountUSD ||
step.estimate.gasCosts?.reduce(
(amount, gasCost) =>
amount + parseFloat(gasCost.amountUSD || '0'),
0,
)) ??
0,
})}{' '}
{isDone ? t('swap.gasFeePaid') : t('swap.gasFeeEstimated')}
</Typography>
</Box>
</Box>
);
};
2 changes: 2 additions & 0 deletions packages/widget/src/components/Step/Step.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
import { Card, CardTitle } from '../../components/Card';
import { StepActions } from '../../components/StepActions';
import { Token } from '../../components/Token';
import { GasStepProcess } from './GasStepProcess';
import { StepProcess } from './StepProcess';
import { StepTimer } from './StepTimer';

Expand Down Expand Up @@ -57,6 +58,7 @@ export const Step: React.FC<{
{step.execution?.process.map((process, index) => (
<StepProcess key={index} step={step} process={process} />
))}
<GasStepProcess step={step} />
{toToken ? <Token token={toToken} px={2} py={1} /> : null}
</Box>
</Card>
Expand Down
28 changes: 28 additions & 0 deletions packages/widget/src/components/Step/StepList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Route } from '@lifi/sdk';
import { Fragment } from 'react';
import { StepDivider } from '../../components/StepDivider';
import { Step } from './Step';

export const getStepList = (route?: Route) =>
route?.steps.map((step, index, steps) => {
const lastIndex = steps.length - 1;
const fromToken =
index === 0
? { ...step.action.fromToken, amount: step.action.fromAmount }
: undefined;
const toToken =
index === lastIndex
? {
...(step.execution?.toToken ?? step.action?.toToken),
amount: step.execution?.toAmount ?? step.estimate.toAmount,
}
: undefined;
return (
<Fragment key={step.id}>
<Step step={step} fromToken={fromToken} toToken={toToken} />
{steps.length > 1 && index !== steps.length - 1 ? (
<StepDivider />
) : null}
</Fragment>
);
});
2 changes: 2 additions & 0 deletions packages/widget/src/components/Step/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './Step';
export * from './StepList';

58 changes: 30 additions & 28 deletions packages/widget/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@
"unknown": "Please try again or contact support."
},
"title": {
"balanceIsTooLow": "The balance is too low.",
"chainSwitch": "Chain switch required.",
"failed": "Swap failed.",
"gasLimitIsTooLow": "The gas limit is too low.",
"slippageNotMet": "Slippage conditions not met.",
"transactionCanceled": "Transaction canceled.",
"transactionFailed": "Transaction failed.",
"transactionRejected": "Signature required.",
"transactionUnderpriced": "Transaction is underpriced.",
"transactionUnprepared": "Unable to prepare transaction.",
"unknown": "Something went wrong.",
"balanceIsTooLow": "The balance is too low",
"chainSwitch": "Chain switch required",
"failed": "Swap failed",
"gasLimitIsTooLow": "The gas limit is too low",
"slippageNotMet": "Slippage conditions not met",
"transactionCanceled": "Transaction canceled",
"transactionFailed": "Transaction failed",
"transactionRejected": "Signature required",
"transactionUnderpriced": "Transaction is underpriced",
"transactionUnprepared": "Unable to prepare transaction",
"unknown": "Something went wrong",
"walletAddressInvalid": "Wallet address is invalid.",
"walletEnsAddressInvalid": "Wallet address is invalid or network doesn't support ENS."
}
Expand All @@ -99,6 +99,8 @@
"from": "From",
"fromAmount": "You pay",
"gasCost": "Gas cost",
"gasFeeEstimated": "estimated gas fee",
"gasFeePaid": "gas fee paid",
"inProgress": "in progress",
"info": {
"message": {
Expand All @@ -117,31 +119,31 @@
"otherTokens": "Other tokens",
"process": {
"crossChain": {
"actionRequired": "Please sign the transaction.",
"done": "Bridge transaction confirmed.",
"pending": "Waiting for bridge transaction.",
"started": "Preparing bridge transaction."
"actionRequired": "Please sign the transaction",
"done": "Bridge transaction confirmed",
"pending": "Waiting for bridge transaction",
"started": "Preparing bridge transaction"
},
"receivingChain": {
"done": "Bridge completed.",
"partial": "Bridge partially completed.",
"pending": "Waiting for destination chain.",
"refunded": "Bridge transaction refunded."
"done": "Bridge completed",
"partial": "Bridge partially completed",
"pending": "Waiting for destination chain",
"refunded": "Bridge transaction refunded"
},
"swap": {
"actionRequired": "Please sign the transaction.",
"done": "Swap completed.",
"pending": "Waiting for swap transaction.",
"started": "Preparing swap transaction."
"actionRequired": "Please sign the transaction",
"done": "Swap completed",
"pending": "Waiting for swap transaction",
"started": "Preparing swap transaction"
},
"switchChain": {
"actionRequired": "Chain switch required.",
"done": "Chain switched successfully."
"actionRequired": "Chain switch required",
"done": "Chain switched successfully"
},
"tokenAllowance": {
"done": "Token allowance approved.",
"pending": "Waiting for token allowance.",
"started": "Setting token allowance."
"done": "Token allowance approved",
"pending": "Waiting for token allowance",
"started": "Setting token allowance"
}
},
"quotedAmount": "Quoted amount",
Expand Down
33 changes: 8 additions & 25 deletions packages/widget/src/pages/SwapDetailsPage/SwapDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ import {
IconButton,
Typography
} from '@mui/material';
import { Fragment, useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import shallow from 'zustand/shallow';
import { Card, CardTitle } from '../../components/Card';
import { Dialog } from '../../components/Dialog';
import { useHeaderActionStore } from '../../components/Header';
import { Step } from '../../components/Step';
import { StepDivider } from '../../components/StepDivider';
import { getStepList } from '../../components/Step';
import { useNavigateBack } from '../../hooks';
import { useRouteExecutionStore } from '../../stores';
import { Container } from './SwapDetailsPage.style';
Expand All @@ -46,13 +45,17 @@ export const SwapDetailsPage: React.FC = () => {
}
};

const supportId =
let supportId =
routeExecution?.route.steps[0].execution?.process.find(
(process) => process.txHash,
)?.txHash ??
routeExecution?.route.id ??
'';

if (process.env.NODE_ENV === 'development') {
supportId += `_${routeExecution?.route.id}`;
}

const copySupportId = async () => {
await navigator.clipboard.writeText(supportId);
};
Expand Down Expand Up @@ -90,27 +93,7 @@ export const SwapDetailsPage: React.FC = () => {
}).format(startedAt)}
</Typography>
</Box>
{routeExecution?.route.steps.map((step, index, steps) => {
const fromToken =
index === 0
? { ...step.action.fromToken, amount: step.action.fromAmount }
: undefined;
const toToken =
index === steps.length - 1
? {
...(step.execution?.toToken ?? step.action?.toToken),
amount: step.execution?.toAmount ?? step.estimate.toAmount,
}
: undefined;
return (
<Fragment key={step.id}>
<Step step={step} fromToken={fromToken} toToken={toToken} />
{steps.length > 1 && index !== steps.length - 1 ? (
<StepDivider />
) : null}
</Fragment>
);
})}
{getStepList(routeExecution?.route)}
<Card mt={2}>
<Box
sx={{
Expand Down
27 changes: 3 additions & 24 deletions packages/widget/src/pages/SwapPage/SwapPage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Delete as DeleteIcon } from '@mui/icons-material';
import { Box, Button, Tooltip } from '@mui/material';
import { Fragment, useCallback, useRef } from 'react';
import { useCallback, useRef } from 'react';
import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import type { BottomSheetBase } from '../../components/BottomSheet';
import { GasSufficiencyMessage } from '../../components/GasSufficiencyMessage';
import { Step } from '../../components/Step';
import { StepDivider } from '../../components/StepDivider';
import { getStepList } from '../../components/Step';
import { SwapButton } from '../../components/SwapButton';
import { useNavigateBack, useRouteExecution } from '../../hooks';
import { SwapFormKey } from '../../providers';
Expand Down Expand Up @@ -76,27 +75,7 @@ export const SwapPage: React.FC = () => {

return (
<Container>
{route?.steps.map((step, index, steps) => {
const fromToken =
index === 0
? { ...step.action.fromToken, amount: step.action.fromAmount }
: undefined;
const toToken =
index === steps.length - 1
? {
...(step.execution?.toToken ?? step.action?.toToken),
amount: step.execution?.toAmount ?? step.estimate.toAmount,
}
: undefined;
return (
<Fragment key={step.id}>
<Step step={step} fromToken={fromToken} toToken={toToken} />
{steps.length > 1 && index !== steps.length - 1 ? (
<StepDivider />
) : null}
</Fragment>
);
})}
{getStepList(route)}
{status === RouteExecutionStatus.Idle ||
status === RouteExecutionStatus.Failed ? (
<>
Expand Down

0 comments on commit be4f613

Please sign in to comment.