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