Skip to content

Commit

Permalink
Add UI for portfolio overview chart and card
Browse files Browse the repository at this point in the history
  • Loading branch information
JP Angelle committed Nov 1, 2023
1 parent 5acb85c commit a7c1c21
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 10 deletions.
78 changes: 78 additions & 0 deletions centrifuge-app/src/components/Portfolio/CardPortfolioValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Box, Shelf, Stack, Text, TextWithPlaceholder } from '@centrifuge/fabric'
import * as React from 'react'
import { useTheme } from 'styled-components'
import { config } from '../../config'
import { Dec } from '../../utils/Decimal'
import { formatBalance } from '../../utils/formatting'
import { useListedPools } from '../../utils/useListedPools'
import { DataPoint, PortfolioValue } from './PortfolioValue'

export function CardPortfolioValue() {
const { colors } = useTheme()
const [hovered, setHovered] = React.useState<DataPoint | undefined>(undefined)

Check warning on line 12 in centrifuge-app/src/components/Portfolio/CardPortfolioValue.tsx

View workflow job for this annotation

GitHub Actions / build-app

'hovered' is assigned a value but never used
const [, listedTokens] = useListedPools()

const chartHeight = 130
const balanceProps = {
as: 'strong',
fontSize: [16, 18],
}
const headingProps = {
as: 'p',
variant: 'body3',
}

const totalValueLocked = React.useMemo(() => {
return (
listedTokens
?.map((tranche) => ({
valueLocked: tranche.totalIssuance
.toDecimal()
.mul(tranche.tokenPrice?.toDecimal() ?? Dec(0))
.toNumber(),
}))
.reduce((prev, curr) => prev.add(curr.valueLocked), Dec(0)) ?? Dec(0)
)
}, [listedTokens])

return (
<Box position="relative">
<Box
role="article"
borderRadius="card"
borderStyle="solid"
borderWidth={1}
borderColor="borderSecondary"
p={3}
pb={chartHeight * 0.6}
style={{
boxShadow: `0px 3px 2px -2px ${colors.borderPrimary}`,
}}
background={colors.backgroundPage}
>
<Stack>
<Text variant="heading2">Overview</Text>

<Shelf gap={4}>
<Stack>
<Text {...headingProps}>Current portfolio value</Text>
<TextWithPlaceholder {...balanceProps} isLoading={!totalValueLocked}>
{formatBalance(Dec(totalValueLocked || 0), config.baseCurrency)}
</TextWithPlaceholder>
</Stack>
<Stack>
<Text {...headingProps}>Profit</Text>
<TextWithPlaceholder {...balanceProps} isLoading={!totalValueLocked}>
{formatBalance(Dec(totalValueLocked || 0), config.baseCurrency)}
</TextWithPlaceholder>
</Stack>
</Shelf>
</Stack>

<Box width="100%" height="300px">
<PortfolioValue setHovered={setHovered} />
</Box>
</Box>
</Box>
)
}
150 changes: 150 additions & 0 deletions centrifuge-app/src/components/Portfolio/PortfolioValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { Area, AreaChart, CartesianGrid, ResponsiveContainer, XAxis, YAxis } from 'recharts'

export type DataPoint = {
dateInMilliseconds: number
}

type TotalValueLockedProps = {
setHovered: (entry: DataPoint | undefined) => void
}

