Skip to content

Commit

Permalink
Daily transaction chart
Browse files Browse the repository at this point in the history
  • Loading branch information
lubej committed Mar 14, 2023
1 parent 121fee9 commit 14432c9
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 6 deletions.
32 changes: 28 additions & 4 deletions src/app/pages/DashboardPage/TransactionsChartCard.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { useTranslation } from 'react-i18next'
import { Layer, useGetLayerStatsTxVolume } from '../../../oasis-indexer/api'
import { ChartDuration, chartUseQueryStaleTimeMs, durationToQueryParams } from '../../utils/chart-utils'
import {
ChartDuration,
chartUseQueryStaleTimeMs,
durationToQueryParams,
sumBucketsByStartDuration,
} from '../../utils/chart-utils'
import { LineChart } from '../../components/charts/LineChart'
import { useTheme } from '@mui/material/styles'
import useMediaQuery from '@mui/material/useMediaQuery'
import { FC, memo } from 'react'
import { SnapshotCard } from './SnapshotCard'
import { PercentageGain } from '../../components/PercentageGain'
import startOfHour from 'date-fns/startOfHour'

interface TransactionsChartCardProps {
chartDuration: ChartDuration
Expand All @@ -17,19 +23,36 @@ const TransactionsChartCardCmp: FC<TransactionsChartCardProps> = ({ chartDuratio
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const statsParams = durationToQueryParams[chartDuration]
const { data } = useGetLayerStatsTxVolume(Layer.emerald, statsParams, {
const { data, isFetched } = useGetLayerStatsTxVolume(Layer.emerald, statsParams, {
query: { staleTime: chartUseQueryStaleTimeMs },
})

const lineChartData = data?.data.buckets.map(bucket => {
const isDailyChart = isFetched && chartDuration === ChartDuration.TODAY

const buckets = data?.data.buckets.map(bucket => {
return {
bucket_start: bucket.bucket_start,
volume_per_second: bucket.tx_volume / statsParams.bucket_size_seconds,
}
})

const totalTransactions = data?.data.buckets.reduce((acc, curr) => acc + curr.tx_volume, 0) ?? 0

const lineChartData = isDailyChart
? sumBucketsByStartDuration(buckets, 'volume_per_second', 'bucket_start', startOfHour)
: buckets

const formatParams = isDailyChart
? {
timestamp: {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
} satisfies Intl.DateTimeFormatOptions,
}
: undefined

return (
<SnapshotCard
title={t('common.transactions')}
Expand All @@ -55,6 +78,7 @@ const TransactionsChartCardCmp: FC<TransactionsChartCardProps> = ({ chartDuratio
label: (value: string) =>
t('common.formattedDateTime', {
timestamp: new Date(value),
formatParams,
}),
}}
/>
Expand Down
44 changes: 42 additions & 2 deletions src/app/utils/chart-utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import startOfHour from 'date-fns/startOfHour'
import startOfDay from 'date-fns/startOfDay'
import isSameMonth from 'date-fns/isSameMonth'
import startOfMonth from 'date-fns/startOfMonth'
import { GetLayerStatsTxVolumeParams, type TxVolume, type ActiveAccounts } from '../../oasis-indexer/api'

export enum ChartDuration {
Expand Down Expand Up @@ -39,7 +42,7 @@ export const chartUseQueryStaleTimeMs = durationToQueryParams[ChartDuration.TODA
type Buckets = TxVolume[] | undefined
type MonthlyTxVolume = TxVolume & { numberOfItemsInGroup: number }

const groupBucketsByMonth = (buckets: Buckets) => {
const groupBucketsByDuration = (buckets: Buckets) => {
return buckets?.reduce((acc: MonthlyTxVolume[], cur, index, arr) => {
if (index > 0 && isSameMonth(new Date(cur.bucket_start), new Date(arr[index - 1].bucket_start))) {
acc[acc.length - 1].tx_volume += cur.tx_volume
Expand All @@ -56,7 +59,7 @@ const groupBucketsByMonth = (buckets: Buckets) => {
}

export const getMonthlyBucketsDailyAverage = (buckets: Buckets): Buckets => {
const monthlyBuckets = groupBucketsByMonth(buckets)
const monthlyBuckets = groupBucketsByDuration(buckets)

return monthlyBuckets?.map(item => ({
...item,
Expand All @@ -69,3 +72,40 @@ export const filterHourlyActiveAccounts = (
): ActiveAccounts[] | undefined => {
return windows?.filter((value, index) => index % 12 === 0)
}

type NumberOnly<T> = {
[key in keyof T as T[key] extends number | undefined ? key : never]: T[key]
}

type StringOnly<T> = {
[key in keyof T as T[key] extends string | undefined ? key : never]: T[key]
}

export const sumBucketsByStartDuration = <
T extends NumberOnly<any> & StringOnly<any>,
N extends keyof NumberOnly<T>,
S extends keyof StringOnly<T>,
>(
buckets: T[] | undefined,
sumKey: N,
dateKey: S,
startDurationFn: typeof startOfHour | typeof startOfDay | typeof startOfMonth,
) => {
if (!buckets) {
return []
}

const durationMap = buckets.reduce((accMap, item) => {
const key = startDurationFn(new Date(item[dateKey])).toISOString()

return {
...accMap,
[key]: (accMap[key] || 0) + item[sumKey],
}
}, {} as { [key: string]: number })

return Object.keys(durationMap).map(key => ({
[dateKey]: key,
[sumKey]: durationMap[key],
}))
}

0 comments on commit 14432c9

Please sign in to comment.