show details of used accounts in settings and hook for data
This commit is contained in:
parent
60810ca2e4
commit
ae9235b1d1
|
@ -1,4 +1,4 @@
|
|||
import { Fragment, useMemo, useState } from 'react'
|
||||
import { Fragment, useState } from 'react'
|
||||
import Button, { IconButton } from '../shared/Button'
|
||||
import {
|
||||
ArrowDownRightIcon,
|
||||
|
@ -28,7 +28,7 @@ import useUnownedAccount from 'hooks/useUnownedAccount'
|
|||
import { useViewport } from 'hooks/useViewport'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
import MangoAccountSizeModal from '@components/modals/MangoAccountSizeModal'
|
||||
import { getIsAccountSizeFull } from '@components/settings/AccountSettings'
|
||||
import useMangoAccountAccounts from 'hooks/useMangoAccountAccounts'
|
||||
|
||||
export const handleCopyAddress = (
|
||||
mangoAccount: MangoAccount,
|
||||
|
@ -55,6 +55,7 @@ const AccountActions = () => {
|
|||
const { isDelegatedAccount, isUnownedAccount } = useUnownedAccount()
|
||||
const { width } = useViewport()
|
||||
const isMobile = width ? width < breakpoints.sm : false
|
||||
const { isAccountFull } = useMangoAccountAccounts()
|
||||
|
||||
const handleBorrowModal = () => {
|
||||
if (mangoAccountAddress || !connected) {
|
||||
|
@ -64,11 +65,6 @@ const AccountActions = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const isAccountFull = useMemo(() => {
|
||||
if (!mangoAccountAddress) return true
|
||||
return getIsAccountSizeFull()
|
||||
}, [mangoAccountAddress])
|
||||
|
||||
return (
|
||||
<>
|
||||
{isUnownedAccount ? null : (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import NumberFormat, {
|
||||
NumberFormatValues,
|
||||
|
@ -15,11 +15,9 @@ import InlineNotification from '../shared/InlineNotification'
|
|||
import Modal from '@components/shared/Modal'
|
||||
import { ModalProps } from 'types/modal'
|
||||
import Label from '@components/forms/Label'
|
||||
import {
|
||||
import useMangoAccountAccounts, {
|
||||
getAvaialableAccountsColor,
|
||||
getTotalMangoAccountAccounts,
|
||||
getUsedMangoAccountAccounts,
|
||||
} from '@components/settings/AccountSettings'
|
||||
} from 'hooks/useMangoAccountAccounts'
|
||||
|
||||
const MIN_ACCOUNTS = 8
|
||||
export const MAX_ACCOUNTS: AccountSizeForm = {
|
||||
|
@ -56,35 +54,16 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
|
|||
useState<AccountSizeForm>(DEFAULT_FORM)
|
||||
const [formErrors, setFormErrors] = useState<FormErrors>()
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
const [availableTokens, availableSerum3, availablePerps, availablePerpOo] =
|
||||
useMemo(() => {
|
||||
const [usedTokens, usedSerum3, usedPerps, usedPerpOo] =
|
||||
getUsedMangoAccountAccounts(mangoAccountAddress)
|
||||
const [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders] =
|
||||
getTotalMangoAccountAccounts(mangoAccountAddress)
|
||||
return [
|
||||
<span
|
||||
className={getAvaialableAccountsColor(usedTokens, totalTokens)}
|
||||
key="tokenAccounts"
|
||||
>{`${usedTokens}/${totalTokens}`}</span>,
|
||||
<span
|
||||
className={getAvaialableAccountsColor(usedSerum3, totalSerum3)}
|
||||
key="spotOpenOrders"
|
||||
>{`${usedSerum3}/${totalSerum3}`}</span>,
|
||||
<span
|
||||
className={getAvaialableAccountsColor(usedPerps, totalPerps)}
|
||||
key="perpAccounts"
|
||||
>{`${usedPerps}/${totalPerps}`}</span>,
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
const {
|
||||
usedTokens,
|
||||
usedSerum3,
|
||||
usedPerps,
|
||||
usedPerpOo,
|
||||
totalTokens,
|
||||
totalSerum3,
|
||||
totalPerps,
|
||||
totalPerpOpenOrders,
|
||||
)}
|
||||
key="perpOpenOrders"
|
||||
>{`${usedPerpOo}/${totalPerpOpenOrders}`}</span>,
|
||||
]
|
||||
}, [mangoAccountAddress])
|
||||
} = useMangoAccountAccounts()
|
||||
|
||||
useEffect(() => {
|
||||
if (mangoAccount) {
|
||||
|
@ -245,7 +224,14 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
|
|||
</p>
|
||||
<div className="mb-4">
|
||||
<AccountSizeFormInput
|
||||
availableAccounts={availableTokens}
|
||||
availableAccounts={
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedTokens.length,
|
||||
totalTokens.length,
|
||||
)}
|
||||
>{`${usedTokens.length}/${totalTokens.length}`}</span>
|
||||
}
|
||||
disabled={
|
||||
mangoAccount
|
||||
? mangoAccount.tokens.length >=
|
||||
|
@ -265,7 +251,14 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
|
|||
</div>
|
||||
<div className="mb-4">
|
||||
<AccountSizeFormInput
|
||||
availableAccounts={availableSerum3}
|
||||
availableAccounts={
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedSerum3.length,
|
||||
totalSerum3.length,
|
||||
)}
|
||||
>{`${usedSerum3.length}/${totalSerum3.length}`}</span>
|
||||
}
|
||||
disabled
|
||||
error={formErrors?.spotOpenOrders}
|
||||
label={t('settings:spot-open-orders')}
|
||||
|
@ -280,7 +273,15 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
|
|||
</div>
|
||||
<div className="mb-4">
|
||||
<AccountSizeFormInput
|
||||
availableAccounts={availablePerps}
|
||||
availableAccounts={
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedPerps.length,
|
||||
totalPerps.length,
|
||||
)}
|
||||
key="spotOpenOrders"
|
||||
>{`${usedPerps.length}/${totalPerps.length}`}</span>
|
||||
}
|
||||
disabled
|
||||
error={formErrors?.perpAccounts}
|
||||
label={t('settings:perp-positions')}
|
||||
|
@ -295,7 +296,15 @@ const MangoAccountSizeModal = ({ isOpen, onClose }: ModalProps) => {
|
|||
</div>
|
||||
<div>
|
||||
<AccountSizeFormInput
|
||||
availableAccounts={availablePerpOo}
|
||||
availableAccounts={
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedPerpOo.length,
|
||||
totalPerpOpenOrders.length,
|
||||
)}
|
||||
key="spotOpenOrders"
|
||||
>{`${usedPerpOo.length}/${totalPerpOpenOrders.length}`}</span>
|
||||
}
|
||||
disabled={
|
||||
mangoAccount
|
||||
? mangoAccount.perpOpenOrders.length >=
|
||||
|
|
|
@ -2,119 +2,41 @@ import MangoAccountSizeModal, {
|
|||
MAX_ACCOUNTS,
|
||||
} from '@components/modals/MangoAccountSizeModal'
|
||||
import { LinkButton } from '@components/shared/Button'
|
||||
import TokenLogo from '@components/shared/TokenLogo'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import MarketLogos from '@components/trade/MarketLogos'
|
||||
import { Disclosure } from '@headlessui/react'
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
ExclamationCircleIcon,
|
||||
SquaresPlusIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useMangoAccountAccounts, {
|
||||
getAvaialableAccountsColor,
|
||||
} from 'hooks/useMangoAccountAccounts'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
// todo: use these functions to auto show model when an account is full
|
||||
export const getUsedMangoAccountAccounts = (
|
||||
mangoAccountAddress: string | undefined,
|
||||
) => {
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
if (!mangoAccountAddress || !mangoAccount) return [0, 0, 0, 0]
|
||||
const { tokens, serum3, perps, perpOpenOrders } = mangoAccount
|
||||
const usedTokens = tokens.filter((t) => t.inUseCount).length
|
||||
const usedSerum3 = serum3.filter((s) => s.marketIndex !== 65535).length
|
||||
const usedPerps = perps.filter((p) => p.marketIndex !== 65535).length
|
||||
const usedPerpOo = perpOpenOrders.filter(
|
||||
(p) => p.orderMarket !== 65535,
|
||||
).length
|
||||
return [usedTokens, usedSerum3, usedPerps, usedPerpOo]
|
||||
}
|
||||
|
||||
export const getTotalMangoAccountAccounts = (
|
||||
mangoAccountAddress: string | undefined,
|
||||
) => {
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
if (!mangoAccountAddress || !mangoAccount) return [0, 0, 0, 0]
|
||||
const { tokens, serum3, perps, perpOpenOrders } = mangoAccount
|
||||
const totalTokens = tokens.length
|
||||
const totalSerum3 = serum3.length
|
||||
const totalPerps = perps.length
|
||||
const totalPerpOpenOrders = perpOpenOrders.length
|
||||
return [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders]
|
||||
}
|
||||
|
||||
export const getAvaialableAccountsColor = (used: number, total: number) => {
|
||||
const remaining = total - used
|
||||
return remaining >= 4
|
||||
? 'text-th-up'
|
||||
: remaining >= 2
|
||||
? 'text-th-warning'
|
||||
: 'text-th-down'
|
||||
}
|
||||
|
||||
const isAccountSlotFull = (slots: number, max: string) => {
|
||||
const numberMax = Number(max)
|
||||
return slots >= numberMax
|
||||
}
|
||||
|
||||
export const getIsAccountSizeFull = () => {
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
if (!mangoAccount) return true
|
||||
return (
|
||||
isAccountSlotFull(
|
||||
mangoAccount.tokens.length,
|
||||
MAX_ACCOUNTS.tokenAccounts!,
|
||||
) &&
|
||||
isAccountSlotFull(
|
||||
mangoAccount.serum3.length,
|
||||
MAX_ACCOUNTS.spotOpenOrders!,
|
||||
) &&
|
||||
isAccountSlotFull(mangoAccount.perps.length, MAX_ACCOUNTS.perpAccounts!) &&
|
||||
isAccountSlotFull(
|
||||
mangoAccount.perpOpenOrders.length,
|
||||
MAX_ACCOUNTS.perpOpenOrders!,
|
||||
)
|
||||
)
|
||||
}
|
||||
import { useState } from 'react'
|
||||
|
||||
const AccountSettings = () => {
|
||||
const { t } = useTranslation(['common', 'settings'])
|
||||
const { mangoAccountAddress } = useMangoAccount()
|
||||
const { group } = useMangoGroup()
|
||||
const [showAccountSizeModal, setShowAccountSizeModal] = useState(false)
|
||||
|
||||
const [availableTokens, availableSerum3, availablePerps, availablePerpOo] =
|
||||
useMemo(() => {
|
||||
const [usedTokens, usedSerum3, usedPerps, usedPerpOo] =
|
||||
getUsedMangoAccountAccounts(mangoAccountAddress)
|
||||
const [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders] =
|
||||
getTotalMangoAccountAccounts(mangoAccountAddress)
|
||||
return [
|
||||
<span
|
||||
className={getAvaialableAccountsColor(usedTokens, totalTokens)}
|
||||
key="tokenAccounts"
|
||||
>{`${usedTokens}/${totalTokens}`}</span>,
|
||||
<span
|
||||
className={getAvaialableAccountsColor(usedSerum3, totalSerum3)}
|
||||
key="spotOpenOrders"
|
||||
>{`${usedSerum3}/${totalSerum3}`}</span>,
|
||||
<span
|
||||
className={getAvaialableAccountsColor(usedPerps, totalPerps)}
|
||||
key="perpAccounts"
|
||||
>{`${usedPerps}/${totalPerps}`}</span>,
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
const {
|
||||
usedTokens,
|
||||
usedSerum3,
|
||||
usedPerps,
|
||||
usedPerpOo,
|
||||
totalTokens,
|
||||
totalSerum3,
|
||||
totalPerps,
|
||||
totalPerpOpenOrders,
|
||||
)}
|
||||
key="perpOpenOrders"
|
||||
>{`${usedPerpOo}/${totalPerpOpenOrders}`}</span>,
|
||||
]
|
||||
}, [mangoAccountAddress])
|
||||
isAccountFull,
|
||||
} = useMangoAccountAccounts()
|
||||
|
||||
const isAccountFull = useMemo(() => {
|
||||
if (!mangoAccountAddress) return true
|
||||
return getIsAccountSizeFull()
|
||||
}, [mangoAccountAddress])
|
||||
|
||||
return (
|
||||
return mangoAccountAddress && group ? (
|
||||
<>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2 className="text-base">{t('account')}</h2>
|
||||
|
@ -135,17 +57,66 @@ const AccountSettings = () => {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 py-4 md:flex-row md:items-center md:justify-between md:px-4">
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Disclosure.Button className="w-full border-t border-th-bkg-3 py-4 md:px-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Tooltip
|
||||
content={t('settings:tooltip-token-accounts', {
|
||||
max: MAX_ACCOUNTS.tokenAccounts,
|
||||
})}
|
||||
>
|
||||
<p className="tooltip-underline mb-2 md:mb-0">{t('tokens')}</p>
|
||||
<p className="tooltip-underline">{t('tokens')}</p>
|
||||
</Tooltip>
|
||||
<p className="font-mono text-th-fgd-2">{availableTokens}</p>
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className="font-mono">
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedTokens.length,
|
||||
totalTokens.length,
|
||||
)}
|
||||
>{`${usedTokens.length}/${totalTokens.length}`}</span>
|
||||
</p>
|
||||
<ChevronDownIcon
|
||||
className={`${
|
||||
open ? 'rotate-180' : 'rotate-360'
|
||||
} h-6 w-6 flex-shrink-0 text-th-fgd-3`}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 py-4 md:flex-row md:items-center md:justify-between md:px-4">
|
||||
</div>
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel className="md:px-4 pb-2">
|
||||
{usedTokens.length ? (
|
||||
usedTokens.map((token, i) => {
|
||||
const tokenBank = group.getFirstBankByTokenIndex(
|
||||
token.tokenIndex,
|
||||
)
|
||||
return (
|
||||
<div
|
||||
className="flex items-center mb-2"
|
||||
key={token.tokenIndex}
|
||||
>
|
||||
<p className="mr-3 text-th-fgd-4">{i + 1}.</p>
|
||||
<TokenLogo bank={tokenBank} size={20} />
|
||||
<p className="ml-2 text-th-fgd-2">{tokenBank.name}</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<p className="text-center mb-2">
|
||||
{t('notifications:empty-state-title')}...
|
||||
</p>
|
||||
)}
|
||||
</Disclosure.Panel>
|
||||
</>
|
||||
)}
|
||||
</Disclosure>
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Disclosure.Button className="w-full border-t border-th-bkg-3 py-4 md:px-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Tooltip
|
||||
content={t('settings:tooltip-spot-open-orders', {
|
||||
max: MAX_ACCOUNTS.spotOpenOrders,
|
||||
|
@ -155,9 +126,55 @@ const AccountSettings = () => {
|
|||
{t('settings:spot-open-orders')}
|
||||
</p>
|
||||
</Tooltip>
|
||||
<p className="font-mono text-th-fgd-2">{availableSerum3}</p>
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className="font-mono">
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedSerum3.length,
|
||||
totalSerum3.length,
|
||||
)}
|
||||
key="spotOpenOrders"
|
||||
>{`${usedSerum3.length}/${totalSerum3.length}`}</span>
|
||||
</p>
|
||||
<ChevronDownIcon
|
||||
className={`${
|
||||
open ? 'rotate-180' : 'rotate-360'
|
||||
} h-6 w-6 flex-shrink-0 text-th-fgd-3`}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 py-4 md:flex-row md:items-center md:justify-between md:px-4">
|
||||
</div>
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel className="md:px-4 pb-2">
|
||||
{usedSerum3.length ? (
|
||||
usedSerum3.map((mkt, i) => {
|
||||
const market = group.getSerum3MarketByMarketIndex(
|
||||
mkt.marketIndex,
|
||||
)
|
||||
return (
|
||||
<div
|
||||
className="flex items-center mb-2"
|
||||
key={mkt.marketIndex}
|
||||
>
|
||||
<p className="mr-3 text-th-fgd-4">{i + 1}.</p>
|
||||
<MarketLogos market={market} />
|
||||
<p className="text-th-fgd-2">{market.name}</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<p className="text-center mb-2">
|
||||
{t('notifications:empty-state-title')}...
|
||||
</p>
|
||||
)}
|
||||
</Disclosure.Panel>
|
||||
</>
|
||||
)}
|
||||
</Disclosure>
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Disclosure.Button className="w-full border-t border-th-bkg-3 py-4 md:px-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Tooltip
|
||||
content={t('settings:tooltip-perp-positions', {
|
||||
max: MAX_ACCOUNTS.perpAccounts,
|
||||
|
@ -167,8 +184,107 @@ const AccountSettings = () => {
|
|||
{t('settings:perp-positions')}
|
||||
</p>
|
||||
</Tooltip>
|
||||
<p className="font-mono text-th-fgd-2">{availablePerps}</p>
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className="font-mono">
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedPerps.length,
|
||||
totalPerps.length,
|
||||
)}
|
||||
>{`${usedPerps.length}/${totalPerps.length}`}</span>
|
||||
</p>
|
||||
<ChevronDownIcon
|
||||
className={`${
|
||||
open ? 'rotate-180' : 'rotate-360'
|
||||
} h-6 w-6 flex-shrink-0 text-th-fgd-3`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel className="md:px-4 pb-2">
|
||||
{usedPerps.length ? (
|
||||
usedPerps.map((perp, i) => {
|
||||
const market = group.getPerpMarketByMarketIndex(
|
||||
perp.marketIndex,
|
||||
)
|
||||
return (
|
||||
<div
|
||||
className="flex items-center mb-2"
|
||||
key={perp.marketIndex}
|
||||
>
|
||||
<p className="mr-3 text-th-fgd-4">{i + 1}.</p>
|
||||
<MarketLogos market={market} />
|
||||
<p className="text-th-fgd-2">{market.name}</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<p className="text-center mb-2">
|
||||
{t('notifications:empty-state-title')}...
|
||||
</p>
|
||||
)}
|
||||
</Disclosure.Panel>
|
||||
</>
|
||||
)}
|
||||
</Disclosure>
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Disclosure.Button className="w-full border-t border-th-bkg-3 py-4 md:px-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Tooltip
|
||||
content={t('settings:tooltip-perp-open-orders', {
|
||||
max: MAX_ACCOUNTS.perpOpenOrders,
|
||||
})}
|
||||
>
|
||||
<p className="tooltip-underline mb-2 md:mb-0">
|
||||
{t('settings:perp-open-orders')}
|
||||
</p>
|
||||
</Tooltip>
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className="font-mono">
|
||||
<span
|
||||
className={getAvaialableAccountsColor(
|
||||
usedPerpOo.length,
|
||||
totalPerpOpenOrders.length,
|
||||
)}
|
||||
>{`${usedPerpOo.length}/${totalPerpOpenOrders.length}`}</span>
|
||||
</p>
|
||||
<ChevronDownIcon
|
||||
className={`${
|
||||
open ? 'rotate-180' : 'rotate-360'
|
||||
} h-6 w-6 flex-shrink-0 text-th-fgd-3`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Disclosure.Button>
|
||||
<Disclosure.Panel className="md:px-4 pb-2">
|
||||
{usedPerpOo.length ? (
|
||||
usedPerpOo.map((perp, i) => {
|
||||
const market = group.getPerpMarketByMarketIndex(
|
||||
perp.orderMarket,
|
||||
)
|
||||
return (
|
||||
<div
|
||||
className="flex items-center mb-2"
|
||||
key={perp.orderMarket}
|
||||
>
|
||||
<p className="mr-3 text-th-fgd-4">{i + 1}.</p>
|
||||
<MarketLogos market={market} />
|
||||
<p className="text-th-fgd-2">{market.name}</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<p className="text-center mb-2">
|
||||
{t('notifications:empty-state-title')}...
|
||||
</p>
|
||||
)}
|
||||
</Disclosure.Panel>
|
||||
</>
|
||||
)}
|
||||
</Disclosure>
|
||||
{/*
|
||||
<div className="flex flex-col border-t border-th-bkg-3 py-4 md:flex-row md:items-center md:justify-between md:px-4">
|
||||
<Tooltip
|
||||
content={t('settings:tooltip-perp-open-orders', {
|
||||
|
@ -180,7 +296,7 @@ const AccountSettings = () => {
|
|||
</p>
|
||||
</Tooltip>
|
||||
<p className="font-mono text-th-fgd-2">{availablePerpOo}</p>
|
||||
</div>
|
||||
</div> */}
|
||||
{showAccountSizeModal ? (
|
||||
<MangoAccountSizeModal
|
||||
isOpen={showAccountSizeModal}
|
||||
|
@ -188,7 +304,7 @@ const AccountSettings = () => {
|
|||
/>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
) : null
|
||||
}
|
||||
|
||||
export default AccountSettings
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import mangoStore from '@store/mangoStore'
|
||||
import { useMemo } from 'react'
|
||||
import useMangoAccount from './useMangoAccount'
|
||||
import { MAX_ACCOUNTS } from '@components/modals/MangoAccountSizeModal'
|
||||
import {
|
||||
PerpOo,
|
||||
PerpPosition,
|
||||
Serum3Orders,
|
||||
TokenPosition,
|
||||
} from '@blockworks-foundation/mango-v4'
|
||||
|
||||
export const getAvaialableAccountsColor = (used: number, total: number) => {
|
||||
const remaining = total - used
|
||||
return remaining >= 4
|
||||
? 'text-th-up'
|
||||
: remaining >= 2
|
||||
? 'text-th-warning'
|
||||
: 'text-th-down'
|
||||
}
|
||||
|
||||
const isAccountSlotFull = (slots: number, max: string) => {
|
||||
const numberMax = Number(max)
|
||||
return slots >= numberMax
|
||||
}
|
||||
|
||||
const getIsAccountSizeFull = () => {
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
if (!mangoAccount) return true
|
||||
return (
|
||||
isAccountSlotFull(
|
||||
mangoAccount.tokens.length,
|
||||
MAX_ACCOUNTS.tokenAccounts!,
|
||||
) &&
|
||||
isAccountSlotFull(
|
||||
mangoAccount.serum3.length,
|
||||
MAX_ACCOUNTS.spotOpenOrders!,
|
||||
) &&
|
||||
isAccountSlotFull(mangoAccount.perps.length, MAX_ACCOUNTS.perpAccounts!) &&
|
||||
isAccountSlotFull(
|
||||
mangoAccount.perpOpenOrders.length,
|
||||
MAX_ACCOUNTS.perpOpenOrders!,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default function useMangoAccountAccounts() {
|
||||
const { mangoAccountAddress } = useMangoAccount()
|
||||
|
||||
const [usedTokens, usedSerum3, usedPerps, usedPerpOo] = useMemo(() => {
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
if (!mangoAccountAddress || !mangoAccount) return [[], [], [], []]
|
||||
const { tokens, serum3, perps, perpOpenOrders } = mangoAccount
|
||||
const usedTokens: TokenPosition[] = tokens.filter((t) => t.inUseCount)
|
||||
const usedSerum3: Serum3Orders[] = serum3.filter(
|
||||
(s) => s.marketIndex !== 65535,
|
||||
)
|
||||
const usedPerps: PerpPosition[] = perps.filter(
|
||||
(p) => p.marketIndex !== 65535,
|
||||
)
|
||||
const usedPerpOo: PerpOo[] = perpOpenOrders.filter(
|
||||
(p) => p.orderMarket !== 65535,
|
||||
)
|
||||
return [usedTokens, usedSerum3, usedPerps, usedPerpOo]
|
||||
}, [mangoAccountAddress])
|
||||
|
||||
const [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders] =
|
||||
useMemo(() => {
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
if (!mangoAccountAddress || !mangoAccount) return [[], [], [], []]
|
||||
const { tokens, serum3, perps, perpOpenOrders } = mangoAccount
|
||||
const totalTokens = tokens
|
||||
const totalSerum3 = serum3
|
||||
const totalPerps = perps
|
||||
const totalPerpOpenOrders = perpOpenOrders
|
||||
return [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders]
|
||||
}, [mangoAccountAddress])
|
||||
|
||||
// const [availableTokens, availableSerum3, availablePerps, availablePerpOo] =
|
||||
// useMemo(() => {
|
||||
// const [usedTokens, usedSerum3, usedPerps, usedPerpOo] =
|
||||
// getUsedMangoAccountAccounts(mangoAccountAddress)
|
||||
// const [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders] =
|
||||
// getTotalMangoAccountAccounts(mangoAccountAddress)
|
||||
// return [
|
||||
// `${usedTokens}/${totalTokens}`,
|
||||
// `${usedSerum3}/${totalSerum3}`,
|
||||
// `${usedPerps}/${totalPerps}`,
|
||||
// `${usedPerpOo}/${totalPerpOpenOrders}`,
|
||||
// ]
|
||||
// }, [mangoAccountAddress])
|
||||
|
||||
const isAccountFull = useMemo(() => {
|
||||
if (!mangoAccountAddress) return true
|
||||
return getIsAccountSizeFull()
|
||||
}, [mangoAccountAddress])
|
||||
|
||||
return {
|
||||
usedTokens,
|
||||
usedSerum3,
|
||||
usedPerps,
|
||||
usedPerpOo,
|
||||
totalTokens,
|
||||
totalSerum3,
|
||||
totalPerps,
|
||||
totalPerpOpenOrders,
|
||||
isAccountFull,
|
||||
}
|
||||
}
|
53
yarn.lock
53
yarn.lock
|
@ -12,14 +12,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@apocentre/alias-sampling/-/alias-sampling-0.5.3.tgz#897ff181b48ad7b2bcb4ecf29400214888244f08"
|
||||
integrity sha512-7UDWIIF9hIeJqfKXkNIzkVandlwLf1FWTSdrb9iXvOP8oF544JRXQjCbiTmCv2c9n44n/FIWtehhBfNuAx2CZA==
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.22.5", "@babel/runtime@^7.22.6":
|
||||
version "7.22.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438"
|
||||
integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.11"
|
||||
|
||||
"@babel/runtime@^7.21.0":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.22.6":
|
||||
version "7.22.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682"
|
||||
integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==
|
||||
|
@ -1009,31 +1002,24 @@
|
|||
jsbi "^3.1.5"
|
||||
sha.js "^2.4.11"
|
||||
|
||||
"@noble/curves@1.1.0", "@noble/curves@^1.1.0", "@noble/curves@~1.1.0":
|
||||
"@noble/curves@1.1.0", "@noble/curves@^1.0.0", "@noble/curves@^1.1.0", "@noble/curves@~1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
|
||||
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
|
||||
dependencies:
|
||||
"@noble/hashes" "1.3.1"
|
||||
|
||||
"@noble/curves@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932"
|
||||
integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==
|
||||
dependencies:
|
||||
"@noble/hashes" "1.3.0"
|
||||
|
||||
"@noble/ed25519@^1.6.1", "@noble/ed25519@^1.7.1":
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123"
|
||||
integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==
|
||||
|
||||
"@noble/hashes@1.3.0", "@noble/hashes@^1.1.3", "@noble/hashes@^1.3.0":
|
||||
"@noble/hashes@1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1"
|
||||
integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==
|
||||
|
||||
"@noble/hashes@1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1":
|
||||
"@noble/hashes@1.3.1", "@noble/hashes@^1.1.3", "@noble/hashes@^1.3.0", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
|
||||
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
|
||||
|
@ -1578,7 +1564,7 @@
|
|||
dependencies:
|
||||
"@solana/wallet-adapter-base" "^0.9.23"
|
||||
|
||||
"@solana/wallet-adapter-base@0.9.23", "@solana/wallet-adapter-base@^0.9.22", "@solana/wallet-adapter-base@^0.9.23":
|
||||
"@solana/wallet-adapter-base@0.9.23", "@solana/wallet-adapter-base@^0.9.17", "@solana/wallet-adapter-base@^0.9.2", "@solana/wallet-adapter-base@^0.9.22", "@solana/wallet-adapter-base@^0.9.23":
|
||||
version "0.9.23"
|
||||
resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.23.tgz#3b17c28afd44e173f44f658bf9700fd637e12a11"
|
||||
integrity sha512-apqMuYwFp1jFi55NxDfvXUX2x1T0Zh07MxhZ/nCCTGys5raSfYUh82zen2BLv8BSDj/JxZ2P/s7jrQZGrX8uAw==
|
||||
|
@ -1588,16 +1574,6 @@
|
|||
"@wallet-standard/features" "^1.0.3"
|
||||
eventemitter3 "^4.0.7"
|
||||
|
||||
"@solana/wallet-adapter-base@^0.9.17", "@solana/wallet-adapter-base@^0.9.2":
|
||||
version "0.9.22"
|
||||
resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.22.tgz#97812eaf6aebe01e5fe714326b3c9a0614ae6112"
|
||||
integrity sha512-xbLEZPGSJFvgTeldG9D55evhl7QK/3e/F7vhvcA97mEt1eieTgeKMnGlmmjs3yivI3/gtZNZeSk1XZLnhKcQvw==
|
||||
dependencies:
|
||||
"@solana/wallet-standard-features" "^1.0.1"
|
||||
"@wallet-standard/base" "^1.0.1"
|
||||
"@wallet-standard/features" "^1.0.3"
|
||||
eventemitter3 "^4.0.7"
|
||||
|
||||
"@solana/wallet-adapter-bitkeep@^0.3.19":
|
||||
version "0.3.19"
|
||||
resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-bitkeep/-/wallet-adapter-bitkeep-0.3.19.tgz#7d6a467fae791c5486b325473ed6b494958e3b5e"
|
||||
|
@ -1983,15 +1959,7 @@
|
|||
dependencies:
|
||||
"@wallet-standard/base" "^1.0.1"
|
||||
|
||||
"@solana/wallet-standard-features@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@solana/wallet-standard-features/-/wallet-standard-features-1.0.1.tgz#36270a646f74a80e51b9e21fb360edb64f840c68"
|
||||
integrity sha512-SUfx7KtBJ55XIj0qAhhVcC1I6MklAXqWFEz9hDHW+6YcJIyvfix/EilBhaBik1FJ2JT0zukpOfFv8zpuAbFRbw==
|
||||
dependencies:
|
||||
"@wallet-standard/base" "^1.0.1"
|
||||
"@wallet-standard/features" "^1.0.3"
|
||||
|
||||
"@solana/wallet-standard-features@^1.1.0":
|
||||
"@solana/wallet-standard-features@^1.0.1", "@solana/wallet-standard-features@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@solana/wallet-standard-features/-/wallet-standard-features-1.1.0.tgz#516d78626dd0802d299db49298e4ebbec3433940"
|
||||
integrity sha512-oVyygxfYkkF5INYL0GuD8GFmNO/wd45zNesIqGCFE6X66BYxmI6HmyzQJCcZTZ0BNsezlVg4t+3MCL5AhfFoGA==
|
||||
|
@ -7822,14 +7790,7 @@ semver@^6.3.0:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.3.2, semver@^7.3.5, semver@^7.3.7:
|
||||
version "7.3.8"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
|
||||
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.3.8:
|
||||
semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
|
|
Loading…
Reference in New Issue