mango-v4-ui/components/account/HealthContributionsChart.tsx

143 lines
4.0 KiB
TypeScript
Raw Normal View History

2023-07-06 20:45:32 -07:00
import { useTranslation } from 'next-i18next'
2023-07-10 04:56:38 -07:00
import {
Cell,
Pie,
PieChart,
2023-07-10 23:01:22 -07:00
ResponsiveContainer,
2023-07-10 04:56:38 -07:00
Sector,
SectorProps,
} from 'recharts'
2023-07-06 20:45:32 -07:00
import { COLORS } from 'styles/colors'
2023-07-10 23:01:22 -07:00
import { useMemo } from 'react'
2023-07-10 04:56:38 -07:00
import { formatCurrencyValue } from 'utils/numbers'
2023-07-10 23:01:22 -07:00
import { useViewport } from 'hooks/useViewport'
2023-07-11 17:26:37 -07:00
import { HealthContribution } from 'types'
2023-07-21 11:50:06 -07:00
import useThemeWrapper from 'hooks/useThemeWrapper'
2023-07-06 20:45:32 -07:00
2023-07-10 23:01:22 -07:00
const HealthContributionsChart = ({
data,
activeIndex,
setActiveIndex,
}: {
data: HealthContribution[]
activeIndex: number | undefined
setActiveIndex: (i: number | undefined) => void
}) => {
2023-07-10 04:56:38 -07:00
const { t } = useTranslation(['common', 'account'])
2023-07-21 11:50:06 -07:00
const { theme } = useThemeWrapper()
2023-08-31 20:22:50 -07:00
const { isMobile } = useViewport()
2023-07-10 04:56:38 -07:00
const handleMouseEnter = (data: HealthContribution, index: number) => {
setActiveIndex(index)
}
2023-07-06 20:45:32 -07:00
2023-07-10 04:56:38 -07:00
const handleMouseLeave = () => {
setActiveIndex(undefined)
}
2023-07-10 23:01:22 -07:00
const pieSizes = isMobile
? { size: 160, outerRadius: 80, innerRadius: 64 }
: { size: 240, outerRadius: 120, innerRadius: 96 }
2023-07-06 20:45:32 -07:00
const { size, outerRadius, innerRadius } = pieSizes
2023-07-10 04:56:38 -07:00
const [chartHeroAsset, chartHeroValue] = useMemo(() => {
2023-07-10 23:01:22 -07:00
if (!data.length) return [undefined, undefined]
2023-07-10 04:56:38 -07:00
if (activeIndex === undefined) {
2023-07-10 23:01:22 -07:00
const value = data.reduce((a, c) => {
2023-07-10 04:56:38 -07:00
const assetOrLiabMultiplier = c.isAsset ? 1 : -1
return a + c.contribution * assetOrLiabMultiplier
2023-07-06 20:45:32 -07:00
}, 0)
2023-07-10 04:56:38 -07:00
return [t('total'), value]
} else {
2023-07-10 23:01:22 -07:00
const asset = data[activeIndex]
2023-07-10 04:56:38 -07:00
const assetOrLiabMultiplier = asset.isAsset ? 1 : -1
const value = asset.contribution * assetOrLiabMultiplier
return [asset.asset, value]
}
2023-07-10 23:01:22 -07:00
}, [activeIndex, data])
2023-07-06 20:45:32 -07:00
2023-07-10 04:56:38 -07:00
const renderActiveShape = ({
cx,
cy,
innerRadius,
outerRadius,
startAngle,
endAngle,
fill,
}: SectorProps) => {
return (
<g>
<Sector
cx={cx}
cy={cy}
2023-07-10 23:01:22 -07:00
innerRadius={innerRadius}
outerRadius={outerRadius! + 4}
2023-07-10 04:56:38 -07:00
startAngle={startAngle}
endAngle={endAngle}
fill={fill}
/>
</g>
)
}
2023-07-10 23:01:22 -07:00
return data.length ? (
<div className="mt-4 flex h-full w-full flex-col items-center">
<div className="relative h-[168px] w-[168px] sm:h-[248px] sm:w-[248px]">
<ResponsiveContainer height="100%" width="100%">
<PieChart width={size} height={size}>
<Pie
cursor="pointer"
data={data}
dataKey="contribution"
cx="50%"
cy="50%"
outerRadius={outerRadius}
innerRadius={innerRadius}
minAngle={2}
startAngle={90}
endAngle={450}
activeIndex={activeIndex}
activeShape={renderActiveShape}
2023-09-19 22:56:20 -07:00
// onClick={handleClick}
2023-07-10 23:01:22 -07:00
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{data.map((entry, index) => {
const fillColor = entry.isAsset
? COLORS.UP[theme]
: COLORS.DOWN[theme]
2023-07-06 20:45:32 -07:00
2023-07-10 23:01:22 -07:00
let opacity
if (entry.isAsset) {
opacity = 1 - index * 0.1
} else {
opacity = 1 - Math.abs((index - (data.length - 1)) * 0.1)
}
return (
<Cell
key={`cell-${index}`}
fill={fillColor}
opacity={opacity}
stroke="none"
/>
)
})}
</Pie>
</PieChart>
</ResponsiveContainer>
{chartHeroValue !== undefined ? (
2023-07-10 04:56:38 -07:00
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-center">
2023-07-10 23:01:22 -07:00
<p className="text-xs sm:text-sm">{chartHeroAsset}</p>
<span className="text-base font-bold sm:text-xl">
{formatCurrencyValue(chartHeroValue, 2)}
2023-07-10 04:56:38 -07:00
</span>
</div>
) : null}
</div>
2023-07-06 20:45:32 -07:00
</div>
2023-07-10 04:56:38 -07:00
) : null
2023-07-06 20:45:32 -07:00
}
export default HealthContributionsChart