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 && ( )} )}
)) } 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 = () => (
Pending Transaction
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 ( ) }