manifold/web/components/portfolio/portfolio-value-graph.tsx
Pico2x ebc4bd6bcf
[PortfolioGraph] Shows a graph of the portfolio value over time (#570)
* [Portfolio Graph] Shows a graph of the portfolio value over time

* [PortfolioGraph] Fix some nits.

* [PortfolioGraph] Comment out portfolio-value-section

Hides the component completely for now, so we can land today. My plan would be to land today, wait for the history to build up, and then revert this commit. As opposed to leaving the PR idle for a while, and then have to deal with conflicts.

* [PortfolioGraph] Rm duplicate firestore rule
2022-06-24 12:14:20 -05:00

84 lines
2.4 KiB
TypeScript

import { ResponsiveLine } from '@nivo/line'
import { PortfolioMetrics } from 'common/user'
import { formatMoney } from 'common/util/format'
import { DAY_MS } from 'common/util/time'
import { last } from 'lodash'
import { memo } from 'react'
import { useWindowSize } from 'web/hooks/use-window-size'
import { formatTime } from 'web/lib/util/time'
export const PortfolioValueGraph = memo(function PortfolioValueGraph(props: {
portfolioHistory: PortfolioMetrics[]
height?: number
period?: string
}) {
const { portfolioHistory, height, period } = props
const { width } = useWindowSize()
const portfolioHistoryFiltered = portfolioHistory.filter((p) => {
switch (period) {
case 'daily':
return p.timestamp > Date.now() - 1 * DAY_MS
case 'weekly':
return p.timestamp > Date.now() - 7 * DAY_MS
case 'monthly':
return p.timestamp > Date.now() - 30 * DAY_MS
case 'allTime':
return true
default:
return true
}
})
const points = portfolioHistoryFiltered.map((p) => {
return {
x: new Date(p.timestamp),
y: p.balance + p.investmentValue,
}
})
const data = [{ id: 'Value', data: points, color: '#11b981' }]
const numXTickValues = !width || width < 800 ? 2 : 5
const numYTickValues = 4
const endDate = last(points)?.x
const includeTime = period === 'daily'
return (
<div
className="w-full overflow-hidden"
style={{ height: height ?? (!width || width >= 800 ? 350 : 250) }}
>
<ResponsiveLine
data={data}
margin={{ top: 20, right: 28, bottom: 22, left: 60 }}
xScale={{
type: 'time',
min: points[0].x,
max: endDate,
}}
yScale={{
type: 'linear',
stacked: false,
min: Math.min(...points.map((p) => p.y)),
}}
gridYValues={numYTickValues}
curve="monotoneX"
colors={{ datum: 'color' }}
axisBottom={{
tickValues: numXTickValues,
format: (time) => formatTime(+time, includeTime),
}}
pointBorderColor="#fff"
pointSize={points.length > 100 ? 0 : 6}
axisLeft={{
tickValues: numYTickValues,
format: (value) => formatMoney(value),
}}
enableGridX={!!width && width >= 800}
enableGridY={true}
enableSlices="x"
animate={false}
></ResponsiveLine>
</div>
)
})