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:
Linkie Link 2023-09-25 20:17:43 +02:00 committed by GitHub
parent d0ce3eea45
commit cfd7fb3073
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 409 additions and 275 deletions

View File

@ -14,11 +14,15 @@ jest.mock('hooks/useHealthComputer', () =>
jest.mock('components/Account/AccountBalancesTable', () => jest.fn(() => null))
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 />', () => {
beforeAll(() => {
useStore.setState({
address: 'walletAddress',
accounts: [mockedAccount],
})
})
@ -27,7 +31,7 @@ describe('<AccountDetails />', () => {
})
it('renders account details WHEN account is selected', () => {
mockedUseCurrentAccount.mockReturnValue({ id: 1 })
mockedUseCurrentAccount.mockReturnValue(mockedAccount)
render(<AccountDetails />)
const container = screen.queryByTestId('account-details')

View File

@ -13,6 +13,7 @@ const data: LendingMarketTableData = {
marketLiquidityRate: 0.017,
marketLiquidationThreshold: 0.61,
marketMaxLtv: 0.59,
borrowEnabled: true,
}
jest.mock('hooks/useDisplayCurrencyPrice', () => () => {

View File

@ -28,6 +28,8 @@ const mockedDepositedVault: DepositedVault = {
values: {
primary: BN_ZERO,
secondary: BN_ZERO,
unlocked: BN_ZERO,
unlocking: BN_ZERO,
},
cap: {
denom: 'mock',

View 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>
)
}

View File

@ -1,9 +1,11 @@
import classNames from 'classnames'
import { useMemo } from 'react'
import { useCallback, useMemo } from 'react'
import AccountBalancesTable from 'components/Account/AccountBalancesTable'
import AccountComposition from 'components/Account/AccountComposition'
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 Card from 'components/Card'
import DisplayCurrency from 'components/DisplayCurrency'
@ -14,6 +16,8 @@ import Text from 'components/Text'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { REDUCE_MOTION_KEY } from 'constants/localStore'
import { ORACLE_DENOM } from 'constants/oracle'
import useAccountId from 'hooks/useAccountId'
import useAccounts from 'hooks/useAccounts'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useCurrentAccount from 'hooks/useCurrentAccount'
import useHealthComputer from 'hooks/useHealthComputer'
@ -29,11 +33,15 @@ import {
} from 'utils/accounts'
export default function AccountDetailsController() {
const account = useCurrentAccount()
const address = useStore((s) => s.address)
const { isLoading } = useAccounts(address)
const accountId = useAccountId()
const account = useCurrentAccount()
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} />
}
@ -81,6 +89,19 @@ function AccountDetails(props: Props) {
[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 (
<div
data-testid='account-details'
@ -146,7 +167,7 @@ function AccountDetails(props: Props) {
{glowElement(!reduceMotion)}
</div>
<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} />
<Text className='w-full px-4 py-2 text-white bg-white/10'>Balances</Text>
<AccountBalancesTable

View File

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

View 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>
)
}

View 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>
)
}

View 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>
)
}

View File

@ -2,15 +2,15 @@ import { Suspense } from 'react'
import AccountMenuContent from 'components/Account/AccountMenuContent'
import Loading from 'components/Loading'
import useAccounts from 'hooks/useAccounts'
import useAccountIds from 'hooks/useAccountIds'
import useStore from 'store'
function Content() {
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 (!accounts) return null
return <AccountMenuContent accounts={accounts} />
if (!accountIds) return null
return <AccountMenuContent />
}
export default function AccountMenu() {

View File

@ -6,7 +6,6 @@ import AccountCreateFirst from 'components/Account/AccountCreateFirst'
import AccountFund from 'components/Account/AccountFund/AccountFundFullPage'
import AccountList from 'components/Account/AccountList'
import Button from 'components/Button'
import { CircularProgress } from 'components/CircularProgress'
import { Account, Plus, PlusCircled } from 'components/Icons'
import Overlay from 'components/Overlay'
import Text from 'components/Text'
@ -14,6 +13,7 @@ import WalletBridges from 'components/Wallet/WalletBridges'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LEND_ASSETS_KEY } from 'constants/localStore'
import useAccountId from 'hooks/useAccountId'
import useAccountIds from 'hooks/useAccountIds'
import useAutoLend from 'hooks/useAutoLend'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
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 ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
interface Props {
accounts: Account[]
}
export default function AccountMenuContent(props: Props) {
export default function AccountMenuContent() {
const navigate = useNavigate()
const { pathname } = useLocation()
const { address } = useParams()
const { data: accountIds } = useAccountIds(address)
const accountId = useAccountId()
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 { enableAutoLendAccountId } = useAutoLend()
const hasCreditAccounts = !!props.accounts.length
const hasCreditAccounts = !!accountIds.length
const isAccountSelected = isNumber(accountId)
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
const isLoadingAccount = isAccountSelected && selectedAccountDetails?.id !== accountId
const checkHasFunds = useCallback(() => {
return (
transactionFeeCoinBalance &&
@ -149,14 +142,7 @@ export default function AccountMenuContent(props: Props) {
'top-[54px] h-[calc(100%-54px)] items-start',
)}
>
{isAccountSelected && isLoadingAccount && (
<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} />
)}
{hasCreditAccounts && <AccountList setShowMenu={setShowMenu} />}
</div>
</Overlay>
</div>

View File

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

View File

@ -6,6 +6,8 @@ import Text from 'components/Text'
interface Props {
enableKeyPress?: boolean
hideText?: boolean
className?: string
onClick: () => void
}
@ -34,10 +36,10 @@ export default function EscButton(props: Props) {
leftIcon={<Cross />}
iconClassName='w-3'
color='tertiary'
className='h-3 w-13'
className={props.className ? props.className : 'h-3 w-13'}
size='xs'
>
<Text size='2xs'>ESC</Text>
{!props.hideText && <Text size='2xs'>ESC</Text>}
</Button>
)
}

View File

@ -38,8 +38,10 @@ export const HealthGauge = ({ diameter = 40, health = 0, updatedHealth = 0 }: Pr
[color, updatedColor, isUpdated, isIncrease],
)
const tooltipContent = health === 0 ? 'loading...' : isUpdated ? updatedLabel : label
return (
<Tooltip type='info' content={isUpdated ? updatedLabel : label}>
<Tooltip type='info' content={tooltipContent}>
<div
className={classNames(
'relative grid place-items-center',

View 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>
)
}

View File

@ -3,22 +3,21 @@ import React from 'react'
import HealthBar from 'components/Account/HealthBar'
import Card from 'components/Card'
import { Heart } from 'components/Icons'
import Loading from 'components/Loading'
import Text from 'components/Text'
import TitleAndSubCell from 'components/TitleAndSubCell'
interface Props {
stats: { title: React.ReactNode; sub: string }[]
health: number
accountId: string
isCurrent?: boolean
accountId?: string
}
export default function Skeleton(props: Props) {
return (
<Card className='bg-white/5 p-4'>
<div className='flex justify-between items-center'>
<Text>Credit account {props.accountId || <Loading />}</Text>
<Card className='p-4 bg-white/5'>
<div className='flex items-center justify-between'>
<Text>Credit account {props.accountId}</Text>
<Text size='xs' className='text-white/60'>
{props.isCurrent && '(current)'}
</Text>

View File

@ -4,8 +4,6 @@ import { ReactNode } from 'react'
import { TooltipArrow } from 'components/Icons'
import Text from 'components/Text'
import { TooltipType } from '.'
interface Props {
content: ReactNode | string
type: TooltipType

View File

@ -18,8 +18,6 @@ interface Props {
underline?: boolean
}
export type TooltipType = 'info' | 'warning' | 'error'
export const Tooltip = (props: Props) => {
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)

View File

@ -12,6 +12,7 @@ import { Check, Copy, ExternalLink, Osmo } from 'components/Icons'
import Overlay from 'components/Overlay'
import Text from 'components/Text'
import RecentTransactions from 'components/Wallet/RecentTransactions'
import WalletSelect from 'components/Wallet/WalletSelect'
import { CHAINS } from 'constants/chains'
import { ENV } from 'constants/env'
import { BN_ZERO } from 'constants/math'
@ -25,8 +26,6 @@ import { getBaseAsset, getEnabledMarketAssets } from 'utils/assets'
import { truncate } from 'utils/formatters'
import { getPage, getRoute } from 'utils/route'
import WalletSelect from './WalletSelect'
export default function WalletConnectedButton() {
// ---------------
// EXTERNAL HOOKS

View File

@ -8,4 +8,5 @@ export const DEFAULT_SETTINGS: Settings = {
displayCurrency: ORACLE_DENOM,
slippage: 0.02,
tutorial: true,
migrationBanner: true,
}

View File

@ -8,3 +8,4 @@ export const SLIPPAGE_KEY = 'slippage'
export const TERMS_OF_SERVICE_KEY = 'termsOfService'
export const TUTORIAL_KEY = 'tutorial'
export const TRANSACTIONS_KEY = 'transactions'
export const MIGRATION_BANNER_KEY = 'migrationBanner'

View File

@ -84,7 +84,7 @@ export default function useDepositVault(props: Props): {
amount: 'account_balance',
},
}))
}, [isAutoLend, props.borrowings, props.deposits, props.reclaims])
}, [isAutoLend, props.vault.denoms.primary, props.vault.denoms.secondary])
const actions = useMemo(() => {
return [

View File

@ -1,6 +1,9 @@
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 useLocalStorage from 'hooks/useLocalStorage'
import usePrices from 'hooks/usePrices'
import {
addCoins,
@ -15,10 +18,6 @@ import { cloneAccount } from 'utils/accounts'
import { byDenom } from 'utils/array'
import { getValueFromBNCoins } from 'utils/helpers'
import { DEFAULT_SETTINGS } from '../../constants/defaultSettings'
import { SLIPPAGE_KEY } from '../../constants/localStore'
import useLocalStorage from '../useLocalStorage'
export interface VaultValue {
address: string
value: BigNumber

View File

@ -1,5 +1,6 @@
import BorrowIntro from 'components/Borrow/BorrowIntro'
import BorrowTable from 'components/Borrow/BorrowTable'
import MigrationBanner from 'components/MigrationBanner'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
export default function BorrowPage() {
@ -7,6 +8,7 @@ export default function BorrowPage() {
return (
<div className='flex flex-wrap w-full gap-6'>
<MigrationBanner />
<BorrowIntro />
<BorrowTable data={accountBorrowedAssets} title='Borrowed Assets' />
<BorrowTable data={availableAssets} title='Available to borrow' />

View File

@ -1,10 +1,12 @@
import FarmIntro from 'components/Earn/Farm/FarmIntro'
import { AvailableVaults, DepositedVaults } from 'components/Earn/Farm/Vaults'
import Tab from 'components/Earn/Tab'
import MigrationBanner from 'components/MigrationBanner'
export default function FarmPage() {
return (
<div className='flex flex-wrap w-full gap-6'>
<MigrationBanner />
<Tab isFarm />
<FarmIntro />
<DepositedVaults />

View File

@ -1,12 +1,14 @@
import LendIntro from 'components/Earn/Lend/LendIntro'
import LendingMarketsTable from 'components/Earn/Lend/LendingMarketsTable'
import Tab from 'components/Earn/Tab'
import MigrationBanner from 'components/MigrationBanner'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
export default function LendPage() {
const { accountLentAssets, availableAssets } = useLendingMarketAssetsTableData()
return (
<div className='flex flex-wrap w-full gap-6'>
<MigrationBanner />
<Tab />
<LendIntro />
<LendingMarketsTable data={accountLentAssets} title='Lent Assets' />

View File

@ -1,6 +1,6 @@
import React from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import MigrationBanner from 'components/MigrationBanner'
import Balances from 'components/Portfolio/Account/Balances'
import BreadCrumbs from 'components/Portfolio/Account/BreadCrumbs'
import Summary from 'components/Portfolio/Account/Summary'
@ -19,6 +19,7 @@ export default function PortfolioAccountPage() {
return (
<div className='flex flex-wrap w-full gap-6'>
<MigrationBanner />
<BreadCrumbs accountId={accountId} />
<Summary accountId={accountId} />
<Balances accountId={accountId} />

View File

@ -1,9 +1,11 @@
import MigrationBanner from 'components/MigrationBanner'
import AccountOverview from 'components/Portfolio/Overview'
import PortfolioIntro from 'components/Portfolio/PortfolioIntro'
export default function PortfolioPage() {
return (
<div className='flex flex-wrap w-full gap-6'>
<MigrationBanner />
<PortfolioIntro />
<AccountOverview />
</div>

View File

@ -1,5 +1,6 @@
import { useState } from 'react'
import MigrationBanner from 'components/MigrationBanner'
import AccountDetailsCard from 'components/Trade/AccountDetailsCard'
import TradeChart from 'components/Trade/TradeChart'
import TradeModule from 'components/Trade/TradeModule'
@ -11,6 +12,8 @@ export default function TradePage() {
const [sellAsset, setSellAsset] = useState(enabledMarketAssets[1])
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'>
<TradeModule
buyAsset={buyAsset}
@ -22,5 +25,6 @@ export default function TradePage() {
<div />
<AccountDetailsCard />
</div>
</div>
)
}

View File

@ -6,12 +6,13 @@ import AccountDetails from 'components/Account/AccountDetails'
import Background from 'components/Background'
import Footer from 'components/Footer'
import DesktopHeader from 'components/Header/DesktopHeader'
import MigrationBanner from 'components/MigrationBanner'
import ModalsContainer from 'components/Modals/ModalsContainer'
import PageMetadata from 'components/PageMetadata'
import Toaster from 'components/Toaster'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { REDUCE_MOTION_KEY } from 'constants/localStore'
import useCurrentAccount from 'hooks/useCurrentAccount'
import useAccountId from 'hooks/useAccountId'
import useLocalStorage from 'hooks/useLocalStorage'
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 accountDetailsExpanded = useStore((s) => s.accountDetailsExpanded)
const isFullWidth = location.pathname.includes('trade') || location.pathname === '/'
const account = useCurrentAccount()
const accountId = useAccountId()
return (
<>
@ -57,7 +58,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
'lg:mt-[73px]',
'min-h-screen gap-6 px-4 py-6 w-full relative',
'flex',
isFullWidth && account && (accountDetailsExpanded ? 'pr-110.5' : 'pr-24'),
isFullWidth && accountId && (accountDetailsExpanded ? 'pr-110.5' : 'pr-24'),
!reduceMotion && isFullWidth && 'transition-all duration-300',
'justify-center',
focusComponent && 'items-center',

View File

@ -5,4 +5,5 @@ interface Settings {
lendAssets: boolean
slippage: number
tutorial: boolean
migrationBanner: boolean
}

1
src/types/interfaces/tooltip.d.ts vendored Normal file
View File

@ -0,0 +1 @@
type TooltipType = 'info' | 'warning' | 'error'

View File

@ -245,6 +245,7 @@ module.exports = {
4.5: '18px',
13: '52px',
15: '60px',
18: '72px',
30: '120px',
35: '140px',
50: '200px',