Skip to content

Commit

Permalink
feat: Staking charts + Performance badge WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
amalcaraz committed Nov 8, 2023
1 parent 7ede82a commit d406a20
Show file tree
Hide file tree
Showing 18 changed files with 494 additions and 154 deletions.
53 changes: 53 additions & 0 deletions src/components/common/CCNRewardChart/cmp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { memo, useMemo } from 'react'
import { CCN } from '@/domain/node'
import { StakeManager } from '@/domain/stake'
import RewardChart from '../RewardChart'

export type CCNRewardChartProps = {
nodes?: CCN[]
allNodes?: CCN[]
rewards?: number
disabled?: boolean
}

export const CCNRewardChart = memo(
({
nodes,
allNodes,
rewards: distributionRewards,
...rest
}: CCNRewardChartProps) => {
const stakeManager = useMemo(() => new StakeManager(), [])

const loading = !nodes || !allNodes || distributionRewards === undefined
const distributionFrequency = 10

const estimatedTotalRewards = useMemo(() => {
if (!nodes) return
if (!allNodes) return

return nodes.reduce(
(ac, node) =>
ac +
stakeManager.CCNRewardsPerDay(node, allNodes) * distributionFrequency,
0,
)
}, [nodes, allNodes, stakeManager])

return (
<RewardChart
{...{
title: 'CCN REWARDS',
estimatedTotalRewards,
distributionRewards,
distributionFrequency,
loading,
...rest,
}}
/>
)
},
)
CCNRewardChart.displayName = 'CCNRewardChart'

export default CCNRewardChart
1 change: 1 addition & 0 deletions src/components/common/CCNRewardChart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './cmp'
45 changes: 45 additions & 0 deletions src/components/common/CRNRewardChart/cmp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { memo, useMemo } from 'react'
import { CRN } from '@/domain/node'
import { StakeManager } from '@/domain/stake'
import RewardChart from '../RewardChart'

export type CRNRewardChartProps = {
nodes?: CRN[]
rewards?: number
disabled?: boolean
}

export const CRNRewardChart = memo(
({ nodes, rewards: distributionRewards, ...rest }: CRNRewardChartProps) => {
const stakeManager = useMemo(() => new StakeManager(), [])

const loading = !nodes || distributionRewards === undefined
const distributionFrequency = 10

const estimatedTotalRewards = useMemo(() => {
if (!nodes) return

return nodes.reduce(
(ac, node) =>
ac + stakeManager.CRNRewardsPerDay(node) * distributionFrequency,
0,
)
}, [nodes, stakeManager])

return (
<RewardChart
{...{
title: 'CRN REWARDS',
estimatedTotalRewards,
distributionRewards,
distributionFrequency,
loading,
...rest,
}}
/>
)
},
)
CRNRewardChart.displayName = 'CRNRewardChart'

export default CRNRewardChart
1 change: 1 addition & 0 deletions src/components/common/CRNRewardChart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './cmp'
2 changes: 1 addition & 1 deletion src/components/common/CRNRewardsCell/cmp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const CRNRewardsCell = memo(({ node }: { node: CRN }) => {
// @todo: Refactor this (use singleton)
const rewardManager = new StakeManager()

const rewards = rewardManager.computeCRNRewards(node)
const rewards = rewardManager.CRNRewardsPerDay(node)
const isNotFullyLinked = useMemo(() => !node.parent, [node])

return (
Expand Down
157 changes: 157 additions & 0 deletions src/components/common/RewardChart/cmp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { memo, useMemo } from 'react'
import { Cell, Pie, PieChart } from 'recharts'
import { useTheme } from 'styled-components'
import { Logo, TextGradient } from '@aleph-front/aleph-core'
import Card1 from '../Card1'
import ColorDot from '../ColorDot'
import { SVGGradients } from '../charts'

export type RewardChartProps = {
title: string
estimatedTotalRewards?: number
distributionRewards?: number
distributionFrequency: number
disabled?: boolean
loading?: boolean
}

export const RewardChart = memo(
({
title,
estimatedTotalRewards,
distributionRewards,
distributionFrequency,
disabled,
loading,
...rest
}: RewardChartProps) => {
const theme = useTheme()

const pendingDays = useMemo(() => {
if (distributionRewards === undefined) return distributionFrequency
if (estimatedTotalRewards === undefined) return distributionFrequency

const userRewards = distributionRewards
const percent = Math.max(1 - userRewards / estimatedTotalRewards, 0)

if (Number.isNaN(percent)) return distributionFrequency

return Math.ceil(distributionFrequency * percent)
}, [distributionFrequency, distributionRewards, estimatedTotalRewards])

const data = useMemo(() => {
if (distributionRewards === undefined) return []
if (estimatedTotalRewards === undefined) return []

const userRewards = distributionRewards
const pendingRewards = estimatedTotalRewards - userRewards

return [
{
label: 'Estimated Rewards',
value: userRewards,
percentage: userRewards / estimatedTotalRewards,
gradient: 'main1',
},
{
label: 'Pending rewards',
value: pendingRewards,
percentage: pendingRewards / estimatedTotalRewards,
color: 'transparent',
},
]
}, [estimatedTotalRewards, distributionRewards])

return (
<Card1
tw="w-auto min-w-[9.625rem]"
disabled={disabled}
loading={loading}
{...rest}
>
<TextGradient
forwardedAs="h3"
type="info"
color={disabled ? 'base0' : 'main0'}
tw="m-0 min-h-[2rem]"
>
{title}
</TextGradient>

<div tw="flex flex-col items-center">
<PieChart
data={data}
width={100}
height={100}
margin={{}}
tw="my-3 min-h-[6.25rem]"
>
<defs>
<SVGGradients data={data} />
</defs>
<Pie
data={[{ v: 1 }]}
dataKey="v"
stroke="transparent"
innerRadius="72%"
outerRadius="100%"
startAngle={360 + 90}
endAngle={0 + 90}
isAnimationActive={false}
fill={`${theme.color.base0}20`}
/>
<Pie
data={data}
dataKey="percentage"
stroke="transparent"
innerRadius="72%"
outerRadius="100%"
startAngle={360 + 90}
endAngle={0 + 90}
>
{data.map((entry) => {
const color = `gr-${entry.gradient}`
const fill = entry.gradient
? `url(#${color})`
: entry.color
? theme.color[entry.color] || entry.color
: undefined

return <Cell key={entry.label} fill={fill} />
})}
</Pie>
</PieChart>

<div tw="mt-1 flex flex-col gap-4">
<div tw="flex items-center gap-3">
<ColorDot $color="main1" $size="1.25rem" />
<div
tw="flex flex-col justify-between leading-4! gap-1 not-italic whitespace-nowrap"
className="tp-body3"
>
<div>
<div tw="inline-flex gap-1 items-center">
{(distributionRewards || 0).toFixed(2)}
<Logo text="" size="0.75rem" />
</div>
</div>
<div className="fs-10" tw="opacity-60">
Est. Rewards
</div>
</div>
</div>
<div
className="tp-body1 fs-10"
tw="opacity-60 text-center whitespace-nowrap"
>
Next payout in {pendingDays} days.
</div>
</div>
</div>
</Card1>
)
},
)
RewardChart.displayName = 'RewardChart'

export default RewardChart
1 change: 1 addition & 0 deletions src/components/common/RewardChart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './cmp'
Loading

0 comments on commit d406a20

Please sign in to comment.