feat: added account details and fund account button to empty accounts (#393)
This commit is contained in:
parent
50f365044c
commit
eeb49ba2ab
@ -10,6 +10,8 @@ jest.mock('hooks/useHealthComputer', () =>
|
||||
health: 0,
|
||||
})),
|
||||
)
|
||||
// AccountBalancesTable component has wallet provider dependency, so we mock it
|
||||
jest.mock('components/Account/AccountBalancesTable', () => jest.fn(() => null))
|
||||
|
||||
const mockedUseCurrentAccount = useCurrentAccount as jest.Mock
|
||||
|
||||
|
@ -8,7 +8,10 @@ import {
|
||||
} from '@tanstack/react-table'
|
||||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
|
||||
import AccountFund from 'components/Account/AccountFund'
|
||||
import Button from 'components/Button'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||
@ -16,14 +19,17 @@ import Text from 'components/Text'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
import { convertLiquidityRateToAPR, convertToDisplayAmount, demagnify } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { convertAprToApy } from 'utils/parsers'
|
||||
import { getPage, getRoute } from 'utils/route'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
@ -62,7 +68,10 @@ export default function AccountBalancesTable(props: Props) {
|
||||
DEFAULT_SETTINGS.displayCurrency,
|
||||
)
|
||||
const { data: prices } = usePrices()
|
||||
|
||||
const currentAccount = useCurrentAccount()
|
||||
const navigate = useNavigate()
|
||||
const { pathname } = useLocation()
|
||||
const address = useStore((s) => s.address)
|
||||
const [sorting, setSorting] = React.useState<SortingState>([])
|
||||
const balanceData = React.useMemo<AccountBalanceRow[]>(() => {
|
||||
const accountDeposits = props.account?.deposits ?? []
|
||||
@ -172,6 +181,30 @@ export default function AccountBalancesTable(props: Props) {
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
})
|
||||
|
||||
if (balanceData.length === 0)
|
||||
return (
|
||||
<div className='w-full p-4'>
|
||||
<Button
|
||||
className='w-full'
|
||||
text='Fund this Account'
|
||||
color='tertiary'
|
||||
onClick={() => {
|
||||
if (currentAccount?.id !== props.account.id) {
|
||||
navigate(getRoute(getPage(pathname), address, props.account.id))
|
||||
}
|
||||
useStore.setState({
|
||||
focusComponent: {
|
||||
component: <AccountFund />,
|
||||
onClose: () => {
|
||||
useStore.setState({ getStartedModal: true })
|
||||
},
|
||||
},
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<table className='w-full'>
|
||||
<thead className='border-b border-white/5'>
|
||||
|
@ -85,7 +85,7 @@ export default function AccountComposition(props: Props) {
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='flex-wrap w-full p-4'>
|
||||
<div className='flex-wrap w-full p-4 pb-1'>
|
||||
<Item
|
||||
title='Total Position Value'
|
||||
current={balance}
|
||||
|
@ -1,10 +1,13 @@
|
||||
import classNames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import AccountBalancesTable from 'components/Account/AccountBalancesTable'
|
||||
import AccountComposition from 'components/Account/AccountComposition'
|
||||
import Card from 'components/Card'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import { Gauge } from 'components/Gauge'
|
||||
import { ArrowRight, Heart } from 'components/Icons'
|
||||
import { ArrowRight, ChevronLeft, ChevronRight, Heart } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||
@ -12,6 +15,7 @@ import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import {
|
||||
@ -35,18 +39,20 @@ interface Props {
|
||||
}
|
||||
|
||||
function AccountDetails(props: Props) {
|
||||
const { account } = props
|
||||
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||
const { health } = useHealthComputer(props.account)
|
||||
const [isExpanded, setIsExpanded] = useToggle()
|
||||
const { health } = useHealthComputer(account)
|
||||
const { health: updatedHealth } = useHealthComputer(updatedAccount)
|
||||
const { data: prices } = usePrices()
|
||||
const accountBalanceValue = useMemo(
|
||||
() => calculateAccountBalanceValue(updatedAccount ? updatedAccount : props.account, prices),
|
||||
[updatedAccount, props.account, prices],
|
||||
() => calculateAccountBalanceValue(updatedAccount ? updatedAccount : account, prices),
|
||||
[updatedAccount, account, prices],
|
||||
)
|
||||
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalanceValue)
|
||||
const leverage = useMemo(
|
||||
() => calculateAccountLeverage(updatedAccount ? updatedAccount : props.account, prices),
|
||||
[props.account, updatedAccount, prices],
|
||||
() => calculateAccountLeverage(updatedAccount ? updatedAccount : account, prices),
|
||||
[account, updatedAccount, prices],
|
||||
)
|
||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
||||
useBorrowMarketAssetsTableData()
|
||||
@ -63,76 +69,110 @@ function AccountDetails(props: Props) {
|
||||
const apr = useMemo(
|
||||
() =>
|
||||
calculateAccountApr(
|
||||
props.account,
|
||||
account,
|
||||
accountBalanceValue,
|
||||
borrowAssetsData,
|
||||
lendingAssetsData,
|
||||
prices,
|
||||
),
|
||||
[props.account, accountBalanceValue, borrowAssetsData, lendingAssetsData, prices],
|
||||
[account, accountBalanceValue, borrowAssetsData, lendingAssetsData, prices],
|
||||
)
|
||||
return (
|
||||
<div
|
||||
data-testid='account-details'
|
||||
className='w-16 border rounded-base border-white/20 bg-white/5 backdrop-blur-sticky'
|
||||
className={classNames(
|
||||
isExpanded ? 'right-6' : '-right-80',
|
||||
'w-100 flex items-start gap-6 absolute top-6',
|
||||
'transition-all duration-300',
|
||||
)}
|
||||
>
|
||||
<div className='flex flex-wrap justify-center w-full py-4'>
|
||||
<Gauge tooltip='Health Factor' percentage={health} icon={<Heart />} />
|
||||
<Text size='2xs' className='mb-0.5 mt-1 w-full text-center text-white/50'>
|
||||
Health
|
||||
</Text>
|
||||
<div className='flex'>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-xs'}
|
||||
amount={health}
|
||||
options={{ maxDecimals: 0, minDecimals: 0, suffix: '%' }}
|
||||
animate
|
||||
/>
|
||||
{updatedHealth > 0 && health !== updatedHealth && (
|
||||
<>
|
||||
<ArrowRight
|
||||
width={16}
|
||||
className={classNames(health > updatedHealth ? 'text-loss' : 'text-success')}
|
||||
/>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-xs'}
|
||||
amount={updatedHealth}
|
||||
options={{ maxDecimals: 0, minDecimals: 0, suffix: '%' }}
|
||||
animate
|
||||
/>
|
||||
</>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-wrap w-16 group/details relative',
|
||||
'border rounded-base border-white/20',
|
||||
'bg-white/5 backdrop-blur-sticky transition-colors duration-300',
|
||||
'hover:bg-white/20 hover:cursor-pointer ',
|
||||
)}
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute block opacity-0 top-1/2 transition-[opacity]',
|
||||
'group-hover/details:opacity-100 duration-300 delay-100',
|
||||
isExpanded ? '-right-4' : '-right-3',
|
||||
)}
|
||||
>
|
||||
{isExpanded ? <ChevronRight className='w-2' /> : <ChevronLeft className='w-2' />}
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full py-4 border-t border-white/20'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Leverage
|
||||
</Text>
|
||||
<Text size='2xs' className='text-center'>
|
||||
<div className='flex flex-wrap justify-center w-full py-4'>
|
||||
<Gauge tooltip='Health Factor' percentage={health} icon={<Heart />} />
|
||||
<Text size='2xs' className='mb-0.5 mt-1 w-full text-center text-white/50'>
|
||||
Health
|
||||
</Text>
|
||||
<div className='flex'>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-xs'}
|
||||
amount={health}
|
||||
options={{ maxDecimals: 0, minDecimals: 0, suffix: '%' }}
|
||||
animate
|
||||
/>
|
||||
{updatedHealth > 0 && health !== updatedHealth && (
|
||||
<>
|
||||
<ArrowRight
|
||||
width={16}
|
||||
className={classNames(health > updatedHealth ? 'text-loss' : 'text-success')}
|
||||
/>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-xs'}
|
||||
amount={updatedHealth}
|
||||
options={{ maxDecimals: 0, minDecimals: 0, suffix: '%' }}
|
||||
animate
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full py-4 border-t border-white/20'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Leverage
|
||||
</Text>
|
||||
<Text size='2xs' className='text-center'>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-2xs'}
|
||||
amount={leverage.toNumber()}
|
||||
options={{ maxDecimals: 2, minDecimals: 2, suffix: 'x' }}
|
||||
animate
|
||||
/>
|
||||
</Text>
|
||||
</div>
|
||||
<div className='w-full py-4 border-t border-white/20'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Net worth
|
||||
</Text>
|
||||
<DisplayCurrency coin={coin} className='w-full text-center truncate text-2xs ' />
|
||||
</div>
|
||||
<div className='w-full py-4 border-t border-white/20'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
APR
|
||||
</Text>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-2xs'}
|
||||
amount={leverage.toNumber()}
|
||||
options={{ maxDecimals: 2, minDecimals: 2, suffix: 'x' }}
|
||||
amount={apr.toNumber()}
|
||||
options={{ maxDecimals: 2, minDecimals: 2, suffix: '%' }}
|
||||
animate
|
||||
/>
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full py-4 border-t border-white/20'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Net worth
|
||||
</Text>
|
||||
<DisplayCurrency coin={coin} className='w-full text-center truncate text-2xs ' />
|
||||
</div>
|
||||
<div className='w-full py-4 border-t border-white/20'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
APR
|
||||
</Text>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-2xs'}
|
||||
amount={apr.toNumber()}
|
||||
options={{ maxDecimals: 2, minDecimals: 2, suffix: '%' }}
|
||||
animate
|
||||
/>
|
||||
<div className='flex w-80'>
|
||||
<Card className='w-full bg-white/5' title={`Account ${account.id}`}>
|
||||
<AccountComposition account={account} />
|
||||
<Text className='w-full px-4 py-2 bg-white/10 text-white/40'>Balances</Text>
|
||||
<AccountBalancesTable
|
||||
account={account}
|
||||
borrowingData={borrowAssetsData}
|
||||
lendingData={lendingAssetsData}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -48,7 +48,7 @@ function Content() {
|
||||
{account.map((account: Account, index: number) => (
|
||||
<Card className='w-full h-fit bg-white/5' title={`Account ${account.id}`} key={index}>
|
||||
<AccountComposition account={account} />
|
||||
<Text className='w-full px-4 py-2 mt-3 bg-white/10 text-white/40'>Balances</Text>
|
||||
<Text className='w-full px-4 py-2 bg-white/10 text-white/40'>Balances</Text>
|
||||
<AccountBalancesTable
|
||||
account={account}
|
||||
borrowingData={borrowAssetsData}
|
||||
|
@ -91,7 +91,7 @@ export default function FundAccount(props: Props) {
|
||||
if (assetToUpdateIdx > -1) {
|
||||
prevAssets[assetToUpdateIdx].amount = amount
|
||||
}
|
||||
setChange({ [isAutoLendEnabled ? "lends" : "deposits"]: prevAssets })
|
||||
setChange({ [isAutoLendEnabled ? 'lends' : 'deposits']: prevAssets })
|
||||
return prevAssets
|
||||
})
|
||||
},
|
||||
@ -99,7 +99,7 @@ export default function FundAccount(props: Props) {
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setChange({ [isAutoLendEnabled ? "lends" : "deposits"]: fundingAssets })
|
||||
setChange({ [isAutoLendEnabled ? 'lends' : 'deposits']: fundingAssets })
|
||||
}, [isAutoLendEnabled, fundingAssets, setChange])
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -48,7 +48,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
className={classNames(
|
||||
'lg:min-h-[calc(100vh-65px)]',
|
||||
'lg:mt-[65px]',
|
||||
'min-h-screen gap-6 p-6 w-full',
|
||||
'min-h-screen gap-6 p-6 w-full relative',
|
||||
focusComponent || isMobile
|
||||
? 'flex justify-center'
|
||||
: 'grid grid-cols-[auto_min-content] place-items-start',
|
||||
|
Loading…
Reference in New Issue
Block a user