import Done from '@mui/icons-material/Done' import ErrorRounded from '@mui/icons-material/ErrorRounded' import InfoRounded from '@mui/icons-material/InfoRounded' import WarningRounded from '@mui/icons-material/WarningRounded' import { Box, Button, Typography } from '@mui/material' import { useCallback, useEffect, useRef } from 'react' import { useTranslation } from 'react-i18next' import { BottomSheet } from '../../components/BottomSheet/BottomSheet.js' import type { BottomSheetBase } from '../../components/BottomSheet/types.js' import { Card } from '../../components/Card/Card.js' import { CardTitle } from '../../components/Card/CardTitle.js' import { Token } from '../../components/Token/Token.js' import { useAvailableChains } from '../../hooks/useAvailableChains.js' import { useNavigateBack } from '../../hooks/useNavigateBack.js' import { getProcessMessage } from '../../hooks/useProcessMessage.js' import { useSetContentHeight } from '../../hooks/useSetContentHeight.js' import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js' import { useFieldActions } from '../../stores/form/useFieldActions.js' import { type RouteExecution, RouteExecutionStatus, } from '../../stores/routes/types.js' import { getSourceTxHash } from '../../stores/routes/utils.js' import { hasEnumFlag } from '../../utils/enum.js' import { formatTokenAmount } from '../../utils/format.js' import { navigationRoutes } from '../../utils/navigationRoutes.js' import { CenterContainer, IconCircle } from './StatusBottomSheet.style.js' interface StatusBottomSheetContentProps extends RouteExecution { onClose(): void } export const StatusBottomSheet: React.FC = ({ status, route, }) => { const ref = useRef(null) const onClose = useCallback(() => { ref.current?.close() }, []) useEffect(() => { const hasSuccessFlag = hasEnumFlag(status, RouteExecutionStatus.Done) const hasFailedFlag = hasEnumFlag(status, RouteExecutionStatus.Failed) if ((hasSuccessFlag || hasFailedFlag) && !ref.current?.isOpen()) { ref.current?.open() } }, [status]) return ( ) } const StatusBottomSheetContent: React.FC = ({ status, route, onClose, }) => { const { t } = useTranslation() const { navigateBack, navigate } = useNavigateBack() const { setFieldValue } = useFieldActions() const { subvariant, subvariantOptions, contractSecondaryComponent, contractCompactComponent, feeConfig, } = useWidgetConfig() const { getChainById } = useAvailableChains() const ref = useRef(null) useSetContentHeight(ref) const toToken = { ...(route.steps.at(-1)?.execution?.toToken ?? route.toToken), amount: BigInt( route.steps.at(-1)?.execution?.toAmount ?? route.steps.at(-1)?.estimate.toAmount ?? route.toAmount ), } const cleanFields = () => { setFieldValue('fromAmount', '') setFieldValue('toAmount', '') } const handleDone = () => { cleanFields() navigateBack() } const handlePartialDone = () => { if ( toToken.chainId !== route.toToken.chainId && toToken.address !== route.toToken.address ) { setFieldValue( 'fromAmount', formatTokenAmount(toToken.amount, toToken.decimals), { isTouched: true } ) setFieldValue('fromChain', toToken.chainId, { isTouched: true }) setFieldValue('fromToken', toToken.address, { isTouched: true }) setFieldValue('toChain', route.toToken.chainId, { isTouched: true, }) setFieldValue('toToken', route.toToken.address, { isTouched: true, }) } else { cleanFields() } navigateBack() } const handleClose = () => { cleanFields() onClose() } const handleSeeDetails = () => { handleClose() const transactionHash = getSourceTxHash(route) navigate(navigationRoutes.transactionDetails, { state: { routeId: route.id, transactionHash, }, replace: true, }) } const transactionType = route.fromChainId === route.toChainId ? 'swap' : 'bridge' let title: string | undefined let primaryMessage: string | undefined let failedMessage: string | undefined let handlePrimaryButton = handleDone switch (status) { case RouteExecutionStatus.Done: { title = subvariant === 'custom' ? t( `success.title.${subvariantOptions?.custom ?? 'checkout'}Successful` ) : t(`success.title.${transactionType}Successful`) handlePrimaryButton = handleDone break } case RouteExecutionStatus.Done | RouteExecutionStatus.Partial: { title = t(`success.title.${transactionType}PartiallySuccessful`) primaryMessage = t('success.message.exchangePartiallySuccessful', { tool: route.steps.at(-1)?.toolDetails.name, tokenSymbol: route.steps.at(-1)?.action.toToken.symbol, }) handlePrimaryButton = handlePartialDone break } case RouteExecutionStatus.Done | RouteExecutionStatus.Refunded: { title = t('success.title.refundIssued') primaryMessage = t('success.message.exchangePartiallySuccessful', { tool: route.steps.at(-1)?.toolDetails.name, tokenSymbol: route.steps.at(-1)?.action.toToken.symbol, }) break } case RouteExecutionStatus.Failed: { const step = route.steps.find( (step) => step.execution?.status === 'FAILED' ) const process = step?.execution?.process.find( (process) => process.status === 'FAILED' ) if (!step || !process) { break } const processMessage = getProcessMessage(t, getChainById, step, process) title = processMessage.title failedMessage = processMessage.message handlePrimaryButton = handleClose break } default: break } const showContractComponent = subvariant === 'custom' && hasEnumFlag(status, RouteExecutionStatus.Done) && (contractCompactComponent || contractSecondaryComponent) const VcComponent = status === RouteExecutionStatus.Done ? feeConfig?._vcComponent : undefined return ( {!showContractComponent ? ( {status === RouteExecutionStatus.Idle ? ( ) : null} {status === RouteExecutionStatus.Done ? ( ) : null} {hasEnumFlag(status, RouteExecutionStatus.Partial) || hasEnumFlag(status, RouteExecutionStatus.Refunded) ? ( ) : null} {hasEnumFlag(status, RouteExecutionStatus.Failed) ? ( ) : null} ) : null} {title} {showContractComponent ? ( contractCompactComponent || contractSecondaryComponent ) : hasEnumFlag(status, RouteExecutionStatus.Failed) && failedMessage ? ( {failedMessage} ) : hasEnumFlag(status, RouteExecutionStatus.Done) ? ( {hasEnumFlag(status, RouteExecutionStatus.Refunded) ? t('header.refunded') : t('header.received')} {primaryMessage && ( {primaryMessage} )} {VcComponent ? : null} ) : null} {hasEnumFlag(status, RouteExecutionStatus.Done) ? ( ) : null} ) }