diff --git a/centrifuge-app/src/components/PoolCard/styles.tsx b/centrifuge-app/src/components/ListItemCardStyles.tsx
similarity index 100%
rename from centrifuge-app/src/components/PoolCard/styles.tsx
rename to centrifuge-app/src/components/ListItemCardStyles.tsx
diff --git a/centrifuge-app/src/components/PoolCard/index.tsx b/centrifuge-app/src/components/PoolCard/index.tsx
index 6da4194d7d..0663d99afc 100644
--- a/centrifuge-app/src/components/PoolCard/index.tsx
+++ b/centrifuge-app/src/components/PoolCard/index.tsx
@@ -6,8 +6,8 @@ import { useRouteMatch } from 'react-router'
import { useTheme } from 'styled-components'
import { formatBalance, formatPercentage } from '../../utils/formatting'
import { Eththumbnail } from '../EthThumbnail'
+import { Anchor, Ellipsis, Root } from '../ListItemCardStyles'
import { PoolStatus, PoolStatusKey } from './PoolStatus'
-import { Anchor, Ellipsis, Root } from './styles'
const columns_base = 'minmax(150px, 2fr) minmax(100px, 1fr) 140px 70px 150px'
const columns_extended = 'minmax(200px, 2fr) minmax(100px, 1fr) 140px 100px 150px'
diff --git a/centrifuge-app/src/components/PoolFilter/config.ts b/centrifuge-app/src/components/PoolFilter/config.ts
index cf607b7f72..59389d913d 100644
--- a/centrifuge-app/src/components/PoolFilter/config.ts
+++ b/centrifuge-app/src/components/PoolFilter/config.ts
@@ -1,5 +1,5 @@
+import { SortButtonProps } from '../SortButton'
import { FilterMenuProps } from './FilterMenu'
-import { SortButtonProps } from './SortButton'
export const SEARCH_KEYS = {
SORT_BY: 'sort-by',
diff --git a/centrifuge-app/src/components/PoolFilter/index.tsx b/centrifuge-app/src/components/PoolFilter/index.tsx
index a3fc4d1ede..07da68fe63 100644
--- a/centrifuge-app/src/components/PoolFilter/index.tsx
+++ b/centrifuge-app/src/components/PoolFilter/index.tsx
@@ -1,9 +1,9 @@
import { Grid, Text } from '@centrifuge/fabric'
import * as React from 'react'
import { COLUMNS, COLUMN_GAPS, PoolCardProps } from '../PoolCard'
+import { SortButton } from '../SortButton'
import { poolFilterConfig } from './config'
import { FilterMenu } from './FilterMenu'
-import { SortButton } from './SortButton'
type PoolFilterProps = {
pools?: PoolCardProps[]
diff --git a/centrifuge-app/src/components/Portfolio/InvestedTokens.tsx b/centrifuge-app/src/components/Portfolio/InvestedTokens.tsx
index e953a29ce3..eb4edc32df 100644
--- a/centrifuge-app/src/components/Portfolio/InvestedTokens.tsx
+++ b/centrifuge-app/src/components/Portfolio/InvestedTokens.tsx
@@ -1,89 +1,70 @@
-import { AccountTokenBalance, Pool } from '@centrifuge/centrifuge-js'
-import { formatBalance, useBalances } from '@centrifuge/centrifuge-react'
+import { useAddress, useBalances } from '@centrifuge/centrifuge-react'
import { Box, Grid, Stack, Text } from '@centrifuge/fabric'
-import * as React from 'react'
-import { useAddress } from '../../utils/useAddress'
-import { usePool } from '../../utils/usePools'
+import { useMemo } from 'react'
+import { useLocation } from 'react-router'
+import { useTinlakeBalances } from '../../utils/tinlake/useTinlakeBalances'
+import { useTinlakePools } from '../../utils/tinlake/useTinlakePools'
+import { usePools } from '../../utils/usePools'
+import { SortButton } from '../SortButton'
+import { sortTokens } from './sortTokens'
+import { TokenListItem } from './TokenListItem'
-const TOKEN_ITEM_COLUMNS = `250px 200px 100px 150px 1FR`
-const TOKEN_ITEM_GAP = 4
+export const InvestedTokens = () => {
+ const { search } = useLocation()
-export function InvestedTokens() {
const address = useAddress()
- const balances = useBalances(address)
+ const centBalances = useBalances(address)
+ const { data: tinlakeBalances } = useTinlakeBalances()
- return !!balances?.tranches && !!balances?.tranches.length ? (
- <>
-
-
- Portfolio Composition
-
-
-
-
+ const { data: tinlakePools } = useTinlakePools()
+ const pools = usePools()
+
+ const balances = useMemo(() => {
+ return [
+ ...(centBalances?.tranches || []),
+ ...(tinlakeBalances?.tranches.filter((tranche) => !tranche.balance.isZero) || []),
+ ]
+ }, [centBalances, tinlakeBalances])
+
+ const sortedTokens =
+ balances.length && pools && tinlakePools
+ ? sortTokens(
+ balances,
+ {
+ centPools: pools,
+ tinlakePools: tinlakePools.pools,
+ },
+ new URLSearchParams(search)
+ )
+ : []
+
+ return sortedTokens.length ? (
+
+
+ Portfolio composition
+
+
+
+
Token
-
- Position
-
+
+
+
Token price
-
- Market value
-
+
+
-
- {balances.tranches.map((tranche, index) => (
-
-
-
+
+ {balances.map((balance, index) => (
+
))}
-
- >
+
+
) : null
}
-
-type TokenCardProps = AccountTokenBalance
-export function TokenListItem({ balance, currency, poolId, trancheId }: TokenCardProps) {
- const pool = usePool(poolId) as Pool
- const isTinlakePool = poolId?.startsWith('0x')
-
- if (isTinlakePool) {
- return null
- }
-
- const tranche = pool.tranches.find(({ id }) => id === trancheId)
-
- return (
-
-
- {currency.name}
-
-
-
- {formatBalance(balance, tranche?.currency.symbol)}
-
-
-
- {tranche?.tokenPrice ? formatBalance(tranche.tokenPrice.toDecimal(), tranche.currency.symbol, 4) : '-'}
-
-
-
- {tranche?.tokenPrice
- ? formatBalance(balance.toDecimal().mul(tranche.tokenPrice.toDecimal()), tranche.currency.symbol, 4)
- : '-'}
-
-
- )
-}
diff --git a/centrifuge-app/src/components/Portfolio/TokenListItem.tsx b/centrifuge-app/src/components/Portfolio/TokenListItem.tsx
new file mode 100644
index 0000000000..59cad67eff
--- /dev/null
+++ b/centrifuge-app/src/components/Portfolio/TokenListItem.tsx
@@ -0,0 +1,96 @@
+import { AccountTokenBalance, PoolMetadata } from '@centrifuge/centrifuge-js'
+import { formatBalance } from '@centrifuge/centrifuge-react'
+import {
+ AnchorButton,
+ Box,
+ Button,
+ Grid,
+ IconExternalLink,
+ IconMinus,
+ IconPlus,
+ Shelf,
+ Text,
+ Thumbnail,
+} from '@centrifuge/fabric'
+import { useTheme } from 'styled-components'
+import { usePool } from '../../utils/usePools'
+import { Eththumbnail } from '../EthThumbnail'
+import { Ellipsis, Root } from '../ListItemCardStyles'
+
+export type TokenCardProps = AccountTokenBalance
+
+export function TokenListItem({ balance, currency, poolId, trancheId }: TokenCardProps) {
+ const { sizes } = useTheme()
+ const pool = usePool(poolId, false)
+
+ const isTinlakePool = poolId.startsWith('0x')
+
+ const trancheInfo = pool?.tranches.find(({ id }) => id === trancheId)
+ const icon = (trancheInfo?.poolMetadata as PoolMetadata).tranches?.[trancheId].icon?.uri
+
+ return (
+
+
+
+
+ {icon ? (
+
+ ) : (
+
+ )}
+
+
+
+ {currency.name}
+
+
+
+
+ {formatBalance(balance, currency.symbol)}
+
+
+
+
+ {trancheInfo?.tokenPrice
+ ? formatBalance(trancheInfo.tokenPrice.toDecimal(), trancheInfo.currency.symbol, 4)
+ : '-'}
+
+
+
+
+
+ {trancheInfo?.tokenPrice
+ ? formatBalance(
+ balance.toDecimal().mul(trancheInfo.tokenPrice.toDecimal()),
+ trancheInfo.currency.symbol,
+ 4
+ )
+ : '-'}
+
+
+
+
+ {isTinlakePool ? (
+
+ View on Tinlake
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+
+ )
+}
diff --git a/centrifuge-app/src/components/Portfolio/sortTokens.ts b/centrifuge-app/src/components/Portfolio/sortTokens.ts
new file mode 100644
index 0000000000..cea663cc38
--- /dev/null
+++ b/centrifuge-app/src/components/Portfolio/sortTokens.ts
@@ -0,0 +1,50 @@
+import { Pool } from '@centrifuge/centrifuge-js'
+import { TinlakePool } from '../../utils/tinlake/useTinlakePools'
+import { TokenCardProps } from './TokenListItem'
+
+export const sortTokens = (
+ tranches: TokenCardProps[],
+ pools: {
+ centPools: Pool[]
+ tinlakePools: TinlakePool[]
+ },
+ searchParams: URLSearchParams
+) => {
+ const sortDirection = searchParams.get('sort')
+ const sortBy = searchParams.get('sort-by')
+
+ if (sortBy === 'market-value') {
+ tranches.sort((trancheA, trancheB) => {
+ const valueA = sortMarketValue(trancheA, pools)
+ const valueB = sortMarketValue(trancheB, pools)
+
+ return sortDirection === 'asc' ? valueA - valueB : valueB - valueA
+ })
+ }
+
+ if (sortBy === 'position' || (!sortDirection && !sortBy)) {
+ tranches.sort(({ balance: balanceA }, { balance: balanceB }) =>
+ sortDirection === 'asc'
+ ? balanceA.toDecimal().toNumber() - balanceB.toDecimal().toNumber()
+ : balanceB.toDecimal().toNumber() - balanceA.toDecimal().toNumber()
+ )
+ }
+
+ return tranches
+}
+
+const sortMarketValue = (
+ tranche: TokenCardProps,
+ pools: {
+ centPools: Pool[]
+ tinlakePools: TinlakePool[]
+ }
+) => {
+ const pool = tranche.poolId.startsWith('0x')
+ ? pools.tinlakePools?.find((p) => p.id.toLowerCase() === tranche.poolId.toLowerCase())
+ : pools.centPools?.find((p) => p.id === tranche.poolId)
+
+ const poolTranche = pool?.tranches.find(({ id }) => id === tranche.trancheId)
+
+ return poolTranche?.tokenPrice ? tranche.balance.toDecimal().mul(poolTranche.tokenPrice.toDecimal()).toNumber() : 0
+}
diff --git a/centrifuge-app/src/components/PoolFilter/SortButton.tsx b/centrifuge-app/src/components/SortButton.tsx
similarity index 95%
rename from centrifuge-app/src/components/PoolFilter/SortButton.tsx
rename to centrifuge-app/src/components/SortButton.tsx
index ba31ffe790..84ea210acc 100644
--- a/centrifuge-app/src/components/PoolFilter/SortButton.tsx
+++ b/centrifuge-app/src/components/SortButton.tsx
@@ -1,13 +1,12 @@
import { IconChevronDown, IconChevronUp, Stack, Tooltip } from '@centrifuge/fabric'
import * as React from 'react'
import { useHistory, useLocation } from 'react-router-dom'
-import { SEARCH_KEYS } from './config'
-import { FilterButton } from './styles'
-import { SortBy } from './types'
+import { SEARCH_KEYS } from './PoolFilter/config'
+import { FilterButton } from './PoolFilter/styles'
export type SortButtonProps = {
label: string
- searchKey: SortBy
+ searchKey: string
tooltip?: string
justifySelf?: 'start' | 'end'
}