import MangoDateRangePicker from '@components/forms/DateRangePicker' import Input from '@components/forms/Input' import Label from '@components/forms/Label' import MultiSelectDropdown from '@components/forms/MultiSelectDropdown' import { EXPLORERS } from '@components/settings/PreferredExplorerSettings' import Button, { IconButton } from '@components/shared/Button' import Tooltip from '@components/shared/Tooltip' import { Disclosure } from '@headlessui/react' import { AdjustmentsVerticalIcon, ArrowLeftIcon, ArrowPathIcon, ChevronDownIcon, ChevronRightIcon, } 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 useMangoGroup from 'hooks/useMangoGroup' import { useTranslation } from 'next-i18next' import Image from 'next/legacy/image' import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react' import { PREFERRED_EXPLORER_KEY } from 'utils/constants' import { formatDecimal, formatFixedDecimals } from 'utils/numbers' import ActivityFeedTable from './ActivityFeedTable' interface AdvancedFilters { symbol: string[] 'start-date': string 'end-date': string 'usd-lower': string 'usd-upper': string } const DEFAULT_ADVANCED_FILTERS = { symbol: [], 'start-date': '', 'end-date': '', 'usd-lower': '', 'usd-upper': '', } const DEFAULT_PARAMS = [ 'deposit', 'perp_trade', 'liquidate_token_with_token', 'openbook_trade', 'swap', 'withdraw', ] const ActivityFeed = () => { const activityFeed = mangoStore((s) => s.activityFeed.feed) const actions = mangoStore.getState().actions const { mangoAccountAddress } = useMangoAccount() const [showActivityDetail, setShowActivityDetail] = useState(null) const [advancedFilters, setAdvancedFilters] = useState( DEFAULT_ADVANCED_FILTERS ) const [params, setParams] = useState(DEFAULT_PARAMS) useEffect(() => { if (mangoAccountAddress) { actions.fetchActivityFeed(mangoAccountAddress) } }, [actions, mangoAccountAddress]) const handleShowActivityDetails = (activity: any) => { setShowActivityDetail(activity) } const advancedParamsString = useMemo(() => { let advancedParams = '' Object.entries(advancedFilters).map((entry) => { if (entry[1].length) { advancedParams = advancedParams + `&${entry[0]}=${entry[1]}` } }) return advancedParams }, [advancedFilters]) const queryParams = useMemo(() => { return !params.length || params.length === 6 ? advancedParamsString : `&activity-type=${params.toString()}${advancedParamsString}` }, [advancedParamsString, params]) return !showActivityDetail ? ( <> ) : ( ) } export default ActivityFeed const ActivityFilters = ({ filters, setFilters, params, advancedFilters, setAdvancedFilters, }: { filters: string[] setFilters: (x: string[]) => void params: string advancedFilters: AdvancedFilters setAdvancedFilters: (x: AdvancedFilters) => void }) => { const { t } = useTranslation(['common', 'activity']) const actions = mangoStore.getState().actions const loadActivityFeed = mangoStore((s) => s.activityFeed.loading) const { mangoAccountAddress } = useMangoAccount() const [showMobileFilters, setShowMobileFilters] = useState(false) const [hasFilters, setHasFilters] = useState(false) const handleUpdateResults = useCallback(() => { const set = mangoStore.getState().set if (params) { setHasFilters(true) } else { setHasFilters(false) } set((s) => { s.activityFeed.feed = [] s.activityFeed.loading = true }) if (mangoAccountAddress) { actions.fetchActivityFeed(mangoAccountAddress, 0, params) } }, [actions, params, mangoAccountAddress]) const handleResetFilters = useCallback(async () => { const set = mangoStore.getState().set setHasFilters(false) set((s) => { s.activityFeed.feed = [] s.activityFeed.loading = true }) if (mangoAccountAddress) { await actions.fetchActivityFeed(mangoAccountAddress) setAdvancedFilters(DEFAULT_ADVANCED_FILTERS) setFilters(DEFAULT_PARAMS) } }, [actions, mangoAccountAddress]) const handleUpdateMobileResults = () => { handleUpdateResults() setShowMobileFilters(false) } return mangoAccountAddress ? (
{hasFilters ? (
handleResetFilters()} size="small" >
) : null}
setShowMobileFilters(!showMobileFilters)} role="button" className={`default-transition h-12 w-full bg-th-bkg-2 px-4 hover:bg-th-bkg-3 md:px-6`} >
{t('activity:filter-results')}
) : null } interface FiltersFormProps { advancedFilters: any setAdvancedFilters: (x: any) => void filters: string[] setFilters: (x: string[]) => void } const FiltersForm = ({ advancedFilters, setAdvancedFilters, filters, setFilters, }: FiltersFormProps) => { const { t } = useTranslation(['common', 'activity']) const { group } = useMangoGroup() const [dateFrom, setDateFrom] = useState(null) const [dateTo, setDateTo] = useState(null) const [valueFrom, setValueFrom] = useState(advancedFilters['usd-lower'] || '') const [valueTo, setValueTo] = useState(advancedFilters['usd-upper'] || '') const symbols = useMemo(() => { if (!group) return [] return Array.from(group.banksMapByName, ([key]) => key) }, [group]) useEffect(() => { if (advancedFilters['start-date']) { setDateFrom(new Date(advancedFilters['start-date'])) } if (advancedFilters['end-date']) { setDateTo(new Date(advancedFilters['end-date'])) } }, []) const toggleTypeOption = (option: string) => { if (filters.includes(option)) { setFilters(filters.filter((opt) => opt !== option)) } else { setFilters(filters.concat(option)) } } const toggleSymbolOption = (option: string) => { setAdvancedFilters((prevSelected: any) => { const newSelections = prevSelected.symbol ? [...prevSelected.symbol] : [] if (newSelections.includes(option)) { return { ...prevSelected, symbol: newSelections.filter((item) => item !== option), } } else { newSelections.push(option) return { ...prevSelected, symbol: newSelections } } }) } useEffect(() => { if (dateFrom && dateTo) { setAdvancedFilters({ ...advancedFilters, 'start-date': dayjs(dateFrom).set('hour', 0).toISOString(), 'end-date': dayjs(dateTo) .set('hour', 23) .set('minute', 59) .toISOString(), }) } else { setAdvancedFilters({ ...advancedFilters, 'start-date': '', 'end-date': '', }) } }, [dateFrom, dateTo]) useEffect(() => { if (valueFrom && valueTo) { setAdvancedFilters({ ...advancedFilters, 'usd-lower': Math.floor(valueFrom), 'usd-upper': Math.ceil(valueTo), }) } else { setAdvancedFilters({ ...advancedFilters, 'usd-lower': '', 'usd-upper': '', }) } }, [valueFrom, valueTo]) return ( <>
) } const ActivityDetails = ({ activity, setShowActivityDetail, }: { activity: LiquidationFeedItem setShowActivityDetail: (x: any) => void }) => { const { t } = useTranslation(['common', 'activity', 'settings']) const [preferredExplorer] = useLocalStorageState( PREFERRED_EXPLORER_KEY, EXPLORERS[0] ) const { block_datetime, activity_type } = activity const { asset_amount, asset_price, asset_symbol, liab_amount, liab_price, liab_symbol, signature, } = activity.activity_details return (
setShowActivityDetail(null)} >

{t('activity:liquidation-details')}

{t('date')}

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

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

{t('activity:liquidation-type')}

{activity_type === 'liquidate_token_with_token' ? t('spot') : t('perp')}

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

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

{formatFixedDecimals(asset_price * asset_amount, true)}

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

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

{formatFixedDecimals(liab_price * liab_amount, true)}

) }