Skip to content

Commit

Permalink
Use BigNumber for number formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
csillag committed May 16, 2023
1 parent 745371e commit 84a2c50
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 59 deletions.
4 changes: 3 additions & 1 deletion src/app/components/Account/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { AccountLink } from './AccountLink'
import { RouteUtils } from '../../utils/route-utils'
import { accountTransactionsContainerId } from '../../pages/AccountDetailsPage/TransactionsCard'
import Link from '@mui/material/Link'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

export const StyledAvatarContainer = styled('dt')(({ theme }) => ({
'&&': {
Expand Down Expand Up @@ -53,6 +54,7 @@ type AccountProps = {

export const Account: FC<AccountProps> = ({ account, isLoading, roseFiatValue, showLayer }) => {
const { t } = useTranslation()
const formatNumber = useFormatNumber()
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const balance = account?.balances[0]?.balance ?? '0'
Expand Down Expand Up @@ -108,7 +110,7 @@ export const Account: FC<AccountProps> = ({ account, isLoading, roseFiatValue, s
<dt>{t('common.transactions')}</dt>
<dd>
<Link component={RouterLink} to={transactionsAnchor!}>
{t('common.transactionsNumber', { count: account.stats.num_txns })}
{formatNumber(account.stats.num_txns, { countKey: 'common.transactionsNumber' })}
</Link>
</dd>

Expand Down
18 changes: 11 additions & 7 deletions src/app/components/Blocks/BlockLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ import Link from '@mui/material/Link'
import { Layer } from '../../../oasis-indexer/api'
import { RouteUtils } from '../../utils/route-utils'
import { TrimLinkLabel } from '../TrimLinkLabel'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

export const BlockLink: FC<{ layer: Layer; height: number }> = ({ layer, height }) => (
<Typography variant="mono">
<Link component={RouterLink} to={RouteUtils.getBlockRoute(height, layer)}>
{height.toLocaleString()}
</Link>
</Typography>
)
export const BlockLink: FC<{ layer: Layer; height: number }> = ({ layer, height }) => {
const formatNumber = useFormatNumber()
return (
<Typography variant="mono">
<Link component={RouterLink} to={RouteUtils.getBlockRoute(height, layer)}>
{formatNumber(height)}
</Link>
</Typography>
)
}

export const BlockHashLink: FC<{ layer: Layer; hash: string; height: number }> = ({
layer,
Expand Down
22 changes: 9 additions & 13 deletions src/app/components/Blocks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Table, TableCellAlign, TableColProps } from '../../components/Table'
import { paraTimesConfig } from '../../../config'
import { TablePaginationProps } from '../Table/TablePagination'
import { BlockHashLink, BlockLink } from './BlockLink'
import { useFormatNumber } from '../../hooks/useNumberFormatter'
import { FC } from 'react'

export type TableRuntimeBlock = RuntimeBlock & {
markAsNew?: boolean
Expand All @@ -25,9 +27,10 @@ type BlocksProps = {
pagination: false | TablePaginationProps
}

export const Blocks = (props: BlocksProps) => {
export const Blocks: FC<BlocksProps> = (props: BlocksProps) => {
const { isLoading, blocks, verbose, pagination, limit } = props
const { t } = useTranslation()
const formatNumber = useFormatNumber()

const tableColumns: TableColProps[] = [
{ content: t('common.fill') },
Expand Down Expand Up @@ -66,7 +69,7 @@ export const Blocks = (props: BlocksProps) => {
},
{
align: TableCellAlign.Right,
content: block.num_transactions,
content: formatNumber(block.num_transactions),
key: 'txs',
},
...(verbose
Expand All @@ -79,23 +82,16 @@ export const Blocks = (props: BlocksProps) => {
: []),
{
align: TableCellAlign.Right,
content: t('common.bytes', {
value: block.size,
formatParams: {
value: {
style: 'unit',
unit: 'byte',
unitDisplay: 'long',
} satisfies Intl.NumberFormatOptions,
},
content: formatNumber(block.size, {
unit: 'byte',
}),
key: 'size',
},
...(verbose
? [
{
align: TableCellAlign.Right,
content: block.gas_used.toLocaleString(),
content: formatNumber(block.gas_used),
key: 'gasUsed',
},
]
Expand All @@ -104,7 +100,7 @@ export const Blocks = (props: BlocksProps) => {
? [
{
align: TableCellAlign.Right,
content: blockGasLimit.toLocaleString(),
content: formatNumber(blockGasLimit),
key: 'gasLimit',
},
]
Expand Down
60 changes: 60 additions & 0 deletions src/app/hooks/useNumberFormatter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { BigNumber } from 'bignumber.js'
import { useTranslation } from 'react-i18next'

export type NumberFormattingParameters = Partial<BigNumber.Format> & {
// Additional features which are not natively supported by BigNumber

decimalPlaces?: number
maximumFractionDigits?: number
roundingMode?: BigNumber.RoundingMode
unit?: string
countKey?: string
}

export const useFormatNumber = () => {
const { t } = useTranslation()
return (
inputNumber: number | string | BigNumber.Instance | undefined,
format: NumberFormattingParameters = {},
): string | undefined => {
if (inputNumber === undefined) return
const { decimalPlaces, maximumFractionDigits, roundingMode, unit, countKey, ...formatting } = format
if (!!unit && !!countKey) {
throw new Error("Please don't try to use unit and countKey together! They are incompatible.")
}
let number =
typeof inputNumber === 'number'
? BigNumber(inputNumber.toString(2), 2) // This is required to keep all precision
: BigNumber(inputNumber)
if (maximumFractionDigits !== undefined) {
number = BigNumber(number.toFixed(maximumFractionDigits, roundingMode))
}
const wantedFormat = { ...BigNumber.config().FORMAT, ...formatting }
const numberString =
decimalPlaces === undefined
? number.toFormat(wantedFormat)
: roundingMode === undefined
? number.toFormat(decimalPlaces, wantedFormat)
: number.toFormat(decimalPlaces, roundingMode, wantedFormat)
if (unit) {
const formattedUnit = Intl.NumberFormat(undefined, {
style: 'unit',
unit,
unitDisplay: 'long',
})
.formatToParts(number.toNumber())
.find(p => p.type === 'unit')!.value
return `${numberString} ${formattedUnit}`
} else if (countKey) {
const num: number = number.toNumber()
if (num === 1) {
return t(countKey as any, { count: 1 })
} else {
const i18nForm = t('common.number', { value: num })
return t(countKey as any, { count: num }).replace(i18nForm, numberString)
}
} else {
return numberString
}
}
}
19 changes: 7 additions & 12 deletions src/app/pages/BlockDetailPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { transactionsContainerId } from './TransactionsCard'
import { useLayerParam } from '../../hooks/useLayerParam'
import { BlockLink, BlockHashLink } from '../../components/Blocks/BlockLink'
import { RouteUtils } from '../../utils/route-utils'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

export const BlockDetailPage: FC = () => {
const { t } = useTranslation()
Expand Down Expand Up @@ -58,6 +59,7 @@ export const BlockDetailView: FC<{
standalone?: boolean
}> = ({ isLoading, block, showLayer, standalone = false }) => {
const { t } = useTranslation()
const formatNumber = useFormatNumber()
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const formattedTime = useFormattedTimestampString(block?.timestamp)
Expand Down Expand Up @@ -100,29 +102,22 @@ export const BlockDetailView: FC<{

<dt>{t('common.size')}</dt>
<dd>
{t('common.bytes', {
value: block.size,
formatParams: {
value: {
style: 'unit',
unit: 'byte',
unitDisplay: 'long',
} satisfies Intl.NumberFormatOptions,
},
{formatNumber(block.size, {
unit: 'byte',
})}
</dd>

<dt>{t('common.transactions')}</dt>
<dd>
<Link href={transactionsAnchor}>
{t('common.transactionsNumber', { count: block.num_transactions })}
{formatNumber(block.num_transactions, { countKey: 'common.transactionsNumber' })}
</Link>
</dd>

<dt>{t('common.gasUsed')}</dt>
<dd>
{t('block.gasUsed', {
value: block.gas_used,
value: formatNumber(block.gas_used),
percentage: block.gas_used / blockGasLimit,
formatParams: {
percentage: {
Expand All @@ -134,7 +129,7 @@ export const BlockDetailView: FC<{
</dd>

<dt>{t('common.gasLimit')}</dt>
<dd>{blockGasLimit.toLocaleString()}</dd>
<dd>{formatNumber(blockGasLimit)}</dd>
</StyledDescriptionList>
)
}
10 changes: 7 additions & 3 deletions src/app/pages/DashboardPage/ActiveAccounts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
sumBucketsByStartDuration,
} from '../../utils/chart-utils'
import { useLayerParam } from '../../hooks/useLayerParam'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

export const getActiveAccountsWindows = (duration: ChartDuration, windows: Windows[]) => {
switch (duration) {
Expand Down Expand Up @@ -60,6 +61,7 @@ export const ActiveAccounts: FC<ActiveAccountsProps> = ({ chartDuration }) => {
const { t } = useTranslation()
const { limit, bucket_size_seconds } = durationToQueryParams[chartDuration]
const layer = useLayerParam()
const formatNumber = useFormatNumber()
const activeAccountsQuery = useGetLayerStatsActiveAccounts(
layer,
{
Expand All @@ -80,8 +82,10 @@ export const ActiveAccounts: FC<ActiveAccountsProps> = ({ chartDuration }) => {
getActiveAccountsWindows(chartDuration, activeAccountsQuery.data?.data?.windows)
const totalNumberLabel =
dailyChart && windows?.length
? windows[0].active_accounts.toLocaleString()
: windows?.reduce((acc, curr) => acc + curr.active_accounts, 0).toLocaleString()
? formatNumber(windows[0].active_accounts)
: windows
? formatNumber(windows.reduce((acc, curr) => acc + curr.active_accounts, 0))
: undefined

return (
<SnapshotCard title={t('activeAccounts.title')} label={totalNumberLabel}>
Expand All @@ -93,7 +97,7 @@ export const ActiveAccounts: FC<ActiveAccountsProps> = ({ chartDuration }) => {
formatters={{
data: (value: number) =>
t('activeAccounts.tooltip', {
value,
value: formatNumber(value),
}),
label: (value: string) =>
t('common.formattedDateTime', {
Expand Down
4 changes: 3 additions & 1 deletion src/app/pages/DashboardPage/Nodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { COLORS } from '../../../styles/theme/colors'
import { Layer, useGetRuntimeStatus } from '../../../oasis-indexer/api'
import { useLayerParam } from '../../hooks/useLayerParam'
import { AppErrors } from '../../../types/errors'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

export const Nodes: FC = () => {
const { t } = useTranslation()
const formatNumber = useFormatNumber()
const layer = useLayerParam()
if (layer === Layer.consensus) {
throw AppErrors.UnsupportedLayer
Expand All @@ -25,7 +27,7 @@ export const Nodes: FC = () => {
<>
<OfflineBoltIcon fontSize="large" sx={{ color: COLORS.eucalyptus, mr: 3 }} />
<Typography component="span" sx={{ fontSize: '48px', fontWeight: 700, color: COLORS.brandDark }}>
{t('nodes.value', { value: activeNodes })}
{formatNumber(activeNodes)}
</Typography>
</>
)}
Expand Down
11 changes: 5 additions & 6 deletions src/app/pages/DashboardPage/TotalTransactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import { DurationPills } from './DurationPills'
import { CardHeaderWithResponsiveActions } from './CardHeaderWithResponsiveActions'
import { ChartDuration, cumulativeSum } from '../../utils/chart-utils'
import { useLayerParam } from '../../hooks/useLayerParam'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

export const TotalTransactions: FC = () => {
const { t } = useTranslation()
const formatNumber = useFormatNumber()
const [chartDuration, setChartDuration] = useState<ChartDuration>(ChartDuration.MONTH)
const statsParams = durationToQueryParams[chartDuration]
const layer = useLayerParam()
Expand Down Expand Up @@ -47,12 +49,9 @@ export const TotalTransactions: FC = () => {
formatters={{
data: (value: number) =>
t('totalTransactions.tooltip', {
value,
formatParams: {
value: {
maximumFractionDigits: 2,
} satisfies Intl.NumberFormatOptions,
},
value: formatNumber(value, {
maximumFractionDigits: 2,
})!,
}),
label: (value: string) =>
t('common.formattedDateTime', {
Expand Down
13 changes: 6 additions & 7 deletions src/app/pages/DashboardPage/TransactionsChartCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ import { SnapshotCard } from './SnapshotCard'
import { PercentageGain } from '../../components/PercentageGain'
import startOfHour from 'date-fns/startOfHour'
import { useLayerParam } from '../../hooks/useLayerParam'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

interface TransactionsChartCardProps {
chartDuration: ChartDuration
}

const TransactionsChartCardCmp: FC<TransactionsChartCardProps> = ({ chartDuration }) => {
const { t } = useTranslation()
const formatNumber = useFormatNumber()
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const statsParams = durationToQueryParams[chartDuration]
Expand Down Expand Up @@ -67,7 +69,7 @@ const TransactionsChartCardCmp: FC<TransactionsChartCardProps> = ({ chartDuratio
/>
)
}
label={totalTransactions.toLocaleString()}
label={formatNumber(totalTransactions)}
>
{lineChartData && (
<LineChart
Expand All @@ -77,12 +79,9 @@ const TransactionsChartCardCmp: FC<TransactionsChartCardProps> = ({ chartDuratio
formatters={{
data: (value: number) =>
t('transactionsTpsChart.tooltip', {
value,
formatParams: {
value: {
maximumFractionDigits: 2,
} satisfies Intl.NumberFormatOptions,
},
value: formatNumber(value, {
maximumFractionDigits: 2,
}),
}),
label: (value: string) =>
t('common.formattedDateTime', {
Expand Down
4 changes: 3 additions & 1 deletion src/app/pages/DashboardPage/TransactionsStats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import { DurationPills } from './DurationPills'
import { CardHeaderWithResponsiveActions } from './CardHeaderWithResponsiveActions'
import { ChartDuration } from '../../utils/chart-utils'
import { useLayerParam } from '../../hooks/useLayerParam'
import { useFormatNumber } from '../../hooks/useNumberFormatter'

export const TransactionsStats: FC = () => {
const { t } = useTranslation()
const formatNumber = useFormatNumber()
const [chartDuration, setChartDuration] = useState<ChartDuration>(ChartDuration.MONTH)
const statsParams = durationToQueryParams[chartDuration]
const layer = useLayerParam()
Expand Down Expand Up @@ -55,7 +57,7 @@ export const TransactionsStats: FC = () => {
data={buckets.slice().reverse()}
dataKey="tx_volume"
formatters={{
data: (value: number) => t('transactionStats.tooltip', { value: value.toLocaleString() }),
data: (value: number) => t('transactionStats.tooltip', { value: formatNumber(value) }),
label: (value: string) =>
t('common.formattedDateTime', {
timestamp: new Date(value),
Expand Down
Loading

0 comments on commit 84a2c50

Please sign in to comment.