export function PortfolioValue({ setHovered }: TotalValueLockedProps) {
// const portfolioValue = usePortfolioValue()
const chartColor = '#006EF5'

// const chartData = React.useMemo(
// () => {
// return []
// },
// [ portfolioValue ]
// )

return (
<ResponsiveContainer>
<AreaChart
margin={{
top: 50,
right: 30,
left: 30,
bottom: 0,
}}
data={[
{
portfolioValue: 123809,
dateInMilliseconds: Date.now(),
// month: <Text variant="body4">Jan</Text>,
month: 'Jan',
},
{
portfolioValue: 123809,
dateInMilliseconds: Date.now() - 86400000, // 1 day ago
month: 'Feb',
},
{
portfolioValue: 123809,
dateInMilliseconds: Date.now() - 86400000 * 2, // 2 days ago
month: 'Mar',
},
{
portfolioValue: 2023480,
dateInMilliseconds: Date.now() - 86400000 * 3, // 3 days ago
month: 'Apr',
},
{
portfolioValue: 3023480,
dateInMilliseconds: Date.now() - 86400000 * 4, // 4 days ago
month: 'May',
},
{
portfolioValue: 4023480,
dateInMilliseconds: Date.now() - 86400000 * 5, // 5 days ago
month: 'Jun',
},
{
portfolioValue: 7023480,
dateInMilliseconds: Date.now() - 86400000 * 6, // 6 days ago
month: 'Jul',
},
{
portfolioValue: 8023480,
dateInMilliseconds: Date.now() - 86400000 * 7, // 7 days ago
month: 'Aug',
},
{
portfolioValue: 9023480,
dateInMilliseconds: Date.now() - 86400000 * 8, // 8 days ago
month: 'Sep',
},
{
portfolioValue: 10023480,
dateInMilliseconds: Date.now() - 86400000 * 9, // 9 days ago
month: 'Oct',
},
{
portfolioValue: 11023480,
dateInMilliseconds: Date.now() - 86400000 * 10, // 10 days ago
month: 'Nov',
},
{
portfolioValue: 12023480,
dateInMilliseconds: Date.now() - 86400000 * 11, // 11 days ago
month: 'Dec',
},
]}
onMouseMove={(val: any) => {
if (val?.activePayload && val?.activePayload.length > 0) {
setHovered(val.activePayload[0].payload)
}
}}
onMouseLeave={() => {
setHovered(undefined)
}}
>
<defs>
<linearGradient id="colorPoolValue" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stopColor={chartColor} stopOpacity={0.3} />
<stop offset="90%" stopColor="#F2F2F2" stopOpacity={0.8} />
</linearGradient>
</defs>
<CartesianGrid vertical={false} />

<XAxis dataKey="month" tickLine={false} axisLine={false} />
<YAxis dataKey="portfolioValue" tickCount={10} tickLine={false} axisLine={false} />
<Area
type="monotone"
dataKey="portfolioValue"
strokeWidth={1}
fillOpacity={1}
fill="url(#colorPoolValue)"
name="Current Value Locked"
stroke={`${chartColor}30`}
activeDot={{ fill: chartColor }}
/>
</AreaChart>
</ResponsiveContainer>
)
}

// function getMergedData(combined: DataPoint[], current?: DataPoint) {
// const mergedMap = new Map()

// combined.forEach((entry) => {
// const { dateInMilliseconds, tvl } = entry

// if (mergedMap.has(dateInMilliseconds)) {
// mergedMap.set(dateInMilliseconds, mergedMap.get(dateInMilliseconds).add(tvl))
// } else {
// mergedMap.set(dateInMilliseconds, tvl)
// }
// })

// if (current) {
// mergedMap.set(current.dateInMilliseconds, current.tvl)
// }

// const merged = Array.from(mergedMap, ([dateInMilliseconds, tvl]) => ({ dateInMilliseconds, tvl }))
// .sort((a, b) => a.dateInMilliseconds - b.dateInMilliseconds)
// .map((entry) => ({ ...entry, tvl: entry.tvl.toNumber() }))

// return merged
// }
2 changes: 1 addition & 1 deletion centrifuge-app/src/components/Portfolio/Transactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export function Transactions({ onlyMostRecent, txTypes }: TransactionsProps) {
const { formatAddress } = useCentrifugeUtils()
const address = useAddress()
const formattedAddress = address && isValidEVMAddress(address) ? address : formatAddress(address || '')
const transactions = useTransactionsByAddress(formatAddress(formattedAddress))
const transactions = useTransactionsByAddress(formattedAddress)
const pools = usePools()

const investorTransactions: TransactionTableData = React.useMemo(() => {
Expand Down
12 changes: 3 additions & 9 deletions centrifuge-app/src/pages/Portfolio/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Card, Grid, Stack, Text } from '@centrifuge/fabric'
import { Stack, Text } from '@centrifuge/fabric'
import * as React from 'react'
import { useTheme } from 'styled-components'
import { LayoutBase } from '../../components/LayoutBase'
import { BasePadding } from '../../components/LayoutBase/BasePadding'
import { PoolList } from '../../components/PoolList'
import { AssetAllocation } from '../../components/Portfolio/AssetAllocation'
import { CardPortfolioValue } from '../../components/Portfolio/CardPortfolioValue'
import { InvestedTokens } from '../../components/Portfolio/InvestedTokens'
import { Rewards } from '../../components/Portfolio/Rewards'
import { Transactions } from '../../components/Portfolio/Transactions'
import { useAddress } from '../../utils/useAddress'

Expand Down Expand Up @@ -42,13 +42,7 @@ function Portfolio() {
</Text>
</Stack>

<Grid gridTemplateColumns={['1.5fr 1fr']} gap={4}>
<Card as="article" p={1}>
<Text as="h2">Portfolio overview</Text>
</Card>

<Rewards />
</Grid>
<CardPortfolioValue />
</BasePadding>
<BasePadding gap={3}>
<InvestedTokens />
Expand Down

0 comments on commit a7c1c21

Please sign in to comment.