add disclosure panel for small breakpoints
This commit is contained in:
parent
bc55ef9204
commit
0faaa07bf3
|
@ -6,20 +6,40 @@ import MultiSelectDropdown from '@components/forms/MultiSelectDropdown'
|
||||||
import Button, { IconButton, LinkButton } from '@components/shared/Button'
|
import Button, { IconButton, LinkButton } from '@components/shared/Button'
|
||||||
import Modal from '@components/shared/Modal'
|
import Modal from '@components/shared/Modal'
|
||||||
import Tooltip from '@components/shared/Tooltip'
|
import Tooltip from '@components/shared/Tooltip'
|
||||||
import { ArrowLeftIcon, ArrowPathIcon } from '@heroicons/react/20/solid'
|
import { Disclosure, Transition } from '@headlessui/react'
|
||||||
|
import {
|
||||||
|
ArrowLeftIcon,
|
||||||
|
ArrowPathIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
} from '@heroicons/react/20/solid'
|
||||||
import { useWallet } from '@solana/wallet-adapter-react'
|
import { useWallet } from '@solana/wallet-adapter-react'
|
||||||
import mangoStore, { LiquidationFeedItem } from '@store/mangoStore'
|
import mangoStore, { LiquidationFeedItem } from '@store/mangoStore'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||||
|
import { useViewport } from 'hooks/useViewport'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { EXPLORERS } from 'pages/settings'
|
import { EXPLORERS } from 'pages/settings'
|
||||||
import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react'
|
import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { ModalProps } from 'types/modal'
|
|
||||||
import { PREFERRED_EXPLORER_KEY } from 'utils/constants'
|
import { PREFERRED_EXPLORER_KEY } from 'utils/constants'
|
||||||
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
|
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
|
||||||
|
import { breakpoints } from 'utils/theme'
|
||||||
import ActivityFeedTable from './ActivityFeedTable'
|
import ActivityFeedTable from './ActivityFeedTable'
|
||||||
|
|
||||||
|
interface Filters {
|
||||||
|
deposit: boolean
|
||||||
|
liquidate_token_with_token: boolean
|
||||||
|
withdraw: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AdvancedFilters {
|
||||||
|
symbol: string[]
|
||||||
|
'start-date': string
|
||||||
|
'end-date': string
|
||||||
|
'usd-lower': string
|
||||||
|
'usd-upper': string
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_FILTERS = {
|
const DEFAULT_FILTERS = {
|
||||||
deposit: true,
|
deposit: true,
|
||||||
liquidate_token_with_token: true,
|
liquidate_token_with_token: true,
|
||||||
|
@ -39,8 +59,8 @@ const DEFAULT_PARAMS = ['deposit', 'liquidate_token_with_token', 'withdraw']
|
||||||
const ActivityFeed = () => {
|
const ActivityFeed = () => {
|
||||||
const activityFeed = mangoStore((s) => s.activityFeed.feed)
|
const activityFeed = mangoStore((s) => s.activityFeed.feed)
|
||||||
const [showActivityDetail, setShowActivityDetail] = useState(null)
|
const [showActivityDetail, setShowActivityDetail] = useState(null)
|
||||||
const [filters, setFilters] = useState(DEFAULT_FILTERS)
|
const [filters, setFilters] = useState<Filters>(DEFAULT_FILTERS)
|
||||||
const [advancedFilters, setAdvancedFilters] = useState(
|
const [advancedFilters, setAdvancedFilters] = useState<AdvancedFilters>(
|
||||||
DEFAULT_ADVANCED_FILTERS
|
DEFAULT_ADVANCED_FILTERS
|
||||||
)
|
)
|
||||||
const [params, setParams] = useState<string[]>(DEFAULT_PARAMS)
|
const [params, setParams] = useState<string[]>(DEFAULT_PARAMS)
|
||||||
|
@ -115,11 +135,11 @@ const ActivityFilters = ({
|
||||||
advancedFilters,
|
advancedFilters,
|
||||||
setAdvancedFilters,
|
setAdvancedFilters,
|
||||||
}: {
|
}: {
|
||||||
filters: any
|
filters: Filters
|
||||||
updateFilters: any
|
updateFilters: (e: ChangeEvent<HTMLInputElement>, filter: string) => void
|
||||||
params: string
|
params: string
|
||||||
advancedFilters: any
|
advancedFilters: AdvancedFilters
|
||||||
setAdvancedFilters: (x: any) => void
|
setAdvancedFilters: (x: AdvancedFilters) => void
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation(['common', 'activity'])
|
const { t } = useTranslation(['common', 'activity'])
|
||||||
const actions = mangoStore((s) => s.actions)
|
const actions = mangoStore((s) => s.actions)
|
||||||
|
@ -127,6 +147,9 @@ const ActivityFilters = ({
|
||||||
const { connected } = useWallet()
|
const { connected } = useWallet()
|
||||||
const [showAdvancedFiltersModal, setShowAdvancedFiltersModal] =
|
const [showAdvancedFiltersModal, setShowAdvancedFiltersModal] =
|
||||||
useState(false)
|
useState(false)
|
||||||
|
const { width } = useViewport()
|
||||||
|
const isMobile = width ? width < breakpoints.lg : false
|
||||||
|
const [showFilters, setShowFilters] = useState(false)
|
||||||
|
|
||||||
const handleUpdateResults = useCallback(() => {
|
const handleUpdateResults = useCallback(() => {
|
||||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||||
|
@ -157,42 +180,25 @@ const ActivityFilters = ({
|
||||||
return Object.values(advancedFilters).find((v: any) => v.length > 0)
|
return Object.values(advancedFilters).find((v: any) => v.length > 0)
|
||||||
}, [advancedFilters])
|
}, [advancedFilters])
|
||||||
|
|
||||||
|
const handleUpdateAdvancedResults = () => {
|
||||||
|
handleUpdateResults()
|
||||||
|
setShowAdvancedFiltersModal(false)
|
||||||
|
}
|
||||||
|
|
||||||
return connected ? (
|
return connected ? (
|
||||||
<>
|
!isMobile ? (
|
||||||
<div className="flex flex-col items-center justify-between border-b border-th-bkg-3 bg-th-bkg-2 pt-4 md:flex-row md:pt-0 md:pl-6">
|
<>
|
||||||
<h3 className="mb-2 flex items-center text-sm md:mb-0 md:pr-6">
|
<div className="flex items-center justify-between border-b border-th-bkg-3 bg-th-bkg-2 pl-6">
|
||||||
Filter Results
|
<h3 className="flex items-center whitespace-nowrap pr-6 text-sm">
|
||||||
</h3>
|
Filter Results
|
||||||
<div className="grid w-full flex-1 grid-cols-2 pb-2 md:grid-cols-4 md:pb-0">
|
</h3>
|
||||||
<div className="col-span-1 flex h-8 items-center p-6 md:h-12 md:border-l md:border-th-bkg-4 md:p-4">
|
<ActivityTypeFiltersForm
|
||||||
<Checkbox
|
filters={filters}
|
||||||
checked={filters.deposit}
|
updateFilters={updateFilters}
|
||||||
onChange={(e) => updateFilters(e, 'deposit')}
|
/>
|
||||||
>
|
<div className="flex h-12 items-center justify-between border-l border-th-bkg-4 p-6">
|
||||||
<span className="text-sm md:text-xs lg:text-sm">Deposits</span>
|
|
||||||
</Checkbox>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-1 flex h-8 items-center p-6 md:h-12 md:border-l md:border-th-bkg-4 md:p-4">
|
|
||||||
<Checkbox
|
|
||||||
checked={filters.withdraw}
|
|
||||||
onChange={(e) => updateFilters(e, 'withdraw')}
|
|
||||||
>
|
|
||||||
<span className="text-sm md:text-xs lg:text-sm">Withdrawals</span>
|
|
||||||
</Checkbox>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-1 flex h-8 items-center p-6 md:h-12 md:border-l md:border-th-bkg-4 md:p-4">
|
|
||||||
<Checkbox
|
|
||||||
checked={filters.liquidate_token_with_token}
|
|
||||||
onChange={(e) => updateFilters(e, 'liquidate_token_with_token')}
|
|
||||||
>
|
|
||||||
<span className="text-sm md:text-xs lg:text-sm">
|
|
||||||
Liquidations
|
|
||||||
</span>
|
|
||||||
</Checkbox>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-1 flex h-8 items-center justify-between p-6 md:h-12 md:border-l md:border-th-bkg-4 md:p-4">
|
|
||||||
<LinkButton
|
<LinkButton
|
||||||
className="text-sm md:text-xs lg:text-sm"
|
className="whitespace-nowrap text-sm"
|
||||||
onClick={() => setShowAdvancedFiltersModal(true)}
|
onClick={() => setShowAdvancedFiltersModal(true)}
|
||||||
>
|
>
|
||||||
Advanced Filters
|
Advanced Filters
|
||||||
|
@ -200,7 +206,7 @@ const ActivityFilters = ({
|
||||||
{hasAdvancedFilters ? (
|
{hasAdvancedFilters ? (
|
||||||
<Tooltip content={t('activity:reset-advanced-filters')}>
|
<Tooltip content={t('activity:reset-advanced-filters')}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={loadActivityFeed ? 'animate-spin' : ''}
|
className={`ml-4 ${loadActivityFeed ? 'animate-spin' : ''}`}
|
||||||
onClick={() => handleResetAdvancedFilters()}
|
onClick={() => handleResetAdvancedFilters()}
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
|
@ -209,42 +215,148 @@ const ActivityFilters = ({
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
<Button className="h-12 rounded-none" onClick={handleUpdateResults}>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
{showAdvancedFiltersModal ? (
|
||||||
className="h-12 w-full rounded-none bg-th-bkg-4 md:w-auto"
|
<Modal
|
||||||
onClick={handleUpdateResults}
|
isOpen={showAdvancedFiltersModal}
|
||||||
|
onClose={() => setShowAdvancedFiltersModal(false)}
|
||||||
|
>
|
||||||
|
<h2 className="mb-2 text-center">
|
||||||
|
{t('activity:advanced-filters')}
|
||||||
|
</h2>
|
||||||
|
<AdvancedFiltersForm
|
||||||
|
advancedFilters={advancedFilters}
|
||||||
|
setAdvancedFilters={setAdvancedFilters}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className="w-full"
|
||||||
|
size="large"
|
||||||
|
onClick={handleUpdateAdvancedResults}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
</Modal>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Disclosure>
|
||||||
|
<div className="relative">
|
||||||
|
{hasAdvancedFilters ? (
|
||||||
|
<div className="absolute right-14 top-3">
|
||||||
|
<Tooltip content={t('activity:reset-advanced-filters')}>
|
||||||
|
<IconButton
|
||||||
|
className={`${loadActivityFeed ? 'animate-spin' : ''}`}
|
||||||
|
onClick={() => handleResetAdvancedFilters()}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<ArrowPathIcon className="h-5 w-5" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div
|
||||||
|
onClick={() => setShowFilters(!showFilters)}
|
||||||
|
role="button"
|
||||||
|
className={`w-full border-b border-th-bkg-3 bg-th-bkg-2 px-6 py-4`}
|
||||||
|
>
|
||||||
|
<Disclosure.Button
|
||||||
|
className={`flex h-full w-full items-center justify-between rounded-none`}
|
||||||
|
>
|
||||||
|
<span className="text-th-fgd-1">Filters Results</span>
|
||||||
|
|
||||||
|
<ChevronDownIcon
|
||||||
|
className={`${
|
||||||
|
showFilters ? 'rotate-180' : 'rotate-360'
|
||||||
|
} h-6 w-6 flex-shrink-0`}
|
||||||
|
/>
|
||||||
|
</Disclosure.Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Transition
|
||||||
|
appear={true}
|
||||||
|
show={showFilters}
|
||||||
|
enter="transition-all ease-in duration-300"
|
||||||
|
enterFrom="opacity-100 max-h-0"
|
||||||
|
enterTo="opacity-100 max-h-full"
|
||||||
|
leave="transition-all ease-out duration-300"
|
||||||
|
leaveFrom="opacity-100 max-h-full"
|
||||||
|
leaveTo="opacity-0 max-h-0"
|
||||||
>
|
>
|
||||||
Update
|
<Disclosure.Panel className="bg-th-bkg-2 px-6 pb-6">
|
||||||
</Button>
|
<div className="py-4">
|
||||||
</div>
|
<Label text={t('activity:activity-type')} />
|
||||||
{showAdvancedFiltersModal ? (
|
<ActivityTypeFiltersForm
|
||||||
<AdvancedFiltersModal
|
filters={filters}
|
||||||
advancedFilters={advancedFilters}
|
updateFilters={updateFilters}
|
||||||
setAdvancedFilters={setAdvancedFilters}
|
/>
|
||||||
isOpen={showAdvancedFiltersModal}
|
</div>
|
||||||
onClose={() => setShowAdvancedFiltersModal(false)}
|
<AdvancedFiltersForm
|
||||||
handleUpdateResults={handleUpdateResults}
|
advancedFilters={advancedFilters}
|
||||||
/>
|
setAdvancedFilters={setAdvancedFilters}
|
||||||
) : null}
|
/>
|
||||||
</>
|
<Button
|
||||||
|
className="w-full"
|
||||||
|
size="large"
|
||||||
|
onClick={handleUpdateAdvancedResults}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
</Disclosure.Panel>
|
||||||
|
</Transition>
|
||||||
|
</Disclosure>
|
||||||
|
)
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AdvancedFiltersModalProps {
|
const ActivityTypeFiltersForm = ({
|
||||||
advancedFilters: any
|
filters,
|
||||||
setAdvancedFilters: (x: any) => void
|
updateFilters,
|
||||||
handleUpdateResults: () => void
|
}: {
|
||||||
|
filters: Filters
|
||||||
|
updateFilters: (e: ChangeEvent<HTMLInputElement>, filter: string) => void
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="flex w-full flex-col space-y-2 md:flex-row md:space-y-0">
|
||||||
|
<div className="flex h-8 flex-1 items-center lg:h-12 lg:border-l lg:border-th-bkg-4 lg:p-4">
|
||||||
|
<Checkbox
|
||||||
|
checked={filters.deposit}
|
||||||
|
onChange={(e) => updateFilters(e, 'deposit')}
|
||||||
|
>
|
||||||
|
<span className="text-sm">Deposits</span>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
<div className="flex h-8 flex-1 items-center lg:h-12 lg:border-l lg:border-th-bkg-4 lg:p-4">
|
||||||
|
<Checkbox
|
||||||
|
checked={filters.withdraw}
|
||||||
|
onChange={(e) => updateFilters(e, 'withdraw')}
|
||||||
|
>
|
||||||
|
<span className="text-sm">Withdrawals</span>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
<div className="flex h-8 flex-1 items-center lg:h-12 lg:border-l lg:border-th-bkg-4 lg:p-4">
|
||||||
|
<Checkbox
|
||||||
|
checked={filters.liquidate_token_with_token}
|
||||||
|
onChange={(e) => updateFilters(e, 'liquidate_token_with_token')}
|
||||||
|
>
|
||||||
|
<span className="text-sm">Liquidations</span>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModalCombinedProps = ModalProps & AdvancedFiltersModalProps
|
interface AdvancedFiltersFormProps {
|
||||||
|
advancedFilters: any
|
||||||
|
setAdvancedFilters: (x: any) => void
|
||||||
|
}
|
||||||
|
|
||||||
const AdvancedFiltersModal = ({
|
const AdvancedFiltersForm = ({
|
||||||
isOpen,
|
|
||||||
onClose,
|
|
||||||
advancedFilters,
|
advancedFilters,
|
||||||
setAdvancedFilters,
|
setAdvancedFilters,
|
||||||
handleUpdateResults,
|
}: AdvancedFiltersFormProps) => {
|
||||||
}: ModalCombinedProps) => {
|
|
||||||
const { t } = useTranslation(['common', 'activity'])
|
const { t } = useTranslation(['common', 'activity'])
|
||||||
const group = mangoStore((s) => s.group)
|
const group = mangoStore((s) => s.group)
|
||||||
const [dateFrom, setDateFrom] = useState<Date | null>(null)
|
const [dateFrom, setDateFrom] = useState<Date | null>(null)
|
||||||
|
@ -319,14 +431,8 @@ const AdvancedFiltersModal = ({
|
||||||
}
|
}
|
||||||
}, [valueFrom, valueTo])
|
}, [valueFrom, valueTo])
|
||||||
|
|
||||||
const handleUpdateAdvancedResults = () => {
|
|
||||||
handleUpdateResults()
|
|
||||||
onClose()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onClose={onClose}>
|
<>
|
||||||
<h2 className="mb-2 text-center">{t('activity:advanced-filters')}</h2>
|
|
||||||
<Label text={t('tokens')} />
|
<Label text={t('tokens')} />
|
||||||
<MultiSelectDropdown
|
<MultiSelectDropdown
|
||||||
options={symbols}
|
options={symbols}
|
||||||
|
@ -365,14 +471,7 @@ const AdvancedFiltersModal = ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
</>
|
||||||
className="w-full"
|
|
||||||
size="large"
|
|
||||||
onClick={handleUpdateAdvancedResults}
|
|
||||||
>
|
|
||||||
Update
|
|
||||||
</Button>
|
|
||||||
</Modal>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ const MultiSelectDropdown = ({
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute top-12 z-10 h-72 w-full overflow-y-auto">
|
<Popover.Panel className="absolute top-14 z-10 h-72 w-full overflow-y-auto">
|
||||||
<div className="relative space-y-2.5 rounded-md bg-th-bkg-3 p-3">
|
<div className="relative space-y-2.5 rounded-md bg-th-bkg-3 p-3">
|
||||||
{options.map((option: string) => {
|
{options.map((option: string) => {
|
||||||
const isSelected = selected.includes(option)
|
const isSelected = selected.includes(option)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* Range Picker */
|
/* Range Picker */
|
||||||
|
|
||||||
.nice-dates .nice-dates-popover {
|
.nice-dates .nice-dates-popover {
|
||||||
@apply max-w-[384px] bg-th-bkg-4;
|
@apply z-20 max-w-[384px] bg-th-bkg-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nice-dates .nice-dates-navigation {
|
.nice-dates .nice-dates-navigation {
|
||||||
|
|
Loading…
Reference in New Issue