diff --git a/packages/lib/modules/vebal/VebalStats/VebalStatsLayout.tsx b/packages/lib/modules/vebal/VebalStats/VebalStatsLayout.tsx index 4fb91c2ae..5c66d040f 100644 --- a/packages/lib/modules/vebal/VebalStats/VebalStatsLayout.tsx +++ b/packages/lib/modules/vebal/VebalStats/VebalStatsLayout.tsx @@ -1,14 +1,31 @@ 'use client' -import { Stack } from '@chakra-ui/react' +import { Skeleton, Stack } from '@chakra-ui/react' import { VebalStats } from '@repo/lib/modules/vebal/VebalStats/VebalStats' -import { VeBALLocksChart } from '@repo/lib/modules/vebal/vebal-chart/VebalLocksChart' +import { VebalLocksChart } from '@repo/lib/modules/vebal/vebal-chart/VebalLocksChart' +import { useVebalLockInfo } from '@repo/lib/modules/vebal/useVebalLockInfo' +import { useVebalUserData } from '@repo/lib/modules/vebal/useVebalUserData' +import { useMemo } from 'react' export function VebalStatsLayout() { + const lockInfo = useVebalLockInfo() + const { loading, data } = useVebalUserData() + + const lockSnapshots = useMemo(() => data?.veBalGetUser.lockSnapshots ?? [], [data]) + return ( - + {loading || lockInfo.isLoading ? ( + + ) : ( + + )} ) } diff --git a/packages/lib/modules/vebal/useVebalLockInfo.ts b/packages/lib/modules/vebal/useVebalLockInfo.ts index b86437772..79cdc7646 100644 --- a/packages/lib/modules/vebal/useVebalLockInfo.ts +++ b/packages/lib/modules/vebal/useVebalLockInfo.ts @@ -32,6 +32,8 @@ interface MulticallLockInfoResponse { } } +export type UseVebalLockInfoResult = ReturnType + export function useVebalLockInfo() { const { userAddress, isConnected } = useUserAccount() diff --git a/packages/lib/modules/vebal/vebal-chart/VebalLocksChart.tsx b/packages/lib/modules/vebal/vebal-chart/VebalLocksChart.tsx index b2fdd9162..cdaeb4d96 100644 --- a/packages/lib/modules/vebal/vebal-chart/VebalLocksChart.tsx +++ b/packages/lib/modules/vebal/vebal-chart/VebalLocksChart.tsx @@ -1,19 +1,38 @@ -import { Card, CardProps } from '@chakra-ui/react' +import { Card, CardProps, Text, VStack } from '@chakra-ui/react' import ReactECharts from 'echarts-for-react' -import { useVebalLocksChart } from './useVebalLocksChart' +import { useVebalLocksChart, UseVebalLocksChartParams } from './useVebalLocksChart' +import { ChartBubbleIcon } from '@repo/lib/shared/components/icons/ChartBubbleIcon' -export function VeBALLocksChart(props: CardProps) { - const { options, onChartReady, onEvents } = useVebalLocksChart() +export function VebalLocksChart({ + mainnetLockedInfo, + lockSnapshots, + ...props +}: CardProps & UseVebalLocksChartParams) { + const { options, onChartReady, onEvents, insufficientData } = useVebalLocksChart({ + mainnetLockedInfo, + lockSnapshots, + }) return ( - + {insufficientData ? ( + + + + + + Not enough data + + + ) : ( + + )} ) } diff --git a/packages/lib/modules/vebal/vebal-chart/test-locks.ts b/packages/lib/modules/vebal/vebal-chart/test-locks.ts deleted file mode 100644 index 453180d32..000000000 --- a/packages/lib/modules/vebal/vebal-chart/test-locks.ts +++ /dev/null @@ -1,254 +0,0 @@ -export const lockSnapshots = [ - { - bias: '411.968613215338375488', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1648494832', - slope: '0.000013274422196916', - timestamp: 1648494832, - }, - { - bias: '426.768704596875629824', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1648914664', - slope: '0.000013939885570784', - timestamp: 1648914664, - }, - { - bias: '437.379758392016650735', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1649386739', - slope: '0.000014510227094635', - timestamp: 1649386739, - }, - { - bias: '498.274642722178822178', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1650253669', - slope: '0.000017019941832838', - timestamp: 1650253669, - }, - { - bias: '525.4719047945281344', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1651287630', - slope: '0.00001860606412352', - timestamp: 1651287630, - }, - { - bias: '526.22180254040241455', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1652399425', - slope: '0.000019396181651626', - timestamp: 1652399425, - }, - { - bias: '537.78149185152830984', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1652671730', - slope: '0.000020023236833432', - timestamp: 1652671730, - }, - { - bias: '546.23608139662436016', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1652935896', - slope: '0.00002054005269054', - timestamp: 1652935896, - }, - { - bias: '645.68362210525044576', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1655956656', - slope: '0.00002054005269054', - timestamp: 1655956656, - }, - { - bias: '597.063090614348179615', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1659069463', - slope: '0.000021080847757895', - timestamp: 1659069463, - }, - { - bias: '570.212661942865193703', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1660773221', - slope: '0.000021421443182757', - timestamp: 1660773221, - }, - { - bias: '578.856298996191034753', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1660960409', - slope: '0.000021900168589783', - timestamp: 1660960409, - }, - { - bias: '873.31490731813230788', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1661367935', - slope: '0.000033557974410152', - timestamp: 1661367935, - }, - { - bias: '784.567787366075541538', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1664163563', - slope: '0.000033776176475674', - timestamp: 1664163563, - }, - { - bias: '1050.128381346061674874', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1664163599', - slope: '0.000033776176475674', - timestamp: 1664163599, - }, - { - bias: '931.328332517805007732', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1668044771', - slope: '0.000034227895298308', - timestamp: 1668044771, - }, - { - bias: '1076.234317848491017444', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1668044807', - slope: '0.000034227895298308', - timestamp: 1668044807, - }, - { - bias: '994.550288880754896919', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1671037031', - slope: '0.000034956640277551', - timestamp: 1671037031, - }, - { - bias: '1100.258330120702459695', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1671037055', - slope: '0.000034956640277551', - timestamp: 1671037055, - }, - { - bias: '986.354377972902335952', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1674874919', - slope: '0.000035689528064592', - timestamp: 1674874919, - }, - { - bias: '1122.554182554120910032', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1675897079', - slope: '0.000035689528064592', - timestamp: 1675897079, - }, - { - bias: '1103.901122090218030416', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1685491727', - slope: '0.000035689528064592', - timestamp: 1685491727, - }, - { - bias: '1163.452523590283058086', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1686367439', - slope: '0.000038710831253126', - timestamp: 1686367439, - }, - { - bias: '1210.27575148413915515', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1686367475', - slope: '0.000038710831253126', - timestamp: 1686367475, - }, - { - bias: '1185.891454125148391631', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1687746371', - slope: '0.000039680993634939', - timestamp: 1687746371, - }, - { - bias: '1233.888155510199748227', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1687746407', - slope: '0.000039680993634939', - timestamp: 1687746407, - }, - { - bias: '1211.693697205053065936', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1688699951', - slope: '0.000040199980339664', - timestamp: 1688699951, - }, - { - bias: '1260.3186286243824884', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1688699975', - slope: '0.000040199980339664', - timestamp: 1688699975, - }, - { - bias: '1167.088644074268523808', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1691292359', - slope: '0.000040581908153888', - timestamp: 1691292359, - }, - { - bias: '1265.26293533146083344', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1691292395', - slope: '0.000040581908153888', - timestamp: 1691292395, - }, - { - bias: '1282.359069389423530864', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1691721443', - slope: '0.000041704148514352', - timestamp: 1691721443, - }, - { - bias: '1226.553715113925634922', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1693644311', - slope: '0.000042550125863898', - timestamp: 1693644311, - }, - { - bias: '1329.48995840084694297', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1693644335', - slope: '0.000042550125863898', - timestamp: 1693644335, - }, - { - bias: '1311.815238816018343179', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1694491019', - slope: '0.000043153831384959', - timestamp: 1694491019, - }, - { - bias: '1051.61523535449844771', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1700936615', - slope: '0.000043903306220686', - timestamp: 1700936615, - }, - { - bias: '1370.244182704026623686', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1700936699', - slope: '0.000043903306220686', - timestamp: 1700936699, - }, - { - bias: '1207.52747382758520986', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1706411831', - slope: '0.00004692093102794', - timestamp: 1706411831, - }, - { - bias: '1462.92523339417887674', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1706411879', - slope: '0.00004692093102794', - timestamp: 1706411879, - }, - { - bias: '1389.499237660943196577', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1708406507', - slope: '0.000047611853485789', - timestamp: 1708406507, - }, - { - bias: '1130.568460169324406853', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1714278167', - slope: '0.000048496789654141', - timestamp: 1714278167, - }, - { - bias: '989.152639305655695838', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1717392263', - slope: '0.000048972469060174', - timestamp: 1717392263, - }, - { - bias: '1522.28006211641798647', - id: '0x5e4568c4d8343052a06ec8aab1e124af08b73248-1717392395', - slope: '0.000048972469060174', - timestamp: 1717392395, - }, -] diff --git a/packages/lib/modules/vebal/vebal-chart/useVebalLocksChart.tsx b/packages/lib/modules/vebal/vebal-chart/useVebalLocksChart.tsx index ea6fdad1e..5cdfed5ad 100644 --- a/packages/lib/modules/vebal/vebal-chart/useVebalLocksChart.tsx +++ b/packages/lib/modules/vebal/vebal-chart/useVebalLocksChart.tsx @@ -8,8 +8,7 @@ import * as echarts from 'echarts/core' import { EChartsOption, ECharts } from 'echarts' import { format, differenceInDays } from 'date-fns' import BigNumber from 'bignumber.js' -import { lockSnapshots } from './test-locks' -import { useVebalLockInfo } from '../../vebal/useVebalLockInfo' +import { UseVebalLockInfoResult } from '../../vebal/useVebalLockInfo' import { bn, fNum } from '@repo/lib/shared/utils/numbers' import { useTheme as useNextTheme } from 'next-themes' @@ -17,10 +16,12 @@ type ChartValueAcc = [string, number][] interface LockSnapshot { bias: string - slope: string timestamp: number + slope: string } +export const MIN_CHART_VALUES = 2 + function groupValuesByDates(chartValues: ChartValueAcc) { return chartValues.reduce((acc: Record, item) => { const [date, value] = item @@ -80,15 +81,19 @@ function filterAndFlattenValues(valuesByDates: Record) { const MAIN_SERIES_ID = 'main-series' const FUTURE_SERIES_ID = 'future-series' -export function useVebalLocksChart() { +export interface UseVebalLocksChartParams { + lockSnapshots: LockSnapshot[] + mainnetLockedInfo: UseVebalLockInfoResult['mainnetLockedInfo'] +} + +export function useVebalLocksChart({ lockSnapshots, mainnetLockedInfo }: UseVebalLocksChartParams) { const theme = useChakraTheme() const { theme: nextTheme } = useNextTheme() const instanceRef = useRef() - const userHistoricalLocks = lockSnapshots + const userHistoricalLocks = [...lockSnapshots].sort((a, b) => a.timestamp - b.timestamp) - const { mainnetLockedInfo } = useVebalLockInfo() const lockedUntil = mainnetLockedInfo.lockedEndDate ? differenceInDays(new Date(mainnetLockedInfo.lockedEndDate), new Date()) : 0 @@ -96,9 +101,12 @@ export function useVebalLocksChart() { const isExpired = mainnetLockedInfo.isExpired const chartValues = useMemo(() => { - if (!userHistoricalLocks) return [] - - const processedValues = processLockSnapshots(lockSnapshots) + const processedValues = processLockSnapshots( + userHistoricalLocks.map(userHistoricalLock => ({ + ...userHistoricalLock, + slope: userHistoricalLock.slope, + })) + ) const valuesByDates = groupValuesByDates(processedValues) return filterAndFlattenValues(valuesByDates) }, [userHistoricalLocks]) @@ -234,7 +242,7 @@ export function useVebalLocksChart() { if (!mouseoverRef.current) { if (firstPoint.seriesId === MAIN_SERIES_ID) { - if (firstPoint.dataIndex === chartValues.length - 1) { + if ([firstPoint.dataIndex, secondPoint?.dataIndex].includes(chartValues.length - 1)) { return `
@@ -356,5 +364,6 @@ export function useVebalLocksChart() { options, onChartReady, onEvents, + insufficientData: chartValues.length < MIN_CHART_VALUES, } } diff --git a/packages/lib/shared/services/api/vebal.graphql b/packages/lib/shared/services/api/vebal.graphql index ba034518d..cec6770dc 100644 --- a/packages/lib/shared/services/api/vebal.graphql +++ b/packages/lib/shared/services/api/vebal.graphql @@ -8,5 +8,11 @@ query GetVeBalUser( ) { balance rank + lockSnapshots { + balance + timestamp + bias + slope + } } } \ No newline at end of file diff --git a/turbo.json b/turbo.json index 8e9d8ac46..0c5a778b8 100644 --- a/turbo.json +++ b/turbo.json @@ -21,6 +21,9 @@ "dependsOn": ["^start"], "inputs": ["$TURBO_DEFAULT$", ".env*"] }, + "transit": { + "dependsOn": ["^transit"] + }, "lint": { "dependsOn": ["^transit"], "outputs": ["node_modules/.cache/.eslintcache", ".next/cache/eslint"] @@ -31,24 +34,21 @@ "cache": false }, "typecheck": { - "dependsOn": ["graphql:gen", "transit"], + "dependsOn": ["^graphql:gen", "^transit"], "outputs": ["node_modules/.cache/tsbuildinfo.json"] }, "test:unit": { - "dependsOn": ["graphql:gen", "^test:unit"] + "dependsOn": ["^graphql:gen", "^test:unit"] }, "test:integration": { - "dependsOn": ["graphql:gen", "^test:integration"], + "dependsOn": ["^graphql:gen", "^test:integration"], "inputs": ["$TURBO_DEFAULT$", ".env*"] }, "graphql:gen": { "dependsOn": ["^graphql:gen"], - "inputs": [".env*"], + "inputs": ["**/*.graphql"], "outputs": ["shared/services/api/generated/**"] }, - "transit": { - "dependsOn": ["^transit"] - }, "//#format": { "outputs": ["node_modules/.cache/.prettiercache"] },