feat: added account details and fund account button to empty accounts (#393)

This commit is contained in:
Linkie Link 2023-08-24 18:30:54 +02:00 committed by GitHub
parent 50f365044c
commit eeb49ba2ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 140 additions and 65 deletions

View File

@ -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

View File

@ -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'>

View File

@ -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}

View File

@ -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>
)

View File

@ -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}

View File

@ -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(() => {

View File

@ -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',