import { EXPLORERS } from '@components/settings/PreferredExplorerSettings' import { IconButton, LinkButton } from '@components/shared/Button' import SheenLoader from '@components/shared/SheenLoader' import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import Tooltip from '@components/shared/Tooltip' import { Transition } from '@headlessui/react' import { ChevronDownIcon, ChevronRightIcon, NoSymbolIcon, } from '@heroicons/react/20/solid' import mangoStore, { LiquidationFeedItem } from '@store/mangoStore' import dayjs from 'dayjs' import useLocalStorageState from 'hooks/useLocalStorageState' import useMangoAccount from 'hooks/useMangoAccount' import { useViewport } from 'hooks/useViewport' import { useTranslation } from 'next-i18next' import Image from 'next/legacy/image' import { Fragment, useCallback, useState } from 'react' import { PREFERRED_EXPLORER_KEY } from 'utils/constants' import { formatDecimal, formatFixedDecimals } from 'utils/numbers' import { breakpoints } from 'utils/theme' const ActivityFeedTable = ({ activityFeed, handleShowActivityDetails, params, }: { activityFeed: any handleShowActivityDetails: (x: LiquidationFeedItem) => void params: string }) => { const { t } = useTranslation(['common', 'activity']) const { mangoAccount } = useMangoAccount() const actions = mangoStore.getState().actions const loadActivityFeed = mangoStore((s) => s.activityFeed.loading) const [offset, setOffset] = useState(0) const [preferredExplorer] = useLocalStorageState( PREFERRED_EXPLORER_KEY, EXPLORERS[0] ) const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const handleShowMore = useCallback(() => { const mangoAccount = mangoStore.getState().mangoAccount.current const set = mangoStore.getState().set set((s) => { s.activityFeed.loading = true }) if (!mangoAccount) return setOffset(offset + 25) actions.fetchActivityFeed( mangoAccount.publicKey.toString(), offset + 25, params ) }, [actions, offset, params]) const getCreditAndDebit = (activity: any) => { const { activity_type } = activity let credit = { value: '0', symbol: '' } let debit = { value: '0', symbol: '' } if (activity_type === 'liquidate_token_with_token') { const { side, liab_amount, liab_symbol, asset_amount, asset_symbol } = activity.activity_details if (side === 'liqee') { credit = { value: formatDecimal(liab_amount), symbol: liab_symbol } debit = { value: formatDecimal(asset_amount), symbol: asset_symbol, } } else { credit = { value: formatDecimal(asset_amount), symbol: asset_symbol } debit = { value: formatDecimal(liab_amount), symbol: liab_symbol } } } if (activity_type === 'deposit') { const { symbol, quantity } = activity.activity_details credit = { value: formatDecimal(quantity), symbol } debit = { value: '0', symbol: '' } } if (activity_type === 'withdraw') { const { symbol, quantity } = activity.activity_details credit = { value: '0', symbol: '' } debit = { value: formatDecimal(quantity * -1), symbol } } if (activity_type === 'swap') { const { swap_in_amount, swap_in_symbol, swap_out_amount, swap_out_symbol, } = activity.activity_details credit = { value: formatDecimal(swap_out_amount), symbol: swap_out_symbol, } debit = { value: formatDecimal(swap_in_amount * -1), symbol: swap_in_symbol, } } if (activity_type === 'perp_trade') { const { perp_market, price, quantity } = activity.activity_details credit = { value: quantity, symbol: perp_market } debit = { value: formatDecimal(quantity * price * -1), symbol: 'USDC' } } if (activity_type === 'openbook_trade') { const { side, price, size, base_symbol, quote_symbol } = activity.activity_details credit = side === 'buy' ? { value: formatDecimal(size), symbol: base_symbol } : { value: formatDecimal(size * price), symbol: quote_symbol } debit = side === 'buy' ? { value: formatDecimal(size * price * -1), symbol: quote_symbol } : { value: formatDecimal(size * -1), symbol: base_symbol } } return { credit, debit } } const getValue = (activity: any) => { const { activity_type } = activity let value = 0 if (activity_type === 'liquidate_token_with_token') { const { side, liab_amount, liab_price, asset_amount, asset_price } = activity.activity_details if (side === 'liqee') { value = asset_amount * asset_price } else { value = liab_amount * liab_price } } if (activity_type === 'deposit' || activity_type === 'withdraw') { const { usd_equivalent } = activity.activity_details value = activity_type === 'withdraw' ? usd_equivalent * -1 : usd_equivalent } if (activity_type === 'swap') { const { swap_out_amount, swap_out_price_usd } = activity.activity_details value = swap_out_amount * swap_out_price_usd } if (activity_type === 'perp_trade') { const { maker_fee, price, quantity, taker_fee } = activity.activity_details value = quantity * price + maker_fee + taker_fee } if (activity_type === 'openbook_trade') { const { price, size } = activity.activity_details value = price * size } return value } return mangoAccount && (activityFeed.length || loadActivityFeed) ? ( <> {showTableView ? ( {activityFeed.map((activity: any) => { const { activity_type, block_datetime } = activity const { signature } = activity.activity_details const isLiquidation = activity_type === 'liquidate_token_with_token' const isOpenbook = activity_type === 'openbook_trade' const activityName = isLiquidation ? 'spot-liquidation' : isOpenbook ? 'spot-trade' : activity_type const amounts = getCreditAndDebit(activity) const value = getValue(activity) return ( handleShowActivityDetails(activity) : undefined } > ) })}
{t('date')} {t('activity:activity')} {t('activity:credit')} {t('activity:debit')} {t('activity:activity-value')} {t('explorer')}

{dayjs(block_datetime).format('ddd D MMM')}

{dayjs(block_datetime).format('h:mma')}

{t(`activity:${activityName}`)} {amounts.credit.value}{' '} {amounts.credit.symbol} {amounts.debit.value}{' '} {amounts.debit.symbol} = 0 ? 'text-th-up' : 'text-th-down' }`} > {value > 0 && activityName !== 'swap' && activityName !== 'perp_trade' && !isOpenbook ? '+' : ''} {formatFixedDecimals(value, true)} {activity_type !== 'liquidate_token_with_token' ? (
) : (
)}
) : (
{activityFeed.map((activity: any) => ( ))}
)} {loadActivityFeed ? (
{[...Array(4)].map((x, i) => (
))}
) : null} {activityFeed.length && activityFeed.length % 25 === 0 ? (
Show More
) : null} ) : (

{t('activity:no-activity')}

) } export default ActivityFeedTable const MobileActivityFeedItem = ({ activity, getValue, }: { activity: any getValue: (x: any) => number }) => { const { t } = useTranslation(['common', 'activity']) const [expandActivityDetails, setExpandActivityDetails] = useState(false) const [preferredExplorer] = useLocalStorageState( PREFERRED_EXPLORER_KEY, EXPLORERS[0] ) const { activity_type, block_datetime } = activity const { signature } = activity.activity_details const isLiquidation = activity_type === 'liquidate_token_with_token' const isSwap = activity_type === 'swap' const isPerp = activity_type === 'perp_trade' const activityName = isLiquidation ? 'spot-liquidation' : activity_type const value = getValue(activity) return (

{dayjs(block_datetime).format('ddd D MMM')}

{dayjs(block_datetime).format('h:mma')}

{t(`activity:${activityName}`)}

{isLiquidation ? ( formatFixedDecimals(value, true) ) : isSwap ? ( <> {activity.activity_details.swap_in_amount.toLocaleString( undefined, { maximumFractionDigits: 6 } )} {activity.activity_details.swap_in_symbol} for {activity.activity_details.swap_out_amount.toLocaleString( undefined, { maximumFractionDigits: 6 } )} {activity.activity_details.swap_out_symbol} ) : isPerp ? ( <> {activity.activity_details.taker_side === 'bid' ? 'BUY' : 'SELL'} {activity.activity_details.quantity} {activity.activity_details.perp_market} ) : ( <> {activity.activity_details.quantity} {activity.activity_details.symbol} )}

{isLiquidation ? ( setExpandActivityDetails((prev) => !prev)} > ) : (
)}

{t('activity:asset-liquidated')}

{formatDecimal(activity.activity_details.asset_amount)}{' '} {activity.activity_details.asset_symbol} at {' '} {formatFixedDecimals(activity.activity_details.asset_price, true)}

{formatFixedDecimals( activity.activity_details.asset_price * activity.activity_details.asset_amount, true )}

{t('activity:asset-returned')}

{formatDecimal(activity.activity_details.liab_amount)}{' '} {activity.activity_details.liab_symbol} at {' '} {formatFixedDecimals(activity.activity_details.liab_price, true)}

{formatFixedDecimals( activity.activity_details.liab_price * activity.activity_details.liab_amount, true )}

) }