import type { LiFiStep, StepExtended } from '@lifi/sdk'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import type { StepIconProps } from '@mui/material'; import { Badge, Box, Collapse, Step as MuiStep, Stepper, Typography, } from '@mui/material'; import type { MouseEventHandler } from 'react'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { formatUnits } from 'viem'; import { useAvailableChains } from '../../hooks'; import { LiFiToolLogo } from '../../icons'; import { useWidgetConfig } from '../../providers'; import type { WidgetSubvariant } from '../../types'; import { formatTokenAmount } from '../../utils'; import { CardIconButton } from '../Card'; import { SmallAvatar } from '../SmallAvatar'; import { StepAvatar, StepConnector, StepContent, StepLabel, StepLabelTypography, } from './StepActions.style'; import { StepFeeBreakdown } from './StepFeeBreakdown'; import { StepFees } from './StepFees'; import type { StepActionsProps, StepDetailsLabelProps } from './types'; export const StepActions: React.FC = ({ step, dense, ...other }) => { const { t } = useTranslation(); const { subvariant } = useWidgetConfig(); const [cardExpanded, setCardExpanded] = useState(false); const handleExpand: MouseEventHandler = (e) => { e.stopPropagation(); setCardExpanded((expanded) => !expanded); }; // FIXME: step transaction request overrides step tool details, but not included step tool details const toolDetails = subvariant === 'nft' ? step.includedSteps.find( (step) => step.tool === 'custom' && step.toolDetails.key !== 'custom', )?.toolDetails || step.toolDetails : step.toolDetails; return ( } > {toolDetails.name[0]} {t(`main.stepDetails`, { tool: toolDetails.name, })} {dense ? ( {cardExpanded ? : } ) : null} {dense ? ( ) : ( )} ); }; export const IncludedSteps: React.FC<{ step: LiFiStep; subvariant?: WidgetSubvariant; }> = ({ step, subvariant }) => { // eslint-disable-next-line react/no-unstable-nested-components const StepIconComponent = ({ icon }: StepIconProps) => { const tool = step.includedSteps?.[Number(icon) - 1]; return tool ? ( {tool.toolDetails.name[0]} ) : null; }; return ( } activeStep={-1} > {step.includedSteps.map((step, i, includedSteps) => ( {step.type === 'custom' && subvariant === 'nft' ? ( ) : step.type === 'cross' ? ( ) : step.type === 'protocol' ? ( ) : ( )} ))} ); }; export const StepDetailsContent: React.FC<{ step: StepExtended; subvariant?: WidgetSubvariant; }> = ({ step, subvariant }) => { const { t } = useTranslation(); const sameTokenProtocolStep = step.action.fromToken.chainId === step.action.toToken.chainId && step.action.fromToken.address === step.action.toToken.address; let fromAmount: string | undefined; if (sameTokenProtocolStep) { const estimatedFromAmount = BigInt(step.estimate.fromAmount) - BigInt(step.estimate.toAmount); fromAmount = estimatedFromAmount > 0n ? formatUnits(estimatedFromAmount, step.action.fromToken.decimals) : formatUnits( BigInt(step.estimate.fromAmount), step.action.fromToken.decimals, ); } else { fromAmount = formatTokenAmount( BigInt(step.estimate.fromAmount), step.action.fromToken.decimals, ); } const showToAmount = step.type !== 'custom' && step.tool !== 'custom' && !sameTokenProtocolStep; return ( {!showToAmount ? ( <> {formatUnits( BigInt(step.estimate.fromAmount), step.action.fromToken.decimals, )}{' '} {step.action.fromToken.symbol} {' - '} ) : null} {t('format.number', { value: fromAmount, })}{' '} {step.action.fromToken.symbol} {showToAmount ? ( <> {t('format.number', { value: formatTokenAmount( BigInt(step.execution?.toAmount ?? step.estimate.toAmount), step.execution?.toToken?.decimals ?? step.action.toToken.decimals, ), })}{' '} {step.execution?.toToken?.symbol ?? step.action.toToken.symbol} ) : ( ` (${t('format.currency', { value: parseFloat(fromAmount) * parseFloat(step.action.fromToken.priceUSD), })})` )} ); }; export const CustomStepDetailsLabel: React.FC = ({ step, subvariant, }) => { const { t } = useTranslation(); if (!subvariant) { return null; } // FIXME: step transaction request overrides step tool details, but not included step tool details const toolDetails = subvariant === 'nft' && (step as unknown as LiFiStep).includedSteps?.length > 0 ? (step as unknown as LiFiStep).includedSteps.find( (step) => step.tool === 'custom' && step.toolDetails.key !== 'custom', )?.toolDetails || step.toolDetails : step.toolDetails; return ( {t(`main.${subvariant}StepDetails`, { tool: toolDetails.name, })} ); }; export const CrossStepDetailsLabel: React.FC< Omit > = ({ step }) => { const { t } = useTranslation(); const { getChainById } = useAvailableChains(); return ( {t('main.crossStepDetails', { from: getChainById(step.action.fromChainId)?.name, to: getChainById(step.action.toChainId)?.name, tool: step.toolDetails.name, })} ); }; export const SwapStepDetailsLabel: React.FC< Omit > = ({ step }) => { const { t } = useTranslation(); const { getChainById } = useAvailableChains(); return ( {t('main.swapStepDetails', { chain: getChainById(step.action.fromChainId)?.name, tool: step.toolDetails.name, })} ); }; export const ProtocolStepDetailsLabel: React.FC< Omit > = ({ step }) => { const { t } = useTranslation(); return ( {step.toolDetails.key === 'lifuelProtocol' ? t('main.refuelStepDetails', { tool: step.toolDetails.name, }) : step.toolDetails.name} ); };