Full refactor tables (#556)
* 📈 Improve structure generic Table component * ♻️ Update Borrow Table and overall structure of Table comp * ♻️ Update Lend table * ✨ add loading state for lend table * 🧪 Fix unit tests
This commit is contained in:
parent
7917d24134
commit
ccc4a42354
@ -1,38 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import MarketDetails from 'components/MarketAssetTable/MarketDetails'
|
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
|
|
||||||
const data: LendingMarketTableData = {
|
|
||||||
asset: ASSETS[0],
|
|
||||||
marketDepositAmount: BN('890546916'),
|
|
||||||
accountLentValue: BN('0.5498406009348686811'),
|
|
||||||
marketLiquidityAmount: BN('629396551'),
|
|
||||||
marketDepositCap: BN('2500000000000'),
|
|
||||||
marketLiquidityRate: 0.017,
|
|
||||||
marketLiquidationThreshold: 0.61,
|
|
||||||
marketMaxLtv: 0.59,
|
|
||||||
borrowEnabled: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
jest.mock('hooks/useDisplayCurrencyPrice', () => () => {
|
|
||||||
const { BN } = require('utils/helpers')
|
|
||||||
|
|
||||||
return {
|
|
||||||
getConversionRate: () => BN(1),
|
|
||||||
convertAmount: () => BN(1),
|
|
||||||
symbol: 'MARS',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('<LendingDetails />', () => {
|
|
||||||
afterAll(() => {
|
|
||||||
jest.unmock('hooks/usePrices')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<MarketDetails type='lend' data={data} />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
@ -14,6 +14,7 @@ const mockedDepositedVault: DepositedVault = {
|
|||||||
...TESTNET_VAULTS_META_DATA[0],
|
...TESTNET_VAULTS_META_DATA[0],
|
||||||
status: 'active',
|
status: 'active',
|
||||||
apy: 1,
|
apy: 1,
|
||||||
|
apr: null,
|
||||||
ltv: {
|
ltv: {
|
||||||
max: 0.65,
|
max: 0.65,
|
||||||
liq: 0.7,
|
liq: 0.7,
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
import { render } from '@testing-library/react'
|
|
||||||
|
|
||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
|
||||||
import VaultBorrowings, { VaultBorrowingsProps } from 'components/Modals/Vault/VaultBorrowings'
|
|
||||||
import { ASSETS } from 'constants/assets'
|
|
||||||
import { TESTNET_VAULTS_META_DATA } from 'constants/vaults'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
|
|
||||||
jest.mock('hooks/usePrices', () =>
|
|
||||||
jest.fn(() => ({
|
|
||||||
data: [],
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
|
|
||||||
jest.mock('hooks/usePrice', () => jest.fn(() => '1'))
|
|
||||||
|
|
||||||
jest.mock('hooks/useMarketAssets', () =>
|
|
||||||
jest.fn(() => ({
|
|
||||||
data: [],
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
|
|
||||||
jest.mock('hooks/broadcast/useDepositVault', () => jest.fn(() => ({ actions: [] })))
|
|
||||||
|
|
||||||
jest.mock('components/DisplayCurrency')
|
|
||||||
|
|
||||||
jest.mock('hooks/useHealthComputer', () =>
|
|
||||||
jest.fn(() => ({
|
|
||||||
computeMaxBorrowAmount: () => {},
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
|
|
||||||
const mockedDisplayCurrency = jest
|
|
||||||
.mocked(DisplayCurrency)
|
|
||||||
.mockImplementation(() => <div>Display currency</div>)
|
|
||||||
|
|
||||||
const mockedVault: Vault = {
|
|
||||||
...TESTNET_VAULTS_META_DATA[0],
|
|
||||||
apy: 0,
|
|
||||||
ltv: {
|
|
||||||
liq: 0.2,
|
|
||||||
max: 0.1,
|
|
||||||
},
|
|
||||||
cap: {
|
|
||||||
denom: 'test',
|
|
||||||
max: BN(10),
|
|
||||||
used: BN(2),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
describe('<VaultBorrowings />', () => {
|
|
||||||
const defaultProps: VaultBorrowingsProps = {
|
|
||||||
primaryAsset: ASSETS[0],
|
|
||||||
secondaryAsset: ASSETS[1],
|
|
||||||
vault: mockedVault,
|
|
||||||
borrowings: [],
|
|
||||||
deposits: [],
|
|
||||||
onChangeBorrowings: jest.fn(),
|
|
||||||
depositActions: [],
|
|
||||||
depositCapReachedCoins: [],
|
|
||||||
displayCurrency: 'uosmo',
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
useStore.setState({
|
|
||||||
baseCurrency: ASSETS[0],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
useStore.clearState()
|
|
||||||
mockedDisplayCurrency.mockClear()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
const { container } = render(<VaultBorrowings {...defaultProps} />)
|
|
||||||
expect(container).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render DisplayCurrency correctly', () => {
|
|
||||||
expect(mockedDisplayCurrency).toHaveBeenCalledTimes(1)
|
|
||||||
expect(mockedDisplayCurrency).toHaveBeenCalledWith(
|
|
||||||
{ coin: new BNCoin({ denom: 'usd', amount: '0' }) },
|
|
||||||
expect.anything(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,6 +1,5 @@
|
|||||||
import { render } from '@testing-library/react'
|
import { render } from '@testing-library/react'
|
||||||
|
|
||||||
import { TooltipType } from 'components/Tooltip'
|
|
||||||
import TooltipContent from 'components/Tooltip/TooltipContent'
|
import TooltipContent from 'components/Tooltip/TooltipContent'
|
||||||
|
|
||||||
describe('<Tooltip />', () => {
|
describe('<Tooltip />', () => {
|
||||||
|
@ -37,14 +37,10 @@ export default function AccountComposition(props: Props) {
|
|||||||
const { account } = props
|
const { account } = props
|
||||||
const hasChanged = !!updatedAccount
|
const hasChanged = !!updatedAccount
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
useBorrowMarketAssetsTableData()
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||||
useLendingMarketAssetsTableData()
|
useLendingMarketAssetsTableData()
|
||||||
const borrowAssetsData = useMemo(
|
|
||||||
() => [...borrowAvailableAssets, ...accountBorrowedAssets],
|
|
||||||
[borrowAvailableAssets, accountBorrowedAssets],
|
|
||||||
)
|
|
||||||
const lendingAssetsData = useMemo(
|
const lendingAssetsData = useMemo(
|
||||||
() => [...lendingAvailableAssets, ...accountLentAssets],
|
() => [...lendingAvailableAssets, ...accountLentAssets],
|
||||||
[lendingAvailableAssets, accountLentAssets],
|
[lendingAvailableAssets, accountLentAssets],
|
||||||
|
@ -76,14 +76,12 @@ function AccountDetails(props: Props) {
|
|||||||
return updatedLeverage
|
return updatedLeverage
|
||||||
}, [updatedAccount, prices, leverage])
|
}, [updatedAccount, prices, leverage])
|
||||||
|
|
||||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
useBorrowMarketAssetsTableData()
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
|
|
||||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||||
useLendingMarketAssetsTableData()
|
useLendingMarketAssetsTableData()
|
||||||
const borrowAssetsData = useMemo(
|
|
||||||
() => [...borrowAvailableAssets, ...accountBorrowedAssets],
|
|
||||||
[borrowAvailableAssets, accountBorrowedAssets],
|
|
||||||
)
|
|
||||||
const lendingAssetsData = useMemo(
|
const lendingAssetsData = useMemo(
|
||||||
() => [...lendingAvailableAssets, ...accountLentAssets],
|
() => [...lendingAvailableAssets, ...accountLentAssets],
|
||||||
[lendingAvailableAssets, accountLentAssets],
|
[lendingAvailableAssets, accountLentAssets],
|
||||||
|
@ -28,14 +28,10 @@ export default function AccountStats(props: Props) {
|
|||||||
[account, prices],
|
[account, prices],
|
||||||
)
|
)
|
||||||
const { health } = useHealthComputer(account)
|
const { health } = useHealthComputer(account)
|
||||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
useBorrowMarketAssetsTableData()
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||||
useLendingMarketAssetsTableData()
|
useLendingMarketAssetsTableData()
|
||||||
const borrowAssetsData = useMemo(
|
|
||||||
() => [...borrowAvailableAssets, ...accountBorrowedAssets],
|
|
||||||
[borrowAvailableAssets, accountBorrowedAssets],
|
|
||||||
)
|
|
||||||
const lendingAssetsData = useMemo(
|
const lendingAssetsData = useMemo(
|
||||||
() => [...lendingAvailableAssets, ...accountLentAssets],
|
() => [...lendingAvailableAssets, ...accountLentAssets],
|
||||||
[lendingAvailableAssets, accountLentAssets],
|
[lendingAvailableAssets, accountLentAssets],
|
||||||
|
@ -36,15 +36,11 @@ export default function AccountSummary(props: Props) {
|
|||||||
: BN_ZERO,
|
: BN_ZERO,
|
||||||
[props.account, updatedAccount, prices],
|
[props.account, updatedAccount, prices],
|
||||||
)
|
)
|
||||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
useBorrowMarketAssetsTableData()
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||||
useLendingMarketAssetsTableData()
|
useLendingMarketAssetsTableData()
|
||||||
|
|
||||||
const borrowAssetsData = useMemo(
|
|
||||||
() => [...borrowAvailableAssets, ...accountBorrowedAssets],
|
|
||||||
[borrowAvailableAssets, accountBorrowedAssets],
|
|
||||||
)
|
|
||||||
const lendingAssetsData = useMemo(
|
const lendingAssetsData = useMemo(
|
||||||
() => [...lendingAvailableAssets, ...accountLentAssets],
|
() => [...lendingAvailableAssets, ...accountLentAssets],
|
||||||
[lendingAvailableAssets, accountLentAssets],
|
[lendingAvailableAssets, accountLentAssets],
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
import { ColumnDef, Row, Table } from '@tanstack/react-table'
|
|
||||||
import { useCallback, useMemo } from 'react'
|
|
||||||
|
|
||||||
import AmountAndValue from 'components/AmountAndValue'
|
|
||||||
import AssetImage from 'components/Asset/AssetImage'
|
|
||||||
import BorrowActionButtons from 'components/Borrow/BorrowActionButtons'
|
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
|
||||||
import { ChevronDown, ChevronUp } from 'components/Icons'
|
|
||||||
import Loading from 'components/Loading'
|
|
||||||
import AssetListTable from 'components/MarketAssetTable'
|
|
||||||
import MarketAssetTableRow from 'components/MarketAssetTable/MarketAssetTableRow'
|
|
||||||
import MarketDetails from 'components/MarketAssetTable/MarketDetails'
|
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
import { getEnabledMarketAssets } from 'utils/assets'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
title: string
|
|
||||||
data: BorrowMarketTableData[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function BorrowTable(props: Props) {
|
|
||||||
const { title, data } = props
|
|
||||||
const shouldShowAccountBorrowed = !!data[0]?.debt
|
|
||||||
const marketAssets = getEnabledMarketAssets()
|
|
||||||
|
|
||||||
const rowRenderer = useCallback(
|
|
||||||
(row: Row<BorrowMarketTableData>, table: Table<BorrowMarketTableData>) => {
|
|
||||||
return (
|
|
||||||
<MarketAssetTableRow
|
|
||||||
key={`borrow-asset-${row.id}`}
|
|
||||||
isExpanded={row.getIsExpanded()}
|
|
||||||
resetExpanded={table.resetExpanded}
|
|
||||||
rowData={row}
|
|
||||||
expandedActionButtons={<BorrowActionButtons data={row.original} />}
|
|
||||||
expandedDetails={<MarketDetails data={row.original} type='borrow' />}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
|
|
||||||
const columns = useMemo<ColumnDef<BorrowMarketTableData>[]>(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
accessorKey: 'asset.name',
|
|
||||||
header: 'Asset',
|
|
||||||
id: 'symbol',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const asset = row.original.asset
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='flex items-center flex-1 gap-3'>
|
|
||||||
<AssetImage asset={asset} size={32} />
|
|
||||||
<TitleAndSubCell
|
|
||||||
title={asset.symbol}
|
|
||||||
sub={asset.name}
|
|
||||||
className='text-left min-w-15'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...(shouldShowAccountBorrowed
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
accessorKey: 'debt',
|
|
||||||
header: 'Borrowed',
|
|
||||||
cell: (info: any) => {
|
|
||||||
const borrowAsset = info.row.original as BorrowMarketTableData
|
|
||||||
const asset = marketAssets.find((asset) => asset.denom === borrowAsset.asset.denom)
|
|
||||||
|
|
||||||
if (!asset) return null
|
|
||||||
|
|
||||||
return <AmountAndValue asset={asset} amount={borrowAsset?.debt ?? BN_ZERO} />
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
{
|
|
||||||
accessorKey: 'borrowRate',
|
|
||||||
header: 'Borrow Rate',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
if (row.original.borrowRate === null) {
|
|
||||||
return <Loading />
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormattedNumber
|
|
||||||
className='justify-end text-xs'
|
|
||||||
amount={row.original.borrowRate * 100}
|
|
||||||
options={{ minDecimals: 2, maxDecimals: 2, suffix: '%' }}
|
|
||||||
animate
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'liquidity',
|
|
||||||
header: 'Liquidity Available',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const { liquidity, asset: borrowAsset } = row.original
|
|
||||||
const asset = marketAssets.find((asset) => asset.denom === borrowAsset.denom)
|
|
||||||
|
|
||||||
if (!asset) return null
|
|
||||||
|
|
||||||
if (liquidity === null) {
|
|
||||||
return <Loading />
|
|
||||||
}
|
|
||||||
|
|
||||||
return <AmountAndValue asset={asset} amount={liquidity.amount ?? BN_ZERO} />
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'manage',
|
|
||||||
enableSorting: false,
|
|
||||||
header: 'Manage',
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<div className='flex items-center justify-end'>
|
|
||||||
<div className='w-4'>{row.getIsExpanded() ? <ChevronUp /> : <ChevronDown />}</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[shouldShowAccountBorrowed, marketAssets],
|
|
||||||
)
|
|
||||||
|
|
||||||
return <AssetListTable title={title} rowRenderer={rowRenderer} columns={columns} data={data} />
|
|
||||||
}
|
|
37
src/components/Borrow/Borrowings.tsx
Normal file
37
src/components/Borrow/Borrowings.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AvailableBorrowingsTable from 'components/Borrow/Table/AvailableBorrowingsTable'
|
||||||
|
import DepositedBorrowingsTable from 'components/Borrow/Table/DepositedBorrowingsTable'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
|
import { getBorrowEnabledAssets } from 'utils/assets'
|
||||||
|
|
||||||
|
export default function Borrowings() {
|
||||||
|
const { data } = useBorrowMarketAssetsTableData()
|
||||||
|
|
||||||
|
if (!data?.allAssets?.length) {
|
||||||
|
return <Fallback />
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DepositedBorrowingsTable data={data.accountBorrowedAssets} isLoading={false} />
|
||||||
|
<AvailableBorrowingsTable data={data.availableAssets} isLoading={false} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Fallback() {
|
||||||
|
const assets = getBorrowEnabledAssets()
|
||||||
|
const data: BorrowMarketTableData[] = assets.map((asset) => ({
|
||||||
|
asset,
|
||||||
|
borrowRate: null,
|
||||||
|
liquidity: null,
|
||||||
|
marketMaxLtv: 0,
|
||||||
|
marketDepositAmount: BN_ZERO,
|
||||||
|
marketLiquidityRate: 0,
|
||||||
|
marketLiquidityAmount: BN_ZERO,
|
||||||
|
marketLiquidationThreshold: 0,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return <AvailableBorrowingsTable data={data} isLoading />
|
||||||
|
}
|
40
src/components/Borrow/Table/AvailableBorrowingsTable.tsx
Normal file
40
src/components/Borrow/Table/AvailableBorrowingsTable.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Row } from '@tanstack/react-table'
|
||||||
|
import { Table as TanstackTable } from '@tanstack/table-core/build/lib/types'
|
||||||
|
import React, { useCallback } from 'react'
|
||||||
|
|
||||||
|
import useAvailableColumns from 'components/Borrow/Table/Columns/useAvailableColumns'
|
||||||
|
import Card from 'components/Card'
|
||||||
|
import MarketDetails from 'components/MarketDetails'
|
||||||
|
import Table from 'components/Table'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: BorrowMarketTableData[]
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AvailableBorrowingsTable(props: Props) {
|
||||||
|
const columns = useAvailableColumns({ isLoading: props.isLoading })
|
||||||
|
|
||||||
|
const renderExpanded = useCallback(
|
||||||
|
(row: Row<BorrowMarketTableData>, _: TanstackTable<BorrowMarketTableData>) => (
|
||||||
|
<MarketDetails
|
||||||
|
row={row as Row<BorrowMarketTableData | LendingMarketTableData>}
|
||||||
|
type='borrow'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!props.data.length) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className='w-full h-fit bg-white/5' title={'Available to Borrow'}>
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
data={props.data}
|
||||||
|
initialSorting={[{ id: 'asset.name', desc: true }]}
|
||||||
|
renderExpanded={renderExpanded}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
25
src/components/Borrow/Table/Columns/BorrowRate.tsx
Normal file
25
src/components/Borrow/Table/Columns/BorrowRate.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
|
||||||
|
export const BORROW_RATE_META = { accessorKey: 'borrowRate', header: 'Borrow Rate' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
borrowRate: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BorrowRate(props: Props) {
|
||||||
|
if (props.borrowRate === null) {
|
||||||
|
return <Loading />
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormattedNumber
|
||||||
|
className='justify-end text-xs'
|
||||||
|
amount={props.borrowRate * 100}
|
||||||
|
options={{ minDecimals: 2, maxDecimals: 2, suffix: '%' }}
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
22
src/components/Borrow/Table/Columns/Debt.tsx
Normal file
22
src/components/Borrow/Table/Columns/Debt.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AmountAndValue from 'components/AmountAndValue'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { getEnabledMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
|
export const DEBT_META = {
|
||||||
|
accessorKey: 'debt',
|
||||||
|
header: 'Debt',
|
||||||
|
}
|
||||||
|
interface Props {
|
||||||
|
data: BorrowMarketTableData
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Debt(props: Props) {
|
||||||
|
const marketAssets = getEnabledMarketAssets()
|
||||||
|
const asset = marketAssets.find((asset) => asset.denom === props.data.asset.denom)
|
||||||
|
|
||||||
|
if (!asset) return null
|
||||||
|
|
||||||
|
return <AmountAndValue asset={asset} amount={props.data?.debt ?? BN_ZERO} />
|
||||||
|
}
|
24
src/components/Borrow/Table/Columns/Liquidity.tsx
Normal file
24
src/components/Borrow/Table/Columns/Liquidity.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AmountAndValue from 'components/AmountAndValue'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { getEnabledMarketAssets } from 'utils/assets'
|
||||||
|
|
||||||
|
export const LIQUIDITY_META = { accessorKey: 'asset.name', header: 'Asset', id: 'symbol' }
|
||||||
|
interface Props {
|
||||||
|
data: BorrowMarketTableData
|
||||||
|
}
|
||||||
|
export default function Liquidity(props: Props) {
|
||||||
|
const { liquidity, asset: borrowAsset } = props.data
|
||||||
|
const marketAssets = getEnabledMarketAssets()
|
||||||
|
const asset = marketAssets.find((asset) => asset.denom === borrowAsset.denom)
|
||||||
|
|
||||||
|
if (!asset) return null
|
||||||
|
|
||||||
|
if (liquidity === null) {
|
||||||
|
return <Loading />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <AmountAndValue asset={asset} amount={liquidity.amount ?? BN_ZERO} />
|
||||||
|
}
|
17
src/components/Borrow/Table/Columns/Manage.tsx
Normal file
17
src/components/Borrow/Table/Columns/Manage.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { ChevronDown, ChevronUp } from 'components/Icons'
|
||||||
|
|
||||||
|
export const MANAGE_META = { accessorKey: 'manage', enableSorting: false, header: 'Manage' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isExpanded: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Manage(props: Props) {
|
||||||
|
return (
|
||||||
|
<div className='flex items-center justify-end'>
|
||||||
|
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
20
src/components/Borrow/Table/Columns/Name.tsx
Normal file
20
src/components/Borrow/Table/Columns/Name.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AssetImage from 'components/Asset/AssetImage'
|
||||||
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
|
|
||||||
|
export const NAME_META = { accessorKey: 'asset.name', header: 'Asset', id: 'symbol' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: BorrowMarketTableData
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Name(props: Props) {
|
||||||
|
const { asset } = props.data
|
||||||
|
return (
|
||||||
|
<div className='flex items-center flex-1 gap-3'>
|
||||||
|
<AssetImage asset={asset} size={32} />
|
||||||
|
<TitleAndSubCell title={asset.symbol} sub={asset.name} className='text-left min-w-15' />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
34
src/components/Borrow/Table/Columns/useAvailableColumns.tsx
Normal file
34
src/components/Borrow/Table/Columns/useAvailableColumns.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
|
||||||
|
import BorrowRate, { BORROW_RATE_META } from 'components/Borrow/Table/Columns/BorrowRate'
|
||||||
|
import Liquidity, { LIQUIDITY_META } from 'components/Borrow/Table/Columns/Liquidity'
|
||||||
|
import Manage, { MANAGE_META } from 'components/Borrow/Table/Columns/Manage'
|
||||||
|
import Name, { NAME_META } from 'components/Borrow/Table/Columns/Name'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useAvailableColumns(props: Props) {
|
||||||
|
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...NAME_META,
|
||||||
|
cell: ({ row }) => <Name data={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...BORROW_RATE_META,
|
||||||
|
cell: ({ row }) => <BorrowRate borrowRate={row.original.borrowRate} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...LIQUIDITY_META,
|
||||||
|
cell: ({ row }) => <Liquidity data={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...MANAGE_META,
|
||||||
|
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [])
|
||||||
|
}
|
39
src/components/Borrow/Table/Columns/useDepositedColumns.tsx
Normal file
39
src/components/Borrow/Table/Columns/useDepositedColumns.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
|
||||||
|
import BorrowRate, { BORROW_RATE_META } from 'components/Borrow/Table/Columns/BorrowRate'
|
||||||
|
import Debt, { DEBT_META } from 'components/Borrow/Table/Columns/Debt'
|
||||||
|
import Liquidity, { LIQUIDITY_META } from 'components/Borrow/Table/Columns/Liquidity'
|
||||||
|
import Manage, { MANAGE_META } from 'components/Borrow/Table/Columns/Manage'
|
||||||
|
import Name, { NAME_META } from 'components/Borrow/Table/Columns/Name'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useDepositedColumns(props: Props) {
|
||||||
|
return useMemo<ColumnDef<BorrowMarketTableData>[]>(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...NAME_META,
|
||||||
|
cell: ({ row }) => <Name data={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...DEBT_META,
|
||||||
|
cell: ({ row }) => <Debt data={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...BORROW_RATE_META,
|
||||||
|
cell: ({ row }) => <BorrowRate borrowRate={row.original.borrowRate} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...LIQUIDITY_META,
|
||||||
|
cell: ({ row }) => <Liquidity data={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...MANAGE_META,
|
||||||
|
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [])
|
||||||
|
}
|
38
src/components/Borrow/Table/DepositedBorrowingsTable.tsx
Normal file
38
src/components/Borrow/Table/DepositedBorrowingsTable.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Row } from '@tanstack/react-table'
|
||||||
|
import { Table as TanStackTable } from '@tanstack/table-core/build/lib/types'
|
||||||
|
import React, { useCallback } from 'react'
|
||||||
|
|
||||||
|
import useDepositedColumns from 'components/Borrow/Table/Columns/useDepositedColumns'
|
||||||
|
import Card from 'components/Card'
|
||||||
|
import MarketDetails from 'components/MarketDetails'
|
||||||
|
import Table from 'components/Table'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: BorrowMarketTableData[]
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DepositedBorrowingsTable(props: Props) {
|
||||||
|
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
||||||
|
|
||||||
|
const renderExpanded = useCallback(
|
||||||
|
(
|
||||||
|
row: Row<BorrowMarketTableData | LendingMarketTableData>,
|
||||||
|
table: TanStackTable<BorrowMarketTableData>,
|
||||||
|
) => <MarketDetails row={row} type='borrow' />,
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!props.data.length) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className='w-full h-fit bg-white/5' title='Borrowed Assets'>
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
data={props.data}
|
||||||
|
initialSorting={[{ id: 'asset.name', desc: true }]}
|
||||||
|
renderExpanded={renderExpanded}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
@ -11,6 +11,7 @@ type Props = {
|
|||||||
|
|
||||||
export default function AvailableVaultsTable(props: Props) {
|
export default function AvailableVaultsTable(props: Props) {
|
||||||
const columns = useAvailableColumns({ isLoading: props.isLoading })
|
const columns = useAvailableColumns({ isLoading: props.isLoading })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className='w-full h-fit bg-white/5' title={'Available vaults'}>
|
<Card className='w-full h-fit bg-white/5' title={'Available vaults'}>
|
||||||
<Table columns={columns} data={props.data} initialSorting={[{ id: 'name', desc: true }]} />
|
<Table columns={columns} data={props.data} initialSorting={[{ id: 'name', desc: true }]} />
|
||||||
|
@ -3,6 +3,8 @@ import React from 'react'
|
|||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
|
|
||||||
|
export const APY_META = { accessorKey: 'apy', header: 'APY' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault | DepositedVault
|
vault: Vault | DepositedVault
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import TitleAndSubCell from 'components/TitleAndSubCell'
|
|||||||
import { VAULT_DEPOSIT_BUFFER } from 'constants/vaults'
|
import { VAULT_DEPOSIT_BUFFER } from 'constants/vaults'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
|
|
||||||
|
export const DEPOSIT_CAP_META = { accessorKey: 'cap', header: 'Deposit Cap' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault | DepositedVault
|
vault: Vault | DepositedVault
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
|
@ -4,6 +4,8 @@ import React from 'react'
|
|||||||
import { ChevronDown } from 'components/Icons'
|
import { ChevronDown } from 'components/Icons'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
|
|
||||||
|
export const DETAILS_META = { accessorKey: 'details', enableSorting: false, header: 'Deposit' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
isExpanded: boolean
|
isExpanded: boolean
|
||||||
|
@ -3,6 +3,8 @@ import React from 'react'
|
|||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
|
|
||||||
|
export const LTV_MAX_META = { accessorKey: 'ltv.max', header: 'Max LTV' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault | DepositedVault
|
vault: Vault | DepositedVault
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
|
@ -7,6 +7,7 @@ import TitleAndSubCell from 'components/TitleAndSubCell'
|
|||||||
import { VaultStatus } from 'types/enums/vault'
|
import { VaultStatus } from 'types/enums/vault'
|
||||||
import { produceCountdown } from 'utils/formatters'
|
import { produceCountdown } from 'utils/formatters'
|
||||||
|
|
||||||
|
export const NAME_META = { header: 'Vault', accessorKey: 'name' }
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault | DepositedVault
|
vault: Vault | DepositedVault
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,10 @@ import DisplayCurrency from 'components/DisplayCurrency'
|
|||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
|
export const POSITION_VALUE_META = {
|
||||||
|
header: 'Pos. Value',
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: DepositedVault
|
vault: DepositedVault
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
|
@ -4,6 +4,8 @@ import DisplayCurrency from 'components/DisplayCurrency'
|
|||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
|
export const TVL_META = { accessorKey: 'tvl', header: 'TVL' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault | DepositedVault
|
vault: Vault | DepositedVault
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { ColumnDef } from '@tanstack/react-table'
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
|
|
||||||
import Apy from 'components/Earn/Farm/Table/Columns/Apy'
|
import Apy, { APY_META } from 'components/Earn/Farm/Table/Columns/Apy'
|
||||||
import { Deposit } from 'components/Earn/Farm/Table/Columns/Deposit'
|
import { Deposit } from 'components/Earn/Farm/Table/Columns/Deposit'
|
||||||
import DepositCap from 'components/Earn/Farm/Table/Columns/DepositCap'
|
import DepositCap, { DEPOSIT_CAP_META } from 'components/Earn/Farm/Table/Columns/DepositCap'
|
||||||
import MaxLTV from 'components/Earn/Farm/Table/Columns/MaxLTV'
|
import MaxLTV, { LTV_MAX_META } from 'components/Earn/Farm/Table/Columns/MaxLTV'
|
||||||
import Name from 'components/Earn/Farm/Table/Columns/Name'
|
import Name, { NAME_META } from 'components/Earn/Farm/Table/Columns/Name'
|
||||||
import TVL from 'components/Earn/Farm/Table/Columns/TVL'
|
import TVL, { TVL_META } from 'components/Earn/Farm/Table/Columns/TVL'
|
||||||
|
|
||||||
|
import { DETAILS_META } from './Details'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
@ -16,34 +18,27 @@ export default function useAvailableColumns(props: Props) {
|
|||||||
return useMemo<ColumnDef<Vault | DepositedVault>[]>(() => {
|
return useMemo<ColumnDef<Vault | DepositedVault>[]>(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
header: 'Vault',
|
...NAME_META,
|
||||||
accessorKey: 'name',
|
|
||||||
cell: ({ row }) => <Name vault={row.original as Vault} />,
|
cell: ({ row }) => <Name vault={row.original as Vault} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'apy',
|
...APY_META,
|
||||||
header: 'APY',
|
|
||||||
cell: ({ row }) => <Apy vault={row.original as Vault} />,
|
cell: ({ row }) => <Apy vault={row.original as Vault} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'tvl',
|
...TVL_META,
|
||||||
header: 'TVL',
|
|
||||||
cell: ({ row }) => <TVL vault={row.original as Vault} isLoading={props.isLoading} />,
|
cell: ({ row }) => <TVL vault={row.original as Vault} isLoading={props.isLoading} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'cap',
|
...DEPOSIT_CAP_META,
|
||||||
header: 'Deposit Cap',
|
|
||||||
cell: ({ row }) => <DepositCap vault={row.original as Vault} isLoading={props.isLoading} />,
|
cell: ({ row }) => <DepositCap vault={row.original as Vault} isLoading={props.isLoading} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'ltv.max',
|
...LTV_MAX_META,
|
||||||
header: 'Max LTV',
|
|
||||||
cell: ({ row }) => <MaxLTV vault={row.original as Vault} isLoading={props.isLoading} />,
|
cell: ({ row }) => <MaxLTV vault={row.original as Vault} isLoading={props.isLoading} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'details',
|
...DETAILS_META,
|
||||||
enableSorting: false,
|
|
||||||
header: 'Deposit',
|
|
||||||
cell: ({ row }) => <Deposit vault={row.original as Vault} isLoading={props.isLoading} />,
|
cell: ({ row }) => <Deposit vault={row.original as Vault} isLoading={props.isLoading} />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { ColumnDef, Row } from '@tanstack/react-table'
|
import { ColumnDef, Row } from '@tanstack/react-table'
|
||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
|
|
||||||
import Apy from 'components/Earn/Farm/Table/Columns/Apy'
|
import Apy, { APY_META } from 'components/Earn/Farm/Table/Columns/Apy'
|
||||||
import DepositCap from 'components/Earn/Farm/Table/Columns/DepositCap'
|
import DepositCap, { DEPOSIT_CAP_META } from 'components/Earn/Farm/Table/Columns/DepositCap'
|
||||||
import Details from 'components/Earn/Farm/Table/Columns/Details'
|
import Details, { DETAILS_META } from 'components/Earn/Farm/Table/Columns/Details'
|
||||||
import MaxLTV from 'components/Earn/Farm/Table/Columns/MaxLTV'
|
import MaxLTV, { LTV_MAX_META } from 'components/Earn/Farm/Table/Columns/MaxLTV'
|
||||||
import Name from 'components/Earn/Farm/Table/Columns/Name'
|
import Name, { NAME_META } from 'components/Earn/Farm/Table/Columns/Name'
|
||||||
import PositionValue from 'components/Earn/Farm/Table/Columns/PositionValue'
|
import PositionValue, {
|
||||||
import TVL from 'components/Earn/Farm/Table/Columns/TVL'
|
POSITION_VALUE_META,
|
||||||
|
} from 'components/Earn/Farm/Table/Columns/PositionValue'
|
||||||
|
import TVL, { TVL_META } from 'components/Earn/Farm/Table/Columns/TVL'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
@ -17,46 +19,39 @@ export default function useDepositedColumns(props: Props) {
|
|||||||
return useMemo<ColumnDef<DepositedVault>[]>(() => {
|
return useMemo<ColumnDef<DepositedVault>[]>(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
header: 'Vault',
|
...NAME_META,
|
||||||
accessorKey: 'name',
|
|
||||||
cell: ({ row }) => <Name vault={row.original as DepositedVault} />,
|
cell: ({ row }) => <Name vault={row.original as DepositedVault} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Pos. Value',
|
...POSITION_VALUE_META,
|
||||||
cell: ({ row }: { row: Row<DepositedVault> }) => (
|
cell: ({ row }: { row: Row<DepositedVault> }) => (
|
||||||
<PositionValue vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
<PositionValue vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'apy',
|
...APY_META,
|
||||||
header: 'APY',
|
|
||||||
cell: ({ row }) => <Apy vault={row.original as DepositedVault} />,
|
cell: ({ row }) => <Apy vault={row.original as DepositedVault} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'tvl',
|
...TVL_META,
|
||||||
header: 'TVL',
|
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<TVL vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
<TVL vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'cap',
|
...DEPOSIT_CAP_META,
|
||||||
header: 'Deposit Cap',
|
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<DepositCap vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
<DepositCap vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'ltv.max',
|
...LTV_MAX_META,
|
||||||
header: 'Max LTV',
|
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<MaxLTV vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
<MaxLTV vault={row.original as DepositedVault} isLoading={props.isLoading} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'details',
|
...DETAILS_META,
|
||||||
enableSorting: false,
|
|
||||||
header: 'Details',
|
|
||||||
cell: ({ row }) => <Details isLoading={props.isLoading} isExpanded={row.getIsExpanded()} />,
|
cell: ({ row }) => <Details isLoading={props.isLoading} isExpanded={row.getIsExpanded()} />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import React from 'react'
|
import { Row } from '@tanstack/react-table'
|
||||||
|
import { Table as TanStackTable } from '@tanstack/table-core/build/lib/types'
|
||||||
|
import React, { useCallback } from 'react'
|
||||||
|
|
||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
import useDepositedColumns from 'components/Earn/Farm/Table/Columns/useDepositedColumns'
|
import useDepositedColumns from 'components/Earn/Farm/Table/Columns/useDepositedColumns'
|
||||||
|
import VaultExpanded from 'components/Earn/Farm/VaultExpanded'
|
||||||
import Table from 'components/Table'
|
import Table from 'components/Table'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -11,9 +14,22 @@ type Props = {
|
|||||||
|
|
||||||
export default function DepositedVaultsTable(props: Props) {
|
export default function DepositedVaultsTable(props: Props) {
|
||||||
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
||||||
|
|
||||||
|
const renderExpanded = useCallback(
|
||||||
|
(row: Row<DepositedVault>, table: TanStackTable<DepositedVault>) => (
|
||||||
|
<VaultExpanded row={row} resetExpanded={table.resetExpanded} />
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className='w-full h-fit bg-white/5' title={'Deposited vaults'}>
|
<Card className='w-full h-fit bg-white/5' title={'Deposited vaults'}>
|
||||||
<Table columns={columns} data={props.data} initialSorting={[{ id: 'name', desc: true }]} />
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
data={props.data}
|
||||||
|
initialSorting={[{ id: 'name', desc: true }]}
|
||||||
|
renderExpanded={renderExpanded}
|
||||||
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,12 @@ import useStore from 'store'
|
|||||||
import { VaultStatus } from 'types/enums/vault'
|
import { VaultStatus } from 'types/enums/vault'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
row: Row<Vault | DepositedVault>
|
row: Row<DepositedVault>
|
||||||
resetExpanded: (defaultState?: boolean | undefined) => void
|
resetExpanded: (defaultState?: boolean | undefined) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function VaultExpanded(props: Props) {
|
export default function VaultExpanded(props: Props) {
|
||||||
const vault = props.row.original as DepositedVault
|
const vault = props.row.original
|
||||||
const accountId = useAccountId()
|
const accountId = useAccountId()
|
||||||
const [isConfirming, setIsConfirming] = useState(false)
|
const [isConfirming, setIsConfirming] = useState(false)
|
||||||
const withdrawFromVaults = useStore((s) => s.withdrawFromVaults)
|
const withdrawFromVaults = useStore((s) => s.withdrawFromVaults)
|
||||||
@ -113,7 +113,7 @@ export default function VaultExpanded(props: Props) {
|
|||||||
!isExpanded && props.row.toggleExpanded()
|
!isExpanded && props.row.toggleExpanded()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<td colSpan={!status ? 7 : 8}>
|
<td colSpan={props.row.getAllCells().length}>
|
||||||
<div className='flex justify-end gap-3 p-4 align-center'>
|
<div className='flex justify-end gap-3 p-4 align-center'>
|
||||||
{status && <DepositMoreButton />}
|
{status && <DepositMoreButton />}
|
||||||
{status === VaultStatus.ACTIVE && <UnlockButton />}
|
{status === VaultStatus.ACTIVE && <UnlockButton />}
|
||||||
|
@ -1,142 +0,0 @@
|
|||||||
import { ColumnDef, Row, Table } from '@tanstack/react-table'
|
|
||||||
import { useCallback, useMemo } from 'react'
|
|
||||||
|
|
||||||
import AmountAndValue from 'components/AmountAndValue'
|
|
||||||
import AssetImage from 'components/Asset/AssetImage'
|
|
||||||
import AssetRate from 'components/Asset/AssetRate'
|
|
||||||
import LendingActionButtons from 'components/Earn/Lend/LendingActionButtons'
|
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
|
||||||
import { ChevronDown, ChevronUp } from 'components/Icons'
|
|
||||||
import AssetListTable from 'components/MarketAssetTable'
|
|
||||||
import MarketAssetTableRow from 'components/MarketAssetTable/MarketAssetTableRow'
|
|
||||||
import MarketDetails from 'components/MarketAssetTable/MarketDetails'
|
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
import { convertLiquidityRateToAPR } from 'utils/formatters'
|
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
title: string
|
|
||||||
data: LendingMarketTableData[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function LendingMarketsTable(props: Props) {
|
|
||||||
const { title, data } = props
|
|
||||||
const shouldShowAccountDeposit = !!data[0]?.accountLentValue
|
|
||||||
|
|
||||||
const rowRenderer = useCallback(
|
|
||||||
(row: Row<LendingMarketTableData>, table: Table<LendingMarketTableData>) => {
|
|
||||||
return (
|
|
||||||
<MarketAssetTableRow
|
|
||||||
key={`lend-asset-${row.id}`}
|
|
||||||
isExpanded={row.getIsExpanded()}
|
|
||||||
resetExpanded={table.resetExpanded}
|
|
||||||
rowData={row}
|
|
||||||
expandedActionButtons={<LendingActionButtons data={row.original} />}
|
|
||||||
expandedDetails={<MarketDetails data={row.original} type='lend' />}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
|
|
||||||
const columns = useMemo<ColumnDef<LendingMarketTableData>[]>(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
accessorKey: 'asset.name',
|
|
||||||
header: 'Asset',
|
|
||||||
id: 'symbol',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const asset = row.original.asset
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='flex items-center flex-1 gap-3'>
|
|
||||||
<AssetImage asset={asset} size={32} />
|
|
||||||
<TitleAndSubCell
|
|
||||||
title={asset.symbol}
|
|
||||||
sub={asset.name}
|
|
||||||
className='text-left min-w-15'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
...(shouldShowAccountDeposit
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
accessorKey: 'accountDepositValue',
|
|
||||||
header: 'Deposited',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const amount = row.original.accountLentAmount
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AmountAndValue
|
|
||||||
asset={row.original.asset}
|
|
||||||
amount={amount ? BN(amount) : BN_ZERO}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
} as ColumnDef<LendingMarketTableData>,
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
{
|
|
||||||
accessorKey: 'marketLiquidityRate',
|
|
||||||
header: 'APR',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
return (
|
|
||||||
<AssetRate
|
|
||||||
rate={convertLiquidityRateToAPR(row.original.marketLiquidityRate)}
|
|
||||||
isEnabled={row.original.borrowEnabled}
|
|
||||||
className='justify-end text-xs'
|
|
||||||
type='apr'
|
|
||||||
orientation='ltr'
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'marketDepositCap',
|
|
||||||
header: 'Depo. Cap',
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const { marketDepositCap, marketDepositAmount, asset } = row.original
|
|
||||||
const percent = marketDepositAmount
|
|
||||||
.dividedBy(row.original.marketDepositCap)
|
|
||||||
.multipliedBy(100)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TitleAndSubCell
|
|
||||||
className='text-xs'
|
|
||||||
title={
|
|
||||||
<FormattedNumber
|
|
||||||
amount={marketDepositCap.toNumber()}
|
|
||||||
options={{ abbreviated: true, decimals: asset.decimals }}
|
|
||||||
animate
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
sub={
|
|
||||||
<FormattedNumber
|
|
||||||
amount={percent.toNumber()}
|
|
||||||
options={{ minDecimals: 2, maxDecimals: 2, suffix: '% used' }}
|
|
||||||
animate
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'manage',
|
|
||||||
enableSorting: false,
|
|
||||||
header: 'Manage',
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<div className='flex items-center justify-end'>
|
|
||||||
<div className='w-4'>{row.getIsExpanded() ? <ChevronUp /> : <ChevronDown />}</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[shouldShowAccountDeposit],
|
|
||||||
)
|
|
||||||
|
|
||||||
return <AssetListTable title={title} rowRenderer={rowRenderer} columns={columns} data={data} />
|
|
||||||
}
|
|
37
src/components/Earn/Lend/Lends.tsx
Normal file
37
src/components/Earn/Lend/Lends.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AvailableLendsTable from 'components/Earn/Lend/Table/AvailableLendsTable'
|
||||||
|
import DepositedLendsTable from 'components/Earn/Lend/Table/DepositedLendsTable'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
|
import { getLendEnabledAssets } from 'utils/assets'
|
||||||
|
|
||||||
|
export default function Lends() {
|
||||||
|
const { accountLentAssets, availableAssets, allAssets } = useLendingMarketAssetsTableData()
|
||||||
|
|
||||||
|
if (!allAssets?.length) {
|
||||||
|
return <Fallback />
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DepositedLendsTable data={accountLentAssets} isLoading={false} />
|
||||||
|
<AvailableLendsTable data={availableAssets} isLoading={false} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Fallback() {
|
||||||
|
const assets = getLendEnabledAssets()
|
||||||
|
const data: LendingMarketTableData[] = assets.map((asset) => ({
|
||||||
|
asset,
|
||||||
|
marketDepositCap: BN_ZERO,
|
||||||
|
borrowEnabled: false,
|
||||||
|
marketMaxLtv: 0,
|
||||||
|
marketDepositAmount: BN_ZERO,
|
||||||
|
marketLiquidityRate: 0,
|
||||||
|
marketLiquidityAmount: BN_ZERO,
|
||||||
|
marketLiquidationThreshold: 0,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return <AvailableLendsTable data={data} isLoading />
|
||||||
|
}
|
36
src/components/Earn/Lend/Table/AvailableLendsTable.tsx
Normal file
36
src/components/Earn/Lend/Table/AvailableLendsTable.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Row } from '@tanstack/react-table'
|
||||||
|
import React, { useCallback } from 'react'
|
||||||
|
|
||||||
|
import Card from 'components/Card'
|
||||||
|
import { NAME_META } from 'components/Earn/Lend/Table/Columns/Name'
|
||||||
|
import useAvailableColumns from 'components/Earn/Lend/Table/Columns/useAvailableColumns'
|
||||||
|
import Table from 'components/Table'
|
||||||
|
|
||||||
|
import MarketDetails from '../../../MarketDetails'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: LendingMarketTableData[]
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AvailableLendsTable(props: Props) {
|
||||||
|
const columns = useAvailableColumns({ isLoading: props.isLoading })
|
||||||
|
|
||||||
|
const renderExpanded = useCallback(
|
||||||
|
(row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='lend' />,
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!props.data.length) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className='w-full h-fit bg-white/5' title={'Available Markets'}>
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
data={props.data}
|
||||||
|
initialSorting={[{ id: NAME_META.id, desc: true }]}
|
||||||
|
renderExpanded={renderExpanded}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
26
src/components/Earn/Lend/Table/Columns/Apr.tsx
Normal file
26
src/components/Earn/Lend/Table/Columns/Apr.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AssetRate from 'components/Asset/AssetRate'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import { convertLiquidityRateToAPR } from 'utils/formatters'
|
||||||
|
|
||||||
|
export const APR_META = { accessorKey: 'marketLiquidityRate', header: 'APR' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
marketLiquidityRate: number
|
||||||
|
borrowEnabled: boolean
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
export default function Apr(props: Props) {
|
||||||
|
if (props.isLoading) return <Loading />
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AssetRate
|
||||||
|
rate={convertLiquidityRateToAPR(props.marketLiquidityRate)}
|
||||||
|
isEnabled={props.borrowEnabled}
|
||||||
|
className='justify-end text-xs'
|
||||||
|
type='apr'
|
||||||
|
orientation='ltr'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
37
src/components/Earn/Lend/Table/Columns/DepositCap.tsx
Normal file
37
src/components/Earn/Lend/Table/Columns/DepositCap.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
|
|
||||||
|
export const DEPOSIT_CAP_META = { accessorKey: 'marketDepositCap', header: 'Depo. Cap' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isLoading: boolean
|
||||||
|
data: LendingMarketTableData
|
||||||
|
}
|
||||||
|
export default function DepositCap(props: Props) {
|
||||||
|
if (props.isLoading) return <Loading />
|
||||||
|
const { marketDepositCap, marketDepositAmount, asset } = props.data
|
||||||
|
const percent = marketDepositAmount.dividedBy(marketDepositCap).multipliedBy(100)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TitleAndSubCell
|
||||||
|
className='text-xs'
|
||||||
|
title={
|
||||||
|
<FormattedNumber
|
||||||
|
amount={marketDepositCap.toNumber()}
|
||||||
|
options={{ abbreviated: true, decimals: asset.decimals }}
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
sub={
|
||||||
|
<FormattedNumber
|
||||||
|
amount={percent.toNumber()}
|
||||||
|
options={{ minDecimals: 2, maxDecimals: 2, suffix: '% used' }}
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
20
src/components/Earn/Lend/Table/Columns/DepositValue.tsx
Normal file
20
src/components/Earn/Lend/Table/Columns/DepositValue.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AmountAndValue from 'components/AmountAndValue'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
|
export const DEPOSIT_VALUE_META = { accessorKey: 'accountDepositValue', header: 'Deposited' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
asset: Asset
|
||||||
|
lentAmount?: string
|
||||||
|
}
|
||||||
|
export default function DepositValue(props: Props) {
|
||||||
|
return (
|
||||||
|
<AmountAndValue
|
||||||
|
asset={props.asset}
|
||||||
|
amount={props.lentAmount ? BN(props.lentAmount) : BN_ZERO}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
16
src/components/Earn/Lend/Table/Columns/Manage.tsx
Normal file
16
src/components/Earn/Lend/Table/Columns/Manage.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { ChevronDown, ChevronUp } from 'components/Icons'
|
||||||
|
|
||||||
|
export const MANAGE_META = { accessorKey: 'manage', enableSorting: false, header: 'Manage' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isExpanded: boolean
|
||||||
|
}
|
||||||
|
export default function Manage(props: Props) {
|
||||||
|
return (
|
||||||
|
<div className='flex items-center justify-end'>
|
||||||
|
<div className='w-4'>{props.isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
18
src/components/Earn/Lend/Table/Columns/Name.tsx
Normal file
18
src/components/Earn/Lend/Table/Columns/Name.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import AssetImage from 'components/Asset/AssetImage'
|
||||||
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
|
|
||||||
|
export const NAME_META = { accessorKey: 'asset.name', header: 'Asset', id: 'symbol' }
|
||||||
|
interface Props {
|
||||||
|
asset: Asset
|
||||||
|
}
|
||||||
|
export default function Name(props: Props) {
|
||||||
|
const { asset } = props
|
||||||
|
return (
|
||||||
|
<div className='flex items-center flex-1 gap-3'>
|
||||||
|
<AssetImage asset={asset} size={32} />
|
||||||
|
<TitleAndSubCell title={asset.symbol} sub={asset.name} className='text-left min-w-15' />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import Apr, { APR_META } from 'components/Earn/Lend/Table/Columns/Apr'
|
||||||
|
import DepositCap, { DEPOSIT_CAP_META } from 'components/Earn/Lend/Table/Columns/DepositCap'
|
||||||
|
import Manage, { MANAGE_META } from 'components/Earn/Lend/Table/Columns/Manage'
|
||||||
|
import Name, { NAME_META } from 'components/Earn/Lend/Table/Columns/Name'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useAvailableColumns(props: Props) {
|
||||||
|
return useMemo<ColumnDef<LendingMarketTableData>[]>(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...NAME_META,
|
||||||
|
cell: ({ row }) => <Name asset={row.original.asset} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...APR_META,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<Apr
|
||||||
|
isLoading={props.isLoading}
|
||||||
|
borrowEnabled={row.original.borrowEnabled}
|
||||||
|
marketLiquidityRate={row.original.marketLiquidityRate}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...DEPOSIT_CAP_META,
|
||||||
|
cell: ({ row }) => <DepositCap isLoading={props.isLoading} data={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...MANAGE_META,
|
||||||
|
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [])
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import Apr, { APR_META } from 'components/Earn/Lend/Table/Columns/Apr'
|
||||||
|
import DepositCap, { DEPOSIT_CAP_META } from 'components/Earn/Lend/Table/Columns/DepositCap'
|
||||||
|
import DepositValue, { DEPOSIT_VALUE_META } from 'components/Earn/Lend/Table/Columns/DepositValue'
|
||||||
|
import Manage, { MANAGE_META } from 'components/Earn/Lend/Table/Columns/Manage'
|
||||||
|
import Name, { NAME_META } from 'components/Earn/Lend/Table/Columns/Name'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useDepositedColumns(props: Props) {
|
||||||
|
return useMemo<ColumnDef<LendingMarketTableData>[]>(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...NAME_META,
|
||||||
|
cell: ({ row }) => <Name asset={row.original.asset} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...DEPOSIT_VALUE_META,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<DepositValue asset={row.original.asset} lentAmount={row.original.accountLentAmount} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...APR_META,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<Apr
|
||||||
|
isLoading={props.isLoading}
|
||||||
|
borrowEnabled={row.original.borrowEnabled}
|
||||||
|
marketLiquidityRate={row.original.marketLiquidityRate}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...DEPOSIT_CAP_META,
|
||||||
|
cell: ({ row }) => <DepositCap isLoading={props.isLoading} data={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...MANAGE_META,
|
||||||
|
cell: ({ row }) => <Manage isExpanded={row.getIsExpanded()} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [])
|
||||||
|
}
|
35
src/components/Earn/Lend/Table/DepositedLendsTable.tsx
Normal file
35
src/components/Earn/Lend/Table/DepositedLendsTable.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Row } from '@tanstack/react-table'
|
||||||
|
import React, { useCallback } from 'react'
|
||||||
|
|
||||||
|
import Card from 'components/Card'
|
||||||
|
import { NAME_META } from 'components/Earn/Lend/Table/Columns/Name'
|
||||||
|
import useDepositedColumns from 'components/Earn/Lend/Table/Columns/useDepositedColumns'
|
||||||
|
import MarketDetails from 'components/MarketDetails'
|
||||||
|
import Table from 'components/Table'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: LendingMarketTableData[]
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DepositedLendsTable(props: Props) {
|
||||||
|
const columns = useDepositedColumns({ isLoading: props.isLoading })
|
||||||
|
|
||||||
|
const renderExpanded = useCallback(
|
||||||
|
(row: Row<LendingMarketTableData>) => <MarketDetails row={row} type='borrow' />,
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!props.data.length) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className='w-full h-fit bg-white/5' title={'Lent Assets'}>
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
data={props.data}
|
||||||
|
initialSorting={[{ id: NAME_META.id, desc: true }]}
|
||||||
|
renderExpanded={renderExpanded}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
@ -1,73 +0,0 @@
|
|||||||
import { flexRender, Row } from '@tanstack/react-table'
|
|
||||||
import classNames from 'classnames'
|
|
||||||
|
|
||||||
import Text from 'components/Text'
|
|
||||||
|
|
||||||
type Props<TData> = {
|
|
||||||
rowData: Row<TData>
|
|
||||||
resetExpanded: (defaultState?: boolean | undefined) => void
|
|
||||||
isExpanded: boolean
|
|
||||||
expandedActionButtons?: JSX.Element
|
|
||||||
expandedDetails?: JSX.Element
|
|
||||||
}
|
|
||||||
|
|
||||||
function AssetListTableRow<TData>(props: Props<TData>) {
|
|
||||||
const renderFullRow = (key: string, content: JSX.Element) => (
|
|
||||||
<tr key={key} className='bg-black/20'>
|
|
||||||
<td
|
|
||||||
className='border-b border-white border-opacity-10 p-4'
|
|
||||||
colSpan={props.rowData.getAllCells().length}
|
|
||||||
>
|
|
||||||
{content}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
|
|
||||||
const renderExpanded = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{props.expandedActionButtons &&
|
|
||||||
renderFullRow(
|
|
||||||
`${props.rowData.id}-expanded-actions`,
|
|
||||||
<div className='flex flex-1 flex-row justify-between'>
|
|
||||||
<Text className='mt-1 flex p-0 font-bold' size='base'>
|
|
||||||
Details
|
|
||||||
</Text>
|
|
||||||
<div>{props.expandedActionButtons}</div>
|
|
||||||
</div>,
|
|
||||||
)}
|
|
||||||
{props.expandedDetails &&
|
|
||||||
renderFullRow(`${props.rowData.id}-expanded-details`, props.expandedDetails)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<tr
|
|
||||||
key={props.rowData.id}
|
|
||||||
className={classNames(
|
|
||||||
'hover:cursor-pointer transition-colors',
|
|
||||||
|
|
||||||
props.rowData.getIsExpanded() ? 'bg-black/20' : 'bg-white/0 hover:bg-white/5',
|
|
||||||
)}
|
|
||||||
onClick={() => {
|
|
||||||
const isExpanded = props.rowData.getIsExpanded()
|
|
||||||
props.resetExpanded()
|
|
||||||
!isExpanded && props.rowData.toggleExpanded()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.rowData.getVisibleCells().map((cell) => {
|
|
||||||
return (
|
|
||||||
<td key={cell.id} className={'p-4 text-right'}>
|
|
||||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
||||||
</td>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</tr>
|
|
||||||
{props.isExpanded && renderExpanded()}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AssetListTableRow
|
|
@ -1,102 +0,0 @@
|
|||||||
import {
|
|
||||||
ColumnDef,
|
|
||||||
flexRender,
|
|
||||||
getCoreRowModel,
|
|
||||||
getSortedRowModel,
|
|
||||||
Row,
|
|
||||||
SortingState,
|
|
||||||
Table,
|
|
||||||
useReactTable,
|
|
||||||
} from '@tanstack/react-table'
|
|
||||||
import classNames from 'classnames'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import Card from 'components/Card'
|
|
||||||
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
|
||||||
import Text from 'components/Text'
|
|
||||||
|
|
||||||
interface Props<TData> {
|
|
||||||
title: string
|
|
||||||
data: TData[]
|
|
||||||
columns: ColumnDef<TData>[]
|
|
||||||
sorting?: SortingState
|
|
||||||
rowRenderer: (row: Row<TData>, table: Table<TData>) => JSX.Element
|
|
||||||
}
|
|
||||||
|
|
||||||
function AssetListTable<TData>(props: Props<TData>) {
|
|
||||||
const { title, data, columns } = props
|
|
||||||
const [sorting, setSorting] = React.useState<SortingState>(props.sorting ?? [])
|
|
||||||
|
|
||||||
const table = useReactTable({
|
|
||||||
data,
|
|
||||||
columns,
|
|
||||||
state: {
|
|
||||||
sorting,
|
|
||||||
},
|
|
||||||
onSortingChange: setSorting,
|
|
||||||
getCoreRowModel: getCoreRowModel(),
|
|
||||||
getSortedRowModel: getSortedRowModel(),
|
|
||||||
})
|
|
||||||
|
|
||||||
const _rowRenderer = (row: Row<TData>) => props.rowRenderer(row, table)
|
|
||||||
|
|
||||||
if (!data.length) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card className='mb-4 h-fit w-full bg-white/5' title={title}>
|
|
||||||
<table className='w-full'>
|
|
||||||
<thead className='border-b border-white border-opacity-10 bg-black/20'>
|
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
|
||||||
<tr key={headerGroup.id}>
|
|
||||||
{headerGroup.headers.map((header) => {
|
|
||||||
return (
|
|
||||||
<th
|
|
||||||
key={header.id}
|
|
||||||
onClick={header.column.getToggleSortingHandler()}
|
|
||||||
className={classNames(
|
|
||||||
'px-4 py-3',
|
|
||||||
header.column.getCanSort() && 'hover:cursor-pointer',
|
|
||||||
header.id === 'symbol' ? 'text-left' : 'text-right',
|
|
||||||
{
|
|
||||||
'w-32': header.id === 'manage',
|
|
||||||
'w-48': header.id === 'depositCap',
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'flex',
|
|
||||||
header.id === 'symbol' ? 'justify-start' : 'justify-end',
|
|
||||||
'align-center',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className='h-6 w-6 text-white'>
|
|
||||||
{header.column.getCanSort()
|
|
||||||
? {
|
|
||||||
asc: <SortAsc />,
|
|
||||||
desc: <SortDesc />,
|
|
||||||
false: <SortNone />,
|
|
||||||
}[header.column.getIsSorted() as string] ?? null
|
|
||||||
: null}
|
|
||||||
</span>
|
|
||||||
<Text
|
|
||||||
tag='span'
|
|
||||||
size='xs'
|
|
||||||
className='flex items-center font-normal text-white/40'
|
|
||||||
>
|
|
||||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</thead>
|
|
||||||
<tbody>{table.getRowModel().rows.map(_rowRenderer)}</tbody>
|
|
||||||
</table>
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AssetListTable
|
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Row } from '@tanstack/react-table'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
@ -5,7 +6,7 @@ import TitleAndSubCell from 'components/TitleAndSubCell'
|
|||||||
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: BorrowMarketTableData | LendingMarketTableData
|
row: Row<BorrowMarketTableData | LendingMarketTableData>
|
||||||
type: 'borrow' | 'lend'
|
type: 'borrow' | 'lend'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ interface Detail {
|
|||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MarketDetails({ data, type }: Props) {
|
export default function MarketDetails({ row, type }: Props) {
|
||||||
const {
|
const {
|
||||||
convertAmount,
|
convertAmount,
|
||||||
getConversionRate,
|
getConversionRate,
|
||||||
@ -28,7 +29,7 @@ export default function MarketDetails({ data, type }: Props) {
|
|||||||
marketDepositAmount,
|
marketDepositAmount,
|
||||||
marketLiquidityAmount,
|
marketLiquidityAmount,
|
||||||
marketLiquidationThreshold,
|
marketLiquidationThreshold,
|
||||||
} = data
|
} = row.original
|
||||||
|
|
||||||
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
|
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
|
||||||
|
|
||||||
@ -36,7 +37,6 @@ export default function MarketDetails({ data, type }: Props) {
|
|||||||
const isDollar = displayCurrencySymbol === '$'
|
const isDollar = displayCurrencySymbol === '$'
|
||||||
|
|
||||||
function getLendingMarketDetails() {
|
function getLendingMarketDetails() {
|
||||||
const depositCap = (data as LendingMarketTableData).marketDepositCap
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
amount: convertAmount(asset, marketDepositAmount).toNumber(),
|
amount: convertAmount(asset, marketDepositAmount).toNumber(),
|
||||||
@ -107,7 +107,6 @@ export default function MarketDetails({ data, type }: Props) {
|
|||||||
if (type === 'lend') return getLendingMarketDetails()
|
if (type === 'lend') return getLendingMarketDetails()
|
||||||
return getBorrowMarketDetails()
|
return getBorrowMarketDetails()
|
||||||
}, [
|
}, [
|
||||||
data,
|
|
||||||
type,
|
type,
|
||||||
asset,
|
asset,
|
||||||
marketDepositAmount,
|
marketDepositAmount,
|
||||||
@ -120,23 +119,27 @@ export default function MarketDetails({ data, type }: Props) {
|
|||||||
])
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-between flex-1 bg-white rounded-md bg-opacity-5'>
|
<tr>
|
||||||
{details.map((detail, index) => (
|
<td colSpan={row.getAllCells().length}>
|
||||||
<TitleAndSubCell
|
<div className='flex justify-between flex-1 bg-white rounded-md bg-opacity-5'>
|
||||||
key={index}
|
{details.map((detail, index) => (
|
||||||
className='text-center'
|
<TitleAndSubCell
|
||||||
containerClassName='m-5 ml-10 mr-10 space-y-1'
|
key={index}
|
||||||
title={
|
className='text-center'
|
||||||
<FormattedNumber
|
containerClassName='m-5 ml-10 mr-10 space-y-1'
|
||||||
className='text-xs text-center'
|
title={
|
||||||
amount={detail.amount}
|
<FormattedNumber
|
||||||
options={detail.options}
|
className='text-xs text-center'
|
||||||
animate
|
amount={detail.amount}
|
||||||
|
options={detail.options}
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
sub={detail.title}
|
||||||
/>
|
/>
|
||||||
}
|
))}
|
||||||
sub={detail.title}
|
</div>
|
||||||
/>
|
</td>
|
||||||
))}
|
</tr>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import React, { Suspense } from 'react'
|
import React, { Suspense, useMemo } from 'react'
|
||||||
|
|
||||||
import AccountBalancesTable from 'components/Account/AccountBalancesTable'
|
import AccountBalancesTable from 'components/Account/AccountBalancesTable'
|
||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
@ -15,7 +15,8 @@ interface Props {
|
|||||||
function Content(props: Props) {
|
function Content(props: Props) {
|
||||||
const { data: account } = useAccount(props.accountId, true)
|
const { data: account } = useAccount(props.accountId, true)
|
||||||
|
|
||||||
const { allAssets: borrowAssets } = useBorrowMarketAssetsTableData()
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
|
const borrowAssets = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
||||||
|
|
||||||
if (!account || !borrowAssets.length || !lendingAssets.length) {
|
if (!account || !borrowAssets.length || !lendingAssets.length) {
|
||||||
|
@ -20,7 +20,8 @@ function Content(props: Props) {
|
|||||||
const { data: account } = useAccount(props.accountId, true)
|
const { data: account } = useAccount(props.accountId, true)
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const { health } = useHealthComputer(account)
|
const { health } = useHealthComputer(account)
|
||||||
const { allAssets: borrowAssets } = useBorrowMarketAssetsTableData()
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
|
const borrowAssets = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
||||||
|
|
||||||
const stats = useMemo(() => {
|
const stats = useMemo(() => {
|
||||||
|
@ -34,7 +34,8 @@ export default function PortfolioCard(props: Props) {
|
|||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const currentAccountId = useAccountId()
|
const currentAccountId = useAccountId()
|
||||||
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
||||||
const { allAssets: borrowAssets } = useBorrowMarketAssetsTableData()
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
|
const borrowAssets = useMemo(() => data?.allAssets || [], [data])
|
||||||
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
|
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@ export default function PortfolioSummary() {
|
|||||||
const { address: urlAddress } = useParams()
|
const { address: urlAddress } = useParams()
|
||||||
const walletAddress = useStore((s) => s.address)
|
const walletAddress = useStore((s) => s.address)
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const { allAssets: borrowAssets } = useBorrowMarketAssetsTableData()
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
|
const borrowAssets = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
|
||||||
const { data: accounts } = useAccounts(urlAddress || walletAddress)
|
const { data: accounts } = useAccounts(urlAddress || walletAddress)
|
||||||
|
|
||||||
|
42
src/components/Table/Row.tsx
Normal file
42
src/components/Table/Row.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { flexRender, Row as TanstackRow, Table as TanstackTable } from '@tanstack/react-table'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
interface Props<T> {
|
||||||
|
row: TanstackRow<T>
|
||||||
|
table: TanstackTable<T>
|
||||||
|
renderExpanded?: (row: TanstackRow<T>, table: TanstackTable<T>) => JSX.Element
|
||||||
|
rowClassName?: string
|
||||||
|
rowClickHandler?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Row<T>(props: Props<T>) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<tr
|
||||||
|
key={props.row.id}
|
||||||
|
className={classNames(
|
||||||
|
'bg-white/3 group/row border-b border-t border-white/5 transition-colors hover:bg-white/5',
|
||||||
|
props.renderExpanded && 'hover:cursor-pointer',
|
||||||
|
props.row.getIsExpanded() && 'is-expanded',
|
||||||
|
)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const isExpanded = props.row.getIsExpanded()
|
||||||
|
props.table.resetExpanded()
|
||||||
|
!isExpanded && props.row.toggleExpanded()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.row.getVisibleCells().map((cell) => {
|
||||||
|
return (
|
||||||
|
<td key={cell.id} className={'p-4 text-right'}>
|
||||||
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
|
</td>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
{props.row.getIsExpanded() &&
|
||||||
|
props.renderExpanded &&
|
||||||
|
props.renderExpanded(props.row, props.table)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -3,26 +3,26 @@ import {
|
|||||||
flexRender,
|
flexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
Row,
|
|
||||||
SortingState,
|
SortingState,
|
||||||
|
Row as TanstackRow,
|
||||||
|
Table as TanstackTable,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from '@tanstack/react-table'
|
} from '@tanstack/react-table'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import VaultExpanded from 'components/Earn/Farm/VaultExpanded'
|
|
||||||
import { VaultRow } from 'components/Earn/Farm/VaultRow'
|
|
||||||
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||||
|
import Row from 'components/Table/Row'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
|
||||||
import Text from '../Text'
|
interface Props<T> {
|
||||||
|
columns: ColumnDef<T>[]
|
||||||
interface Props {
|
data: T[]
|
||||||
columns: ColumnDef<any>[]
|
|
||||||
data: unknown[]
|
|
||||||
initialSorting: SortingState
|
initialSorting: SortingState
|
||||||
|
renderExpanded?: (row: TanstackRow<T>, table: TanstackTable<T>) => JSX.Element
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Table(props: Props) {
|
export default function Table<T>(props: Props<T>) {
|
||||||
const [sorting, setSorting] = React.useState<SortingState>(props.initialSorting)
|
const [sorting, setSorting] = React.useState<SortingState>(props.initialSorting)
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
@ -83,48 +83,10 @@ export default function Table(props: Props) {
|
|||||||
))}
|
))}
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{table.getRowModel().rows.map((row) => {
|
{table.getRowModel().rows.map((row) => (
|
||||||
if (row.getIsExpanded()) {
|
<Row key={row.id} row={row} table={table} renderExpanded={props.renderExpanded} />
|
||||||
return (
|
))}
|
||||||
<React.Fragment key={`${row.id}_subrow`}>
|
|
||||||
{getExpandedRowModel('farm', row, table.resetExpanded)}
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRowModel('farm', row, table.resetExpanded)
|
|
||||||
})}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExpandedRowModel(
|
|
||||||
type: 'farm',
|
|
||||||
row: unknown,
|
|
||||||
resetExpanded: (defaultState?: boolean | undefined) => void,
|
|
||||||
) {
|
|
||||||
switch (type) {
|
|
||||||
case 'farm':
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<VaultRow row={row as Row<Vault>} resetExpanded={resetExpanded} />
|
|
||||||
<VaultExpanded row={row as Row<Vault>} resetExpanded={resetExpanded} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRowModel(
|
|
||||||
type: 'farm',
|
|
||||||
row: Row<unknown>,
|
|
||||||
resetExpanded: (defaultState?: boolean | undefined) => void,
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<VaultRow
|
|
||||||
key={(row as Row<Vault>).original.address}
|
|
||||||
row={row as Row<Vault>}
|
|
||||||
resetExpanded={resetExpanded}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -8,14 +8,10 @@ import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableDa
|
|||||||
|
|
||||||
export default function AccountDetailsCard() {
|
export default function AccountDetailsCard() {
|
||||||
const account = useCurrentAccount()
|
const account = useCurrentAccount()
|
||||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
const { data } = useBorrowMarketAssetsTableData(false)
|
||||||
useBorrowMarketAssetsTableData()
|
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||||
useLendingMarketAssetsTableData()
|
useLendingMarketAssetsTableData()
|
||||||
const borrowAssetsData = useMemo(
|
|
||||||
() => [...borrowAvailableAssets, ...accountBorrowedAssets],
|
|
||||||
[borrowAvailableAssets, accountBorrowedAssets],
|
|
||||||
)
|
|
||||||
const lendingAssetsData = useMemo(
|
const lendingAssetsData = useMemo(
|
||||||
() => [...lendingAvailableAssets, ...accountLentAssets],
|
() => [...lendingAvailableAssets, ...accountLentAssets],
|
||||||
[lendingAvailableAssets, accountLentAssets],
|
[lendingAvailableAssets, accountLentAssets],
|
||||||
|
@ -17,6 +17,7 @@ export const ASSETS: Asset[] = [
|
|||||||
logo: '/images/tokens/osmo.svg',
|
logo: '/images/tokens/osmo.svg',
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
isMarket: true,
|
isMarket: true,
|
||||||
|
isBorrowEnabled: true,
|
||||||
isDisplayCurrency: true,
|
isDisplayCurrency: true,
|
||||||
isAutoLendEnabled: true,
|
isAutoLendEnabled: true,
|
||||||
pythPriceFeedId: '5867f5683c757393a0670ef0f701490950fe93fdb006d181c8265a831ac0c5c6',
|
pythPriceFeedId: '5867f5683c757393a0670ef0f701490950fe93fdb006d181c8265a831ac0c5c6',
|
||||||
@ -38,6 +39,7 @@ export const ASSETS: Asset[] = [
|
|||||||
isMarket: true,
|
isMarket: true,
|
||||||
isDisplayCurrency: true,
|
isDisplayCurrency: true,
|
||||||
isAutoLendEnabled: true,
|
isAutoLendEnabled: true,
|
||||||
|
isBorrowEnabled: true,
|
||||||
pythPriceFeedId: 'b00b60f88b03a6a625a8d1c048c3f66653edf217439983d037e7222c4e612819',
|
pythPriceFeedId: 'b00b60f88b03a6a625a8d1c048c3f66653edf217439983d037e7222c4e612819',
|
||||||
poolId: 1,
|
poolId: 1,
|
||||||
},
|
},
|
||||||
@ -71,6 +73,7 @@ export const ASSETS: Asset[] = [
|
|||||||
isMarket: ENV.NETWORK !== NETWORK.TESTNET,
|
isMarket: ENV.NETWORK !== NETWORK.TESTNET,
|
||||||
isDisplayCurrency: ENV.NETWORK !== NETWORK.TESTNET,
|
isDisplayCurrency: ENV.NETWORK !== NETWORK.TESTNET,
|
||||||
isAutoLendEnabled: true,
|
isAutoLendEnabled: true,
|
||||||
|
isBorrowEnabled: true,
|
||||||
pythPriceFeedId: 'e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
|
pythPriceFeedId: 'e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
|
||||||
poolId: 712,
|
poolId: 712,
|
||||||
},
|
},
|
||||||
@ -88,6 +91,7 @@ export const ASSETS: Asset[] = [
|
|||||||
isMarket: ENV.NETWORK !== NETWORK.TESTNET,
|
isMarket: ENV.NETWORK !== NETWORK.TESTNET,
|
||||||
isDisplayCurrency: ENV.NETWORK !== NETWORK.TESTNET,
|
isDisplayCurrency: ENV.NETWORK !== NETWORK.TESTNET,
|
||||||
isAutoLendEnabled: true,
|
isAutoLendEnabled: true,
|
||||||
|
isBorrowEnabled: true,
|
||||||
pythPriceFeedId: 'ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
|
pythPriceFeedId: 'ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
|
||||||
poolId: 704,
|
poolId: 704,
|
||||||
},
|
},
|
||||||
@ -126,6 +130,7 @@ export const ASSETS: Asset[] = [
|
|||||||
isMarket: true,
|
isMarket: true,
|
||||||
isDisplayCurrency: true,
|
isDisplayCurrency: true,
|
||||||
isStable: true,
|
isStable: true,
|
||||||
|
isBorrowEnabled: true,
|
||||||
isAutoLendEnabled: true,
|
isAutoLendEnabled: true,
|
||||||
pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a',
|
pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a',
|
||||||
poolId: 678,
|
poolId: 678,
|
||||||
|
6
src/hooks/useBorrowEnabledMarkets.ts
Normal file
6
src/hooks/useBorrowEnabledMarkets.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import useMarketAssets from 'hooks/useMarketAssets'
|
||||||
|
|
||||||
|
export default function useBorrowEnabledMarkets() {
|
||||||
|
const { data: markets } = useMarketAssets()
|
||||||
|
return markets.filter((market) => market.borrowEnabled)
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
import { useMemo } from 'react'
|
import useSWR from 'swr'
|
||||||
|
|
||||||
import useCurrentAccountDebts from 'hooks/useCurrentAccountDebts'
|
import useCurrentAccountDebts from 'hooks/useCurrentAccountDebts'
|
||||||
import useDepositEnabledMarkets from 'hooks/useDepositEnabledMarkets'
|
|
||||||
import useMarketBorrowings from 'hooks/useMarketBorrowings'
|
import useMarketBorrowings from 'hooks/useMarketBorrowings'
|
||||||
import useMarketDeposits from 'hooks/useMarketDeposits'
|
import useMarketDeposits from 'hooks/useMarketDeposits'
|
||||||
import useMarketLiquidities from 'hooks/useMarketLiquidities'
|
import useMarketLiquidities from 'hooks/useMarketLiquidities'
|
||||||
@ -9,47 +8,55 @@ import { byDenom } from 'utils/array'
|
|||||||
import { getAssetByDenom } from 'utils/assets'
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default function useBorrowMarketAssetsTableData(): {
|
import useBorrowEnabledMarkets from './useBorrowEnabledMarkets'
|
||||||
accountBorrowedAssets: BorrowMarketTableData[]
|
|
||||||
availableAssets: BorrowMarketTableData[]
|
export default function useBorrowMarketAssetsTableData(suspense = true) {
|
||||||
allAssets: BorrowMarketTableData[]
|
const markets = useBorrowEnabledMarkets()
|
||||||
} {
|
|
||||||
const markets = useDepositEnabledMarkets()
|
|
||||||
const accountDebts = useCurrentAccountDebts()
|
const accountDebts = useCurrentAccountDebts()
|
||||||
const { data: borrowData } = useMarketBorrowings()
|
const { data: borrowData } = useMarketBorrowings()
|
||||||
const { data: marketDeposits } = useMarketDeposits()
|
const { data: marketDeposits } = useMarketDeposits()
|
||||||
const { data: marketLiquidities } = useMarketLiquidities()
|
const { data: marketLiquidities } = useMarketLiquidities()
|
||||||
|
|
||||||
return useMemo(() => {
|
return useSWR(
|
||||||
const accountBorrowedAssets: BorrowMarketTableData[] = [],
|
'borrowMarketAssetsTableData',
|
||||||
availableAssets: BorrowMarketTableData[] = []
|
async (): Promise<{
|
||||||
|
accountBorrowedAssets: BorrowMarketTableData[]
|
||||||
|
availableAssets: BorrowMarketTableData[]
|
||||||
|
allAssets: BorrowMarketTableData[]
|
||||||
|
}> => {
|
||||||
|
const accountBorrowedAssets: BorrowMarketTableData[] = [],
|
||||||
|
availableAssets: BorrowMarketTableData[] = []
|
||||||
|
|
||||||
markets.forEach(({ denom, liquidityRate, liquidationThreshold, maxLtv }) => {
|
markets.forEach(({ denom, liquidityRate, liquidationThreshold, maxLtv }) => {
|
||||||
const asset = getAssetByDenom(denom) as Asset
|
const asset = getAssetByDenom(denom) as Asset
|
||||||
const borrow = borrowData.find((borrow) => borrow.denom === denom)
|
const borrow = borrowData.find((borrow) => borrow.denom === denom)
|
||||||
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
||||||
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
|
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
|
||||||
|
|
||||||
const debt = accountDebts?.find((debt) => debt.denom === denom)
|
const debt = accountDebts?.find((debt) => debt.denom === denom)
|
||||||
if (!borrow) return
|
if (!borrow) return
|
||||||
|
|
||||||
const borrowMarketAsset: BorrowMarketTableData = {
|
const borrowMarketAsset: BorrowMarketTableData = {
|
||||||
...borrow,
|
...borrow,
|
||||||
asset,
|
asset,
|
||||||
debt: debt?.amount,
|
debt: debt?.amount,
|
||||||
marketDepositAmount,
|
marketDepositAmount,
|
||||||
marketLiquidityAmount,
|
marketLiquidityAmount,
|
||||||
marketLiquidityRate: liquidityRate,
|
marketLiquidityRate: liquidityRate,
|
||||||
marketLiquidationThreshold: liquidationThreshold,
|
marketLiquidationThreshold: liquidationThreshold,
|
||||||
marketMaxLtv: maxLtv,
|
marketMaxLtv: maxLtv,
|
||||||
|
}
|
||||||
|
;(borrowMarketAsset.debt ? accountBorrowedAssets : availableAssets).push(borrowMarketAsset)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
accountBorrowedAssets,
|
||||||
|
availableAssets,
|
||||||
|
allAssets: [...accountBorrowedAssets, ...availableAssets],
|
||||||
}
|
}
|
||||||
;(borrowMarketAsset.debt ? accountBorrowedAssets : availableAssets).push(borrowMarketAsset)
|
},
|
||||||
})
|
{
|
||||||
|
suspense,
|
||||||
return {
|
},
|
||||||
accountBorrowedAssets,
|
)
|
||||||
availableAssets,
|
|
||||||
allAssets: [...accountBorrowedAssets, ...availableAssets],
|
|
||||||
}
|
|
||||||
}, [accountDebts, borrowData, markets, marketDeposits, marketLiquidities])
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
|
import Borrowings from 'components/Borrow/Borrowings'
|
||||||
import BorrowIntro from 'components/Borrow/BorrowIntro'
|
import BorrowIntro from 'components/Borrow/BorrowIntro'
|
||||||
import BorrowTable from 'components/Borrow/BorrowTable'
|
|
||||||
import MigrationBanner from 'components/MigrationBanner'
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
|
||||||
|
|
||||||
export default function BorrowPage() {
|
export default function BorrowPage() {
|
||||||
const { accountBorrowedAssets, availableAssets } = useBorrowMarketAssetsTableData()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-wrap w-full gap-6'>
|
<div className='flex flex-wrap w-full gap-6'>
|
||||||
<MigrationBanner />
|
<MigrationBanner />
|
||||||
<BorrowIntro />
|
<BorrowIntro />
|
||||||
<BorrowTable data={accountBorrowedAssets} title='Borrowed Assets' />
|
<Borrowings />
|
||||||
<BorrowTable data={availableAssets} title='Available to borrow' />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import LendingMarketsTable from 'components/Earn/Lend/LendingMarketsTable'
|
|
||||||
import LendIntro from 'components/Earn/Lend/LendIntro'
|
import LendIntro from 'components/Earn/Lend/LendIntro'
|
||||||
|
import Lends from 'components/Earn/Lend/Lends'
|
||||||
import Tab from 'components/Earn/Tab'
|
import Tab from 'components/Earn/Tab'
|
||||||
import MigrationBanner from 'components/MigrationBanner'
|
import MigrationBanner from 'components/MigrationBanner'
|
||||||
import { EARN_TABS } from 'constants/pages'
|
import { EARN_TABS } from 'constants/pages'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
|
||||||
|
|
||||||
export default function LendPage() {
|
export default function LendPage() {
|
||||||
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 />
|
<MigrationBanner />
|
||||||
<Tab tabs={EARN_TABS} activeTabIdx={0} />
|
<Tab tabs={EARN_TABS} activeTabIdx={0} />
|
||||||
<LendIntro />
|
<LendIntro />
|
||||||
<LendingMarketsTable data={accountLentAssets} title='Lent Assets' />
|
<Lends />
|
||||||
<LendingMarketsTable data={availableAssets} title='Available Markets' />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
1
src/types/interfaces/asset.d.ts
vendored
1
src/types/interfaces/asset.d.ts
vendored
@ -50,6 +50,7 @@ interface Asset {
|
|||||||
isStable?: boolean
|
isStable?: boolean
|
||||||
isFavorite?: boolean
|
isFavorite?: boolean
|
||||||
isAutoLendEnabled?: boolean
|
isAutoLendEnabled?: boolean
|
||||||
|
isBorrowEnabled?: boolean
|
||||||
pythPriceFeedId?: string
|
pythPriceFeedId?: string
|
||||||
forceFetchPrice?: boolean
|
forceFetchPrice?: boolean
|
||||||
testnetDenom?: string
|
testnetDenom?: string
|
||||||
|
@ -35,3 +35,7 @@ export function findCoinByDenom(denom: string, coins: BigNumberCoin[]) {
|
|||||||
export function getLendEnabledAssets() {
|
export function getLendEnabledAssets() {
|
||||||
return ASSETS.filter((asset) => asset.isAutoLendEnabled)
|
return ASSETS.filter((asset) => asset.isAutoLendEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBorrowEnabledAssets() {
|
||||||
|
return ASSETS.filter((asset) => asset.isBorrowEnabled)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user