Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format all numbers with BigNumber #333

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come not number.decimalPlaces

}
const wantedFormat = { ...BigNumber.config().FORMAT, ...formatting }
const numberString =
decimalPlaces === undefined
? number.toFormat(wantedFormat)
: roundingMode === undefined
? number.toFormat(decimalPlaces, wantedFormat)
: number.toFormat(decimalPlaces, roundingMode, wantedFormat)
Comment on lines +33 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If bignumber types weren't broken I would modify to:

  return (
    inputNumber: number | string | BigNumber.Instance | undefined,
    format: NumberFormattingParameters = { roundingMode: BigNumber.ROUND_DOWN },
  ): string | undefined => {
  
    const numberString = 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 })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#731 (comment)
We might be able to simplify a lot

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