Pre migration adjustments (#506)
* fix: added close button to accountDetails * fix: fixed the AccountList to load async * fix: fixed the heart size on the AccountStats * fix: added AccountDetails loading state * feat: added migration banner * fix: fixed tests
This commit is contained in:
parent
d0ce3eea45
commit
cfd7fb3073
@ -14,11 +14,15 @@ jest.mock('hooks/useHealthComputer', () =>
|
|||||||
jest.mock('components/Account/AccountBalancesTable', () => jest.fn(() => null))
|
jest.mock('components/Account/AccountBalancesTable', () => jest.fn(() => null))
|
||||||
|
|
||||||
const mockedUseCurrentAccount = useCurrentAccount as jest.Mock
|
const mockedUseCurrentAccount = useCurrentAccount as jest.Mock
|
||||||
|
const mockedAccount = { id: '1', deposits: [], lends: [], debts: [], vaults: [] }
|
||||||
|
jest.mock('hooks/useAccountId', () => jest.fn(() => '1'))
|
||||||
|
jest.mock('hooks/useAccounts', () => jest.fn(() => [mockedAccount]))
|
||||||
|
|
||||||
describe('<AccountDetails />', () => {
|
describe('<AccountDetails />', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
useStore.setState({
|
useStore.setState({
|
||||||
address: 'walletAddress',
|
address: 'walletAddress',
|
||||||
|
accounts: [mockedAccount],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -27,7 +31,7 @@ describe('<AccountDetails />', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('renders account details WHEN account is selected', () => {
|
it('renders account details WHEN account is selected', () => {
|
||||||
mockedUseCurrentAccount.mockReturnValue({ id: 1 })
|
mockedUseCurrentAccount.mockReturnValue(mockedAccount)
|
||||||
render(<AccountDetails />)
|
render(<AccountDetails />)
|
||||||
|
|
||||||
const container = screen.queryByTestId('account-details')
|
const container = screen.queryByTestId('account-details')
|
||||||
|
@ -13,6 +13,7 @@ const data: LendingMarketTableData = {
|
|||||||
marketLiquidityRate: 0.017,
|
marketLiquidityRate: 0.017,
|
||||||
marketLiquidationThreshold: 0.61,
|
marketLiquidationThreshold: 0.61,
|
||||||
marketMaxLtv: 0.59,
|
marketMaxLtv: 0.59,
|
||||||
|
borrowEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.mock('hooks/useDisplayCurrencyPrice', () => () => {
|
jest.mock('hooks/useDisplayCurrencyPrice', () => () => {
|
||||||
|
@ -28,6 +28,8 @@ const mockedDepositedVault: DepositedVault = {
|
|||||||
values: {
|
values: {
|
||||||
primary: BN_ZERO,
|
primary: BN_ZERO,
|
||||||
secondary: BN_ZERO,
|
secondary: BN_ZERO,
|
||||||
|
unlocked: BN_ZERO,
|
||||||
|
unlocking: BN_ZERO,
|
||||||
},
|
},
|
||||||
cap: {
|
cap: {
|
||||||
denom: 'mock',
|
denom: 'mock',
|
||||||
|
36
src/components/Account/AccountDetails/Skeleton.tsx
Normal file
36
src/components/Account/AccountDetails/Skeleton.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { HealthGauge } from 'components/HealthGauge'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
|
||||||
|
export default function Skeleton() {
|
||||||
|
return (
|
||||||
|
<div className='absolute flex items-start w-16 gap-4 right-4 top-6 opacity-90'>
|
||||||
|
<div className='relative flex flex-wrap w-16 border min-w-16 group rounded-base border-white/20'>
|
||||||
|
<div className='flex flex-wrap justify-center w-full py-4'>
|
||||||
|
<HealthGauge health={0} />
|
||||||
|
<Text size='2xs' className='mb-0.5 mt-1 w-full text-center text-white/50'>
|
||||||
|
Account Health
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-wrap justify-center w-full py-4 border-t border-white/20'>
|
||||||
|
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50 whitespace-nowrap'>
|
||||||
|
Net worth
|
||||||
|
</Text>
|
||||||
|
<Loading className='w-10 h-3 mt-1' />
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-wrap justify-center 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>
|
||||||
|
<Loading className='w-10 h-3 mt-1' />
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-wrap justify-center 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>
|
||||||
|
<Loading className='w-10 h-3 mt-1' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import AccountBalancesTable from 'components/Account/AccountBalancesTable'
|
import AccountBalancesTable from 'components/Account/AccountBalancesTable'
|
||||||
import AccountComposition from 'components/Account/AccountComposition'
|
import AccountComposition from 'components/Account/AccountComposition'
|
||||||
import AccountDetailsLeverage from 'components/Account/AccountDetails/AccountDetailsLeverage'
|
import AccountDetailsLeverage from 'components/Account/AccountDetails/AccountDetailsLeverage'
|
||||||
|
import Skeleton from 'components/Account/AccountDetails/Skeleton'
|
||||||
|
import EscButton from 'components/Button/EscButton'
|
||||||
import { glowElement } from 'components/Button/utils'
|
import { glowElement } from 'components/Button/utils'
|
||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
@ -14,6 +16,8 @@ import Text from 'components/Text'
|
|||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
|
import useAccountId from 'hooks/useAccountId'
|
||||||
|
import useAccounts from 'hooks/useAccounts'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
@ -29,11 +33,15 @@ import {
|
|||||||
} from 'utils/accounts'
|
} from 'utils/accounts'
|
||||||
|
|
||||||
export default function AccountDetailsController() {
|
export default function AccountDetailsController() {
|
||||||
const account = useCurrentAccount()
|
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
const { isLoading } = useAccounts(address)
|
||||||
|
const accountId = useAccountId()
|
||||||
|
const account = useCurrentAccount()
|
||||||
const focusComponent = useStore((s) => s.focusComponent)
|
const focusComponent = useStore((s) => s.focusComponent)
|
||||||
|
|
||||||
if (!account || !address || focusComponent) return null
|
if (!address || focusComponent) return null
|
||||||
|
|
||||||
|
if ((isLoading && accountId && !focusComponent) || !account) return <Skeleton />
|
||||||
|
|
||||||
return <AccountDetails account={account} />
|
return <AccountDetails account={account} />
|
||||||
}
|
}
|
||||||
@ -81,6 +89,19 @@ function AccountDetails(props: Props) {
|
|||||||
[account, borrowAssetsData, lendingAssetsData, prices],
|
[account, borrowAssetsData, lendingAssetsData, prices],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function AccountDetailsHeader() {
|
||||||
|
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex items-center justify-between w-full p-4 bg-white/10 '>
|
||||||
|
<Text size='lg' className='flex items-center flex-grow font-semibold'>
|
||||||
|
{`Credit Account ${account.id}`}
|
||||||
|
</Text>
|
||||||
|
<EscButton onClick={onClose} hideText className='w-6 h-6' />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-testid='account-details'
|
data-testid='account-details'
|
||||||
@ -146,7 +167,7 @@ function AccountDetails(props: Props) {
|
|||||||
{glowElement(!reduceMotion)}
|
{glowElement(!reduceMotion)}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex w-90 backdrop-blur-sticky'>
|
<div className='flex w-90 backdrop-blur-sticky'>
|
||||||
<Card className='w-full bg-white/5' title={`Credit Account ${account.id}`}>
|
<Card className='w-full bg-white/5' title={<AccountDetailsHeader />}>
|
||||||
<AccountComposition account={account} />
|
<AccountComposition account={account} />
|
||||||
<Text className='w-full px-4 py-2 text-white bg-white/10'>Balances</Text>
|
<Text className='w-full px-4 py-2 text-white bg-white/10'>Balances</Text>
|
||||||
<AccountBalancesTable
|
<AccountBalancesTable
|
||||||
|
@ -1,146 +0,0 @@
|
|||||||
import classNames from 'classnames'
|
|
||||||
import { useCallback, useEffect } from 'react'
|
|
||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
|
||||||
|
|
||||||
import AccountFundFullPage from 'components/Account/AccountFund/AccountFundFullPage'
|
|
||||||
import AccountStats from 'components/Account/AccountStats'
|
|
||||||
import Button from 'components/Button'
|
|
||||||
import Card from 'components/Card'
|
|
||||||
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/Icons'
|
|
||||||
import Radio from 'components/Radio'
|
|
||||||
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
|
||||||
import Text from 'components/Text'
|
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
|
||||||
import usePrices from 'hooks/usePrices'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { calculateAccountBalanceValue } from 'utils/accounts'
|
|
||||||
import { getPage, getRoute } from 'utils/route'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
accounts: Account[]
|
|
||||||
setShowMenu: (show: boolean) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const accountCardHeaderClasses = classNames(
|
|
||||||
'flex w-full items-center justify-between bg-white/20 px-4 py-2.5 text-white/70',
|
|
||||||
'border border-transparent border-b-white/20',
|
|
||||||
'group-hover/account:bg-white/30',
|
|
||||||
)
|
|
||||||
|
|
||||||
export default function AccountList(props: Props) {
|
|
||||||
const { accounts, setShowMenu } = props
|
|
||||||
const navigate = useNavigate()
|
|
||||||
const { pathname } = useLocation()
|
|
||||||
const { address } = useParams()
|
|
||||||
const { data: prices } = usePrices()
|
|
||||||
const account = useCurrentAccount()
|
|
||||||
const accountId = account?.id
|
|
||||||
|
|
||||||
const deleteAccountHandler = useCallback(() => {
|
|
||||||
if (!account) return
|
|
||||||
useStore.setState({ accountDeleteModal: account })
|
|
||||||
}, [account])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!accountId) return
|
|
||||||
const element = document.getElementById(`account-${accountId}`)
|
|
||||||
if (element) {
|
|
||||||
element.scrollIntoView({ behavior: 'smooth' })
|
|
||||||
}
|
|
||||||
}, [accountId])
|
|
||||||
|
|
||||||
if (!accounts?.length) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='flex flex-wrap w-full p-4'>
|
|
||||||
{accounts.map((account) => {
|
|
||||||
const positionBalance = calculateAccountBalanceValue(account, prices)
|
|
||||||
const isActive = accountId === account.id
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={account.id} id={`account-${account.id}`} className='w-full pt-4'>
|
|
||||||
<Card
|
|
||||||
id={`account-${account.id}`}
|
|
||||||
key={account.id}
|
|
||||||
className={classNames('w-full', !isActive && 'group/account hover:cursor-pointer')}
|
|
||||||
contentClassName='bg-white/10 group-hover/account:bg-white/20'
|
|
||||||
onClick={() => {
|
|
||||||
if (isActive) return
|
|
||||||
useStore.setState({ accountDeleteModal: null })
|
|
||||||
navigate(getRoute(getPage(pathname), address, account.id))
|
|
||||||
}}
|
|
||||||
title={
|
|
||||||
<div className={accountCardHeaderClasses} role={!isActive ? 'button' : undefined}>
|
|
||||||
<Text size='xs' className='flex flex-1'>
|
|
||||||
Credit Account {account.id}
|
|
||||||
</Text>
|
|
||||||
<Radio active={isActive} className='group-hover/account:opacity-100' />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{isActive ? (
|
|
||||||
<>
|
|
||||||
<div className='w-full p-4 border border-transparent border-b-white/20'>
|
|
||||||
<AccountStats account={account} />
|
|
||||||
</div>
|
|
||||||
<div className='grid grid-flow-row grid-cols-2 gap-4 p-4'>
|
|
||||||
<Button
|
|
||||||
className='w-full'
|
|
||||||
text='Fund'
|
|
||||||
color='tertiary'
|
|
||||||
leftIcon={<ArrowUpLine />}
|
|
||||||
onClick={() => {
|
|
||||||
setShowMenu(false)
|
|
||||||
if (positionBalance.isLessThanOrEqualTo(0)) {
|
|
||||||
useStore.setState({
|
|
||||||
focusComponent: {
|
|
||||||
component: <AccountFundFullPage />,
|
|
||||||
onClose: () => {
|
|
||||||
useStore.setState({ getStartedModal: true })
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
useStore.setState({ fundAndWithdrawModal: 'fund' })
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
className='w-full'
|
|
||||||
color='tertiary'
|
|
||||||
leftIcon={<ArrowDownLine />}
|
|
||||||
text='Withdraw'
|
|
||||||
onClick={() => {
|
|
||||||
setShowMenu(false)
|
|
||||||
useStore.setState({ fundAndWithdrawModal: 'withdraw' })
|
|
||||||
}}
|
|
||||||
disabled={positionBalance.isLessThanOrEqualTo(0)}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
className='w-full col-span-2'
|
|
||||||
color='tertiary'
|
|
||||||
leftIcon={<TrashBin />}
|
|
||||||
text='Delete'
|
|
||||||
onClick={() => {
|
|
||||||
setShowMenu(false)
|
|
||||||
deleteAccountHandler()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SwitchAutoLend
|
|
||||||
className='col-span-2 pt-4 border border-transparent border-t-white/10'
|
|
||||||
accountId={account.id}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className='w-full p-4'>
|
|
||||||
<AccountStats account={account} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
112
src/components/Account/AccountList/AccountStats.tsx
Normal file
112
src/components/Account/AccountList/AccountStats.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
|
import AccountFundFullPage from 'components/Account/AccountFund/AccountFundFullPage'
|
||||||
|
import Skeleton from 'components/Account/AccountList/Skeleton'
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/Icons'
|
||||||
|
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
||||||
|
import useAccount from 'hooks/useAccount'
|
||||||
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
|
import usePrices from 'hooks/usePrices'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { calculateAccountApr, calculateAccountBalanceValue } from 'utils/accounts'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
accountId: string
|
||||||
|
isActive?: boolean
|
||||||
|
setShowMenu?: (show: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AccountStats(props: Props) {
|
||||||
|
const { accountId, isActive, setShowMenu } = props
|
||||||
|
const { data: account } = useAccount(accountId)
|
||||||
|
const { data: prices } = usePrices()
|
||||||
|
const positionBalance = useMemo(
|
||||||
|
() => (!account ? null : calculateAccountBalanceValue(account, prices)),
|
||||||
|
[account, prices],
|
||||||
|
)
|
||||||
|
const { health } = useHealthComputer(account)
|
||||||
|
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
||||||
|
useBorrowMarketAssetsTableData()
|
||||||
|
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||||
|
useLendingMarketAssetsTableData()
|
||||||
|
const borrowAssetsData = useMemo(
|
||||||
|
() => [...borrowAvailableAssets, ...accountBorrowedAssets],
|
||||||
|
[borrowAvailableAssets, accountBorrowedAssets],
|
||||||
|
)
|
||||||
|
const lendingAssetsData = useMemo(
|
||||||
|
() => [...lendingAvailableAssets, ...accountLentAssets],
|
||||||
|
[lendingAvailableAssets, accountLentAssets],
|
||||||
|
)
|
||||||
|
const apr = useMemo(
|
||||||
|
() =>
|
||||||
|
!account ? null : calculateAccountApr(account, borrowAssetsData, lendingAssetsData, prices),
|
||||||
|
[account, borrowAssetsData, lendingAssetsData, prices],
|
||||||
|
)
|
||||||
|
|
||||||
|
const deleteAccountHandler = useCallback(() => {
|
||||||
|
if (!account) return
|
||||||
|
useStore.setState({ accountDeleteModal: account })
|
||||||
|
}, [account])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='w-full p-4'>
|
||||||
|
<Skeleton health={!account ? 0 : health} positionBalance={positionBalance} apr={apr} />
|
||||||
|
{isActive && setShowMenu && (
|
||||||
|
<div className='grid grid-flow-row grid-cols-2 gap-4 pt-4'>
|
||||||
|
<Button
|
||||||
|
className='w-full'
|
||||||
|
text='Fund'
|
||||||
|
color='tertiary'
|
||||||
|
leftIcon={<ArrowUpLine />}
|
||||||
|
disabled={!positionBalance}
|
||||||
|
onClick={() => {
|
||||||
|
setShowMenu(false)
|
||||||
|
if (!positionBalance) return
|
||||||
|
if (positionBalance.isLessThanOrEqualTo(0)) {
|
||||||
|
useStore.setState({
|
||||||
|
focusComponent: {
|
||||||
|
component: <AccountFundFullPage />,
|
||||||
|
onClose: () => {
|
||||||
|
useStore.setState({ getStartedModal: true })
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
useStore.setState({ fundAndWithdrawModal: 'fund' })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className='w-full'
|
||||||
|
color='tertiary'
|
||||||
|
leftIcon={<ArrowDownLine />}
|
||||||
|
text='Withdraw'
|
||||||
|
onClick={() => {
|
||||||
|
setShowMenu(false)
|
||||||
|
useStore.setState({ fundAndWithdrawModal: 'withdraw' })
|
||||||
|
}}
|
||||||
|
disabled={!positionBalance || positionBalance.isLessThanOrEqualTo(0)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className='w-full col-span-2'
|
||||||
|
color='tertiary'
|
||||||
|
leftIcon={<TrashBin />}
|
||||||
|
text='Delete'
|
||||||
|
disabled={!account}
|
||||||
|
onClick={() => {
|
||||||
|
setShowMenu(false)
|
||||||
|
deleteAccountHandler()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SwitchAutoLend
|
||||||
|
className='col-span-2 pt-4 border-t border-white/10'
|
||||||
|
accountId={accountId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
52
src/components/Account/AccountList/Skeleton.tsx
Normal file
52
src/components/Account/AccountList/Skeleton.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import HealthBar from 'components/Account/HealthBar'
|
||||||
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import { ArrowChartLineUp, Heart } from 'components/Icons'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
health: number
|
||||||
|
positionBalance: BigNumber | null
|
||||||
|
apr: BigNumber | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Skeleton(props: Props) {
|
||||||
|
const { positionBalance, apr, health } = props
|
||||||
|
return (
|
||||||
|
<div className='flex flex-wrap w-full'>
|
||||||
|
{positionBalance ? (
|
||||||
|
<DisplayCurrency
|
||||||
|
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, positionBalance)}
|
||||||
|
className='w-full text-xl'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Loading className='h-6 mt-1 w-30' />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className='flex items-center justify-between w-full mt-1'>
|
||||||
|
<div className='flex items-center'>
|
||||||
|
<ArrowChartLineUp className='w-4 mr-1' />
|
||||||
|
{apr ? (
|
||||||
|
<FormattedNumber
|
||||||
|
className='text-xs text-white/70'
|
||||||
|
amount={apr.toNumber()}
|
||||||
|
options={{ prefix: 'APR: ', suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Loading className='h-4 w-18' />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center gap-1'>
|
||||||
|
<Heart className='w-4' />
|
||||||
|
<Text size='xs' className='w-auto mr-1 text-white/70'>
|
||||||
|
Health
|
||||||
|
</Text>
|
||||||
|
<HealthBar health={health} className='w-[92px] h-0.5' hasLabel />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
75
src/components/Account/AccountList/index.tsx
Normal file
75
src/components/Account/AccountList/index.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import AccountStats from 'components/Account/AccountList/AccountStats'
|
||||||
|
import Card from 'components/Card'
|
||||||
|
import Radio from 'components/Radio'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import useAccountId from 'hooks/useAccountId'
|
||||||
|
import useAccountIds from 'hooks/useAccountIds'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
setShowMenu: (show: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountCardHeaderClasses = classNames(
|
||||||
|
'flex w-full items-center justify-between bg-white/20 px-4 py-2.5 text-white/70',
|
||||||
|
'border border-transparent border-b-white/20',
|
||||||
|
'group-hover/account:bg-white/30',
|
||||||
|
)
|
||||||
|
|
||||||
|
export default function AccountList(props: Props) {
|
||||||
|
const { setShowMenu } = props
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
const currentAccountId = useAccountId()
|
||||||
|
const { address } = useParams()
|
||||||
|
const { data: accountIds } = useAccountIds(address)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!currentAccountId) return
|
||||||
|
const element = document.getElementById(`account-${currentAccountId}`)
|
||||||
|
if (element) {
|
||||||
|
element.scrollIntoView({ behavior: 'smooth' })
|
||||||
|
}
|
||||||
|
}, [currentAccountId])
|
||||||
|
|
||||||
|
if (!accountIds?.length) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex flex-wrap w-full p-4'>
|
||||||
|
{accountIds.map((accountId) => {
|
||||||
|
const isActive = currentAccountId === accountId
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={accountId} id={`account-${accountId}`} className='w-full pt-4'>
|
||||||
|
<Card
|
||||||
|
id={`account-${accountId}`}
|
||||||
|
key={accountId}
|
||||||
|
className={classNames('w-full', !isActive && 'group/account hover:cursor-pointer')}
|
||||||
|
contentClassName='bg-white/10 group-hover/account:bg-white/20'
|
||||||
|
onClick={() => {
|
||||||
|
if (isActive) return
|
||||||
|
useStore.setState({ accountDeleteModal: null })
|
||||||
|
navigate(getRoute(getPage(pathname), address, accountId))
|
||||||
|
}}
|
||||||
|
title={
|
||||||
|
<div className={accountCardHeaderClasses} role={!isActive ? 'button' : undefined}>
|
||||||
|
<Text size='xs' className='flex flex-1'>
|
||||||
|
Credit Account {accountId}
|
||||||
|
</Text>
|
||||||
|
<Radio active={isActive} className='group-hover/account:opacity-100' />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AccountStats accountId={accountId} isActive={isActive} setShowMenu={setShowMenu} />
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -2,15 +2,15 @@ import { Suspense } from 'react'
|
|||||||
|
|
||||||
import AccountMenuContent from 'components/Account/AccountMenuContent'
|
import AccountMenuContent from 'components/Account/AccountMenuContent'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
import useAccounts from 'hooks/useAccounts'
|
import useAccountIds from 'hooks/useAccountIds'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
function Content() {
|
function Content() {
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
const { data: accounts, isLoading } = useAccounts(address)
|
const { data: accountIds, isLoading } = useAccountIds(address)
|
||||||
if (isLoading) return <Loading className='h-8 w-35' />
|
if (isLoading) return <Loading className='h-8 w-35' />
|
||||||
if (!accounts) return null
|
if (!accountIds) return null
|
||||||
return <AccountMenuContent accounts={accounts} />
|
return <AccountMenuContent />
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AccountMenu() {
|
export default function AccountMenu() {
|
||||||
|
@ -6,7 +6,6 @@ import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
|||||||
import AccountFund from 'components/Account/AccountFund/AccountFundFullPage'
|
import AccountFund from 'components/Account/AccountFund/AccountFundFullPage'
|
||||||
import AccountList from 'components/Account/AccountList'
|
import AccountList from 'components/Account/AccountList'
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import { CircularProgress } from 'components/CircularProgress'
|
|
||||||
import { Account, Plus, PlusCircled } from 'components/Icons'
|
import { Account, Plus, PlusCircled } from 'components/Icons'
|
||||||
import Overlay from 'components/Overlay'
|
import Overlay from 'components/Overlay'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
@ -14,6 +13,7 @@ import WalletBridges from 'components/Wallet/WalletBridges'
|
|||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LEND_ASSETS_KEY } from 'constants/localStore'
|
import { LEND_ASSETS_KEY } from 'constants/localStore'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
|
import useAccountIds from 'hooks/useAccountIds'
|
||||||
import useAutoLend from 'hooks/useAutoLend'
|
import useAutoLend from 'hooks/useAutoLend'
|
||||||
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
@ -27,14 +27,11 @@ import { getPage, getRoute } from 'utils/route'
|
|||||||
const menuClasses = 'absolute isolate flex w-full flex-wrap scrollbar-hide'
|
const menuClasses = 'absolute isolate flex w-full flex-wrap scrollbar-hide'
|
||||||
const ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
|
const ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
|
||||||
|
|
||||||
interface Props {
|
export default function AccountMenuContent() {
|
||||||
accounts: Account[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AccountMenuContent(props: Props) {
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const { address } = useParams()
|
const { address } = useParams()
|
||||||
|
const { data: accountIds } = useAccountIds(address)
|
||||||
const accountId = useAccountId()
|
const accountId = useAccountId()
|
||||||
|
|
||||||
const createAccount = useStore((s) => s.createAccount)
|
const createAccount = useStore((s) => s.createAccount)
|
||||||
@ -45,13 +42,9 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
const [lendAssets] = useLocalStorage<boolean>(LEND_ASSETS_KEY, DEFAULT_SETTINGS.lendAssets)
|
const [lendAssets] = useLocalStorage<boolean>(LEND_ASSETS_KEY, DEFAULT_SETTINGS.lendAssets)
|
||||||
const { enableAutoLendAccountId } = useAutoLend()
|
const { enableAutoLendAccountId } = useAutoLend()
|
||||||
|
|
||||||
const hasCreditAccounts = !!props.accounts.length
|
const hasCreditAccounts = !!accountIds.length
|
||||||
const isAccountSelected = isNumber(accountId)
|
const isAccountSelected = isNumber(accountId)
|
||||||
|
|
||||||
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
|
||||||
|
|
||||||
const isLoadingAccount = isAccountSelected && selectedAccountDetails?.id !== accountId
|
|
||||||
|
|
||||||
const checkHasFunds = useCallback(() => {
|
const checkHasFunds = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
transactionFeeCoinBalance &&
|
transactionFeeCoinBalance &&
|
||||||
@ -149,14 +142,7 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
'top-[54px] h-[calc(100%-54px)] items-start',
|
'top-[54px] h-[calc(100%-54px)] items-start',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{isAccountSelected && isLoadingAccount && (
|
{hasCreditAccounts && <AccountList setShowMenu={setShowMenu} />}
|
||||||
<div className='flex items-center justify-center w-full h-full p-4'>
|
|
||||||
<CircularProgress size={40} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{hasCreditAccounts && !isLoadingAccount && (
|
|
||||||
<AccountList accounts={props.accounts} setShowMenu={setShowMenu} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
import { useMemo } from 'react'
|
|
||||||
|
|
||||||
import HealthBar from 'components/Account/HealthBar'
|
|
||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
|
||||||
import { ArrowChartLineUp, Heart } from 'components/Icons'
|
|
||||||
import Text from 'components/Text'
|
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
|
||||||
import usePrices from 'hooks/usePrices'
|
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
|
||||||
import { calculateAccountApr, calculateAccountBalanceValue } from 'utils/accounts'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
account: Account
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AccountStats(props: Props) {
|
|
||||||
const { data: prices } = usePrices()
|
|
||||||
const positionBalance = useMemo(
|
|
||||||
() => calculateAccountBalanceValue(props.account, prices),
|
|
||||||
[props.account, prices],
|
|
||||||
)
|
|
||||||
const { health } = useHealthComputer(props.account)
|
|
||||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
|
||||||
useBorrowMarketAssetsTableData()
|
|
||||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
|
||||||
useLendingMarketAssetsTableData()
|
|
||||||
const borrowAssetsData = useMemo(
|
|
||||||
() => [...borrowAvailableAssets, ...accountBorrowedAssets],
|
|
||||||
[borrowAvailableAssets, accountBorrowedAssets],
|
|
||||||
)
|
|
||||||
const lendingAssetsData = useMemo(
|
|
||||||
() => [...lendingAvailableAssets, ...accountLentAssets],
|
|
||||||
[lendingAvailableAssets, accountLentAssets],
|
|
||||||
)
|
|
||||||
const apr = useMemo(
|
|
||||||
() => calculateAccountApr(props.account, borrowAssetsData, lendingAssetsData, prices),
|
|
||||||
[props.account, borrowAssetsData, lendingAssetsData, prices],
|
|
||||||
)
|
|
||||||
return (
|
|
||||||
<div className='flex flex-wrap w-full'>
|
|
||||||
<DisplayCurrency
|
|
||||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, positionBalance)}
|
|
||||||
className='w-full text-xl'
|
|
||||||
/>
|
|
||||||
<div className='flex items-center justify-between w-full mt-1'>
|
|
||||||
<div className='flex items-center'>
|
|
||||||
<ArrowChartLineUp className='w-4 mr-1' />
|
|
||||||
<FormattedNumber
|
|
||||||
className='text-xs text-white/70'
|
|
||||||
amount={apr.toNumber()}
|
|
||||||
options={{ prefix: 'APR: ', suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='flex items-center gap-1'>
|
|
||||||
<Heart className='w-3' />
|
|
||||||
<Text size='xs' className='w-auto mr-1 text-white/70'>
|
|
||||||
Health
|
|
||||||
</Text>
|
|
||||||
<HealthBar health={health} className='w-[92px] h-0.5' hasLabel />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -6,6 +6,8 @@ import Text from 'components/Text'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
enableKeyPress?: boolean
|
enableKeyPress?: boolean
|
||||||
|
hideText?: boolean
|
||||||
|
className?: string
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,10 +36,10 @@ export default function EscButton(props: Props) {
|
|||||||
leftIcon={<Cross />}
|
leftIcon={<Cross />}
|
||||||
iconClassName='w-3'
|
iconClassName='w-3'
|
||||||
color='tertiary'
|
color='tertiary'
|
||||||
className='h-3 w-13'
|
className={props.className ? props.className : 'h-3 w-13'}
|
||||||
size='xs'
|
size='xs'
|
||||||
>
|
>
|
||||||
<Text size='2xs'>ESC</Text>
|
{!props.hideText && <Text size='2xs'>ESC</Text>}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,10 @@ export const HealthGauge = ({ diameter = 40, health = 0, updatedHealth = 0 }: Pr
|
|||||||
[color, updatedColor, isUpdated, isIncrease],
|
[color, updatedColor, isUpdated, isIncrease],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const tooltipContent = health === 0 ? 'loading...' : isUpdated ? updatedLabel : label
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip type='info' content={isUpdated ? updatedLabel : label}>
|
<Tooltip type='info' content={tooltipContent}>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'relative grid place-items-center',
|
'relative grid place-items-center',
|
||||||
|
43
src/components/MigrationBanner.tsx
Normal file
43
src/components/MigrationBanner.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import Card from 'components/Card'
|
||||||
|
import { Cross, ExclamationMarkCircled } from 'components/Icons'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import { TextLink } from 'components/TextLink'
|
||||||
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
|
import { MIGRATION_BANNER_KEY } from 'constants/localStore'
|
||||||
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
|
|
||||||
|
export default function MigrationBanner() {
|
||||||
|
const [migrationBanner, setMigrationBanner] = useLocalStorage<boolean>(
|
||||||
|
MIGRATION_BANNER_KEY,
|
||||||
|
DEFAULT_SETTINGS.migrationBanner,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!migrationBanner) return null
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
className='relative w-full bg-info-bg/20 text-info'
|
||||||
|
contentClassName='flex w-full gap-2 px-4 py-3 items-center'
|
||||||
|
>
|
||||||
|
<div className='flex w-6 h-6 p-1 text-white rounded bg-info'>
|
||||||
|
<ExclamationMarkCircled />
|
||||||
|
</div>
|
||||||
|
<Text className='flex flex-grow' size='sm'>
|
||||||
|
If you have funds on{' '}
|
||||||
|
<TextLink
|
||||||
|
href='https://osmosis.marsprotocol.io'
|
||||||
|
externalLink
|
||||||
|
className='mx-1 text-white no-underline hover:underline'
|
||||||
|
>
|
||||||
|
Mars v1,
|
||||||
|
</TextLink>
|
||||||
|
please withdraw them and deposit them on Mars v2 to migrate.
|
||||||
|
</Text>
|
||||||
|
<div
|
||||||
|
className='absolute right-0 flex items-center h-full px-4 w-11 opacity-80 hover:cursor-pointer hover:opacity-100'
|
||||||
|
onClick={() => setMigrationBanner(false)}
|
||||||
|
>
|
||||||
|
<Cross className='w-3 h-3' />
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
@ -3,22 +3,21 @@ import React from 'react'
|
|||||||
import HealthBar from 'components/Account/HealthBar'
|
import HealthBar from 'components/Account/HealthBar'
|
||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
import { Heart } from 'components/Icons'
|
import { Heart } from 'components/Icons'
|
||||||
import Loading from 'components/Loading'
|
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
stats: { title: React.ReactNode; sub: string }[]
|
stats: { title: React.ReactNode; sub: string }[]
|
||||||
health: number
|
health: number
|
||||||
|
accountId: string
|
||||||
isCurrent?: boolean
|
isCurrent?: boolean
|
||||||
accountId?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Skeleton(props: Props) {
|
export default function Skeleton(props: Props) {
|
||||||
return (
|
return (
|
||||||
<Card className='bg-white/5 p-4'>
|
<Card className='p-4 bg-white/5'>
|
||||||
<div className='flex justify-between items-center'>
|
<div className='flex items-center justify-between'>
|
||||||
<Text>Credit account {props.accountId || <Loading />}</Text>
|
<Text>Credit account {props.accountId}</Text>
|
||||||
<Text size='xs' className='text-white/60'>
|
<Text size='xs' className='text-white/60'>
|
||||||
{props.isCurrent && '(current)'}
|
{props.isCurrent && '(current)'}
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -4,8 +4,6 @@ import { ReactNode } from 'react'
|
|||||||
import { TooltipArrow } from 'components/Icons'
|
import { TooltipArrow } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
|
|
||||||
import { TooltipType } from '.'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
content: ReactNode | string
|
content: ReactNode | string
|
||||||
type: TooltipType
|
type: TooltipType
|
||||||
|
@ -18,8 +18,6 @@ interface Props {
|
|||||||
underline?: boolean
|
underline?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TooltipType = 'info' | 'warning' | 'error'
|
|
||||||
|
|
||||||
export const Tooltip = (props: Props) => {
|
export const Tooltip = (props: Props) => {
|
||||||
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
|
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import { Check, Copy, ExternalLink, Osmo } from 'components/Icons'
|
|||||||
import Overlay from 'components/Overlay'
|
import Overlay from 'components/Overlay'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import RecentTransactions from 'components/Wallet/RecentTransactions'
|
import RecentTransactions from 'components/Wallet/RecentTransactions'
|
||||||
|
import WalletSelect from 'components/Wallet/WalletSelect'
|
||||||
import { CHAINS } from 'constants/chains'
|
import { CHAINS } from 'constants/chains'
|
||||||
import { ENV } from 'constants/env'
|
import { ENV } from 'constants/env'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
@ -25,8 +26,6 @@ import { getBaseAsset, getEnabledMarketAssets } from 'utils/assets'
|
|||||||
import { truncate } from 'utils/formatters'
|
import { truncate } from 'utils/formatters'
|
||||||
import { getPage, getRoute } from 'utils/route'
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
import WalletSelect from './WalletSelect'
|
|
||||||
|
|
||||||
export default function WalletConnectedButton() {
|
export default function WalletConnectedButton() {
|
||||||
// ---------------
|
// ---------------
|
||||||
// EXTERNAL HOOKS
|
// EXTERNAL HOOKS
|
||||||
|
@ -8,4 +8,5 @@ export const DEFAULT_SETTINGS: Settings = {
|
|||||||
displayCurrency: ORACLE_DENOM,
|
displayCurrency: ORACLE_DENOM,
|
||||||
slippage: 0.02,
|
slippage: 0.02,
|
||||||
tutorial: true,
|
tutorial: true,
|
||||||
|
migrationBanner: true,
|
||||||
}
|
}
|
||||||
|
@ -8,3 +8,4 @@ export const SLIPPAGE_KEY = 'slippage'
|
|||||||
export const TERMS_OF_SERVICE_KEY = 'termsOfService'
|
export const TERMS_OF_SERVICE_KEY = 'termsOfService'
|
||||||
export const TUTORIAL_KEY = 'tutorial'
|
export const TUTORIAL_KEY = 'tutorial'
|
||||||
export const TRANSACTIONS_KEY = 'transactions'
|
export const TRANSACTIONS_KEY = 'transactions'
|
||||||
|
export const MIGRATION_BANNER_KEY = 'migrationBanner'
|
||||||
|
@ -84,7 +84,7 @@ export default function useDepositVault(props: Props): {
|
|||||||
amount: 'account_balance',
|
amount: 'account_balance',
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
}, [isAutoLend, props.borrowings, props.deposits, props.reclaims])
|
}, [isAutoLend, props.vault.denoms.primary, props.vault.denoms.secondary])
|
||||||
|
|
||||||
const actions = useMemo(() => {
|
const actions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
|
import { SLIPPAGE_KEY } from 'constants/localStore'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import {
|
import {
|
||||||
addCoins,
|
addCoins,
|
||||||
@ -15,10 +18,6 @@ import { cloneAccount } from 'utils/accounts'
|
|||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { getValueFromBNCoins } from 'utils/helpers'
|
import { getValueFromBNCoins } from 'utils/helpers'
|
||||||
|
|
||||||
import { DEFAULT_SETTINGS } from '../../constants/defaultSettings'
|
|
||||||
import { SLIPPAGE_KEY } from '../../constants/localStore'
|
|
||||||
import useLocalStorage from '../useLocalStorage'
|
|
||||||
|
|
||||||
export interface VaultValue {
|
export interface VaultValue {
|
||||||
address: string
|
address: string
|
||||||
value: BigNumber
|
value: BigNumber
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import BorrowIntro from 'components/Borrow/BorrowIntro'
|
import BorrowIntro from 'components/Borrow/BorrowIntro'
|
||||||
import BorrowTable from 'components/Borrow/BorrowTable'
|
import BorrowTable from 'components/Borrow/BorrowTable'
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
|
|
||||||
export default function BorrowPage() {
|
export default function BorrowPage() {
|
||||||
@ -7,6 +8,7 @@ export default function BorrowPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
|
<MigrationBanner />
|
||||||
<BorrowIntro />
|
<BorrowIntro />
|
||||||
<BorrowTable data={accountBorrowedAssets} title='Borrowed Assets' />
|
<BorrowTable data={accountBorrowedAssets} title='Borrowed Assets' />
|
||||||
<BorrowTable data={availableAssets} title='Available to borrow' />
|
<BorrowTable data={availableAssets} title='Available to borrow' />
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import FarmIntro from 'components/Earn/Farm/FarmIntro'
|
import FarmIntro from 'components/Earn/Farm/FarmIntro'
|
||||||
import { AvailableVaults, DepositedVaults } from 'components/Earn/Farm/Vaults'
|
import { AvailableVaults, DepositedVaults } from 'components/Earn/Farm/Vaults'
|
||||||
import Tab from 'components/Earn/Tab'
|
import Tab from 'components/Earn/Tab'
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
|
|
||||||
export default function FarmPage() {
|
export default function FarmPage() {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
|
<MigrationBanner />
|
||||||
<Tab isFarm />
|
<Tab isFarm />
|
||||||
<FarmIntro />
|
<FarmIntro />
|
||||||
<DepositedVaults />
|
<DepositedVaults />
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import LendIntro from 'components/Earn/Lend/LendIntro'
|
import LendIntro from 'components/Earn/Lend/LendIntro'
|
||||||
import LendingMarketsTable from 'components/Earn/Lend/LendingMarketsTable'
|
import LendingMarketsTable from 'components/Earn/Lend/LendingMarketsTable'
|
||||||
import Tab from 'components/Earn/Tab'
|
import Tab from 'components/Earn/Tab'
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
|
|
||||||
export default function LendPage() {
|
export default function LendPage() {
|
||||||
const { accountLentAssets, availableAssets } = useLendingMarketAssetsTableData()
|
const { accountLentAssets, availableAssets } = useLendingMarketAssetsTableData()
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
|
<MigrationBanner />
|
||||||
<Tab />
|
<Tab />
|
||||||
<LendIntro />
|
<LendIntro />
|
||||||
<LendingMarketsTable data={accountLentAssets} title='Lent Assets' />
|
<LendingMarketsTable data={accountLentAssets} title='Lent Assets' />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
|
||||||
import { useNavigate, useParams } from 'react-router-dom'
|
import { useNavigate, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import Balances from 'components/Portfolio/Account/Balances'
|
import Balances from 'components/Portfolio/Account/Balances'
|
||||||
import BreadCrumbs from 'components/Portfolio/Account/BreadCrumbs'
|
import BreadCrumbs from 'components/Portfolio/Account/BreadCrumbs'
|
||||||
import Summary from 'components/Portfolio/Account/Summary'
|
import Summary from 'components/Portfolio/Account/Summary'
|
||||||
@ -19,6 +19,7 @@ export default function PortfolioAccountPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
|
<MigrationBanner />
|
||||||
<BreadCrumbs accountId={accountId} />
|
<BreadCrumbs accountId={accountId} />
|
||||||
<Summary accountId={accountId} />
|
<Summary accountId={accountId} />
|
||||||
<Balances accountId={accountId} />
|
<Balances accountId={accountId} />
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import AccountOverview from 'components/Portfolio/Overview'
|
import AccountOverview from 'components/Portfolio/Overview'
|
||||||
import PortfolioIntro from 'components/Portfolio/PortfolioIntro'
|
import PortfolioIntro from 'components/Portfolio/PortfolioIntro'
|
||||||
|
|
||||||
export default function PortfolioPage() {
|
export default function PortfolioPage() {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
|
<MigrationBanner />
|
||||||
<PortfolioIntro />
|
<PortfolioIntro />
|
||||||
<AccountOverview />
|
<AccountOverview />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import AccountDetailsCard from 'components/Trade/AccountDetailsCard'
|
import AccountDetailsCard from 'components/Trade/AccountDetailsCard'
|
||||||
import TradeChart from 'components/Trade/TradeChart'
|
import TradeChart from 'components/Trade/TradeChart'
|
||||||
import TradeModule from 'components/Trade/TradeModule'
|
import TradeModule from 'components/Trade/TradeModule'
|
||||||
@ -11,6 +12,8 @@ export default function TradePage() {
|
|||||||
const [sellAsset, setSellAsset] = useState(enabledMarketAssets[1])
|
const [sellAsset, setSellAsset] = useState(enabledMarketAssets[1])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className='flex flex-col w-full h-full gap-4'>
|
||||||
|
<MigrationBanner />
|
||||||
<div className='grid h-full w-full grid-cols-[346px_auto] gap-4'>
|
<div className='grid h-full w-full grid-cols-[346px_auto] gap-4'>
|
||||||
<TradeModule
|
<TradeModule
|
||||||
buyAsset={buyAsset}
|
buyAsset={buyAsset}
|
||||||
@ -22,5 +25,6 @@ export default function TradePage() {
|
|||||||
<div />
|
<div />
|
||||||
<AccountDetailsCard />
|
<AccountDetailsCard />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,13 @@ import AccountDetails from 'components/Account/AccountDetails'
|
|||||||
import Background from 'components/Background'
|
import Background from 'components/Background'
|
||||||
import Footer from 'components/Footer'
|
import Footer from 'components/Footer'
|
||||||
import DesktopHeader from 'components/Header/DesktopHeader'
|
import DesktopHeader from 'components/Header/DesktopHeader'
|
||||||
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import ModalsContainer from 'components/Modals/ModalsContainer'
|
import ModalsContainer from 'components/Modals/ModalsContainer'
|
||||||
import PageMetadata from 'components/PageMetadata'
|
import PageMetadata from 'components/PageMetadata'
|
||||||
import Toaster from 'components/Toaster'
|
import Toaster from 'components/Toaster'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
import { REDUCE_MOTION_KEY } from 'constants/localStore'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
|
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
|
||||||
const accountDetailsExpanded = useStore((s) => s.accountDetailsExpanded)
|
const accountDetailsExpanded = useStore((s) => s.accountDetailsExpanded)
|
||||||
const isFullWidth = location.pathname.includes('trade') || location.pathname === '/'
|
const isFullWidth = location.pathname.includes('trade') || location.pathname === '/'
|
||||||
const account = useCurrentAccount()
|
const accountId = useAccountId()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -57,7 +58,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
'lg:mt-[73px]',
|
'lg:mt-[73px]',
|
||||||
'min-h-screen gap-6 px-4 py-6 w-full relative',
|
'min-h-screen gap-6 px-4 py-6 w-full relative',
|
||||||
'flex',
|
'flex',
|
||||||
isFullWidth && account && (accountDetailsExpanded ? 'pr-110.5' : 'pr-24'),
|
isFullWidth && accountId && (accountDetailsExpanded ? 'pr-110.5' : 'pr-24'),
|
||||||
!reduceMotion && isFullWidth && 'transition-all duration-300',
|
!reduceMotion && isFullWidth && 'transition-all duration-300',
|
||||||
'justify-center',
|
'justify-center',
|
||||||
focusComponent && 'items-center',
|
focusComponent && 'items-center',
|
||||||
|
1
src/types/interfaces/store/settings.d.ts
vendored
1
src/types/interfaces/store/settings.d.ts
vendored
@ -5,4 +5,5 @@ interface Settings {
|
|||||||
lendAssets: boolean
|
lendAssets: boolean
|
||||||
slippage: number
|
slippage: number
|
||||||
tutorial: boolean
|
tutorial: boolean
|
||||||
|
migrationBanner: boolean
|
||||||
}
|
}
|
||||||
|
1
src/types/interfaces/tooltip.d.ts
vendored
Normal file
1
src/types/interfaces/tooltip.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
type TooltipType = 'info' | 'warning' | 'error'
|
@ -245,6 +245,7 @@ module.exports = {
|
|||||||
4.5: '18px',
|
4.5: '18px',
|
||||||
13: '52px',
|
13: '52px',
|
||||||
15: '60px',
|
15: '60px',
|
||||||
|
18: '72px',
|
||||||
30: '120px',
|
30: '120px',
|
||||||
35: '140px',
|
35: '140px',
|
||||||
50: '200px',
|
50: '200px',
|
||||||
|
Loading…
Reference in New Issue
Block a user