import classNames from 'classnames'
import { ReactNode } from 'react'
import { Slide, ToastContainer, toast as toastify } from 'react-toastify'
import { mutate } from 'swr'
import { CheckMark } from 'components/common/CheckMark'
import { CircularProgress } from 'components/common/CircularProgress'
import { ChevronDown, Cross, CrossCircled, ExternalLink } from 'components/common/Icons'
import Text from 'components/common/Text'
import { TextLink } from 'components/common/TextLink'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useChainConfig from 'hooks/useChainConfig'
import useTransactionStore from 'hooks/useTransactionStore'
import useStore from 'store'
import { formatAmountWithSymbol } from 'utils/formatters'
import { BN } from 'utils/helpers'
const toastBodyClasses = classNames(
'flex flex-wrap w-full group/transaction',
'rounded-sm p-4 shadow-overlay backdrop-blur-lg',
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-sm before:p-[1px] before:border-glas',
)
function isPromise(object?: any): object is ToastPending {
if (!object) return false
return 'promise' in object
}
export function generateToastContent(content: ToastSuccess['content'], assets: Asset[]): ReactNode {
return content.map((item, index) => (
{item.text && (
<>
{item.text}
{item.coins.length > 0 && (
{item.coins.map((coin, index) => {
let prefix = ''
if (item.text === 'Swapped') prefix = index === 0 ? 'from ' : 'to '
return BN(coin.amount).isZero() ? null : (
-
{`${prefix}${formatAmountWithSymbol(coin, assets)}`}
)
})}
)}
>
)}
))
}
export default function Toaster() {
const [reduceMotion] = useLocalStorage(
LocalStorageKeys.REDUCE_MOTION,
DEFAULT_SETTINGS.reduceMotion,
)
const chainConfig = useChainConfig()
const toast = useStore((s) => s.toast)
const { addTransaction } = useTransactionStore()
const handlePending = (toast: ToastPending) => {
const Content = () => (
Approve the transaction
and wait for its confirmation.
)
toastify(Content, {
toastId: toast.id,
className: classNames(toastBodyClasses, 'toast-pending'),
icon: false,
draggable: false,
closeOnClick: false,
hideProgressBar: true,
autoClose: false,
})
}
const handleResponse = (toast: ToastResponse, details?: boolean) => {
const isError = toast?.isError
if (!isError && toast.accountId) addTransaction(toast)
const generalMessage = isError ? 'Transaction failed!' : 'Transaction completed successfully!'
const showDetailElement = !!(!details && toast.hash)
const address = useStore.getState().address
let target: string
if (!isError) {
target = toast.accountId === address ? 'Red Bank' : `Credit Account ${toast.accountId}`
}
const Msg = () => (
{isError ? (
) : (
)}
{isError ? (toast.title ? toast.title : 'Error') : 'Success'}
{showDetailElement ? generalMessage : toast.message}
{showDetailElement && (
Transaction Details
)}
{!isError && toast.accountId && (
{target}
)}
{showDetailElement && toast.message && (
{toast.message}
)}
{!isError &&
toast.content?.length > 0 &&
generateToastContent(toast.content, chainConfig.assets)}
{toast.hash && (
{`View on ${chainConfig.explorerName}`}
)}
)
const toastElement = document.getElementById(String(toast.id))
if (toastElement) {
toastify.update(toast.id, {
render: Msg,
className: toastBodyClasses,
type: isError ? 'error' : 'success',
icon: false,
draggable: false,
closeOnClick: true,
autoClose: 5000,
progressClassName: classNames('h-[1px] bg-none', isError ? 'bg-error' : 'bg-success'),
hideProgressBar: false,
})
} else {
toastify(Msg, {
toastId: toast.id,
className: toastBodyClasses,
type: isError ? 'error' : 'success',
icon: false,
draggable: false,
closeOnClick: true,
autoClose: 5000,
progressClassName: classNames('h-[1px] bg-none', isError ? 'bg-error' : 'bg-success'),
})
}
useStore.setState({ toast: null })
mutate(() => true)
}
if (toast) {
if (isPromise(toast)) {
handlePending(toast)
} else {
handleResponse(toast)
}
}
return (
)
}