Skip to content

Commit

Permalink
feat: consistent decimal points (#1088)
Browse files Browse the repository at this point in the history
##  Closes #1074

### [ Summary ]
- Unify formatting utilities into one file
- Expand them to cover more cases
- Make 2 decimals as default
- Display full number of balance on hover over wallet card
- Sticked to using `Intl.NumberFormat` api for localized formatting

---------

Co-authored-by: Brian Pearce <[email protected]>
Co-authored-by: brianp <[email protected]>
  • Loading branch information
3 people authored Nov 22, 2024
1 parent a207f0f commit 643d847
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useTranslation } from 'react-i18next';

import { Typography } from '@app/components/elements/Typography.tsx';
import { Stack } from '@app/components/elements/Stack.tsx';
import { formatHashrate } from '@app/utils/formatHashrate.ts';
import { useMiningStore } from '@app/store/useMiningStore.ts';
import ConnectionStatus from '../connections/ConnectionStatus.tsx';

Expand All @@ -12,6 +11,7 @@ import {
SettingsGroupTitle,
SettingsGroupWrapper,
} from '../../components/SettingsGroup.styles.ts';
import { formatHashrate } from '@app/utils/formatters.ts';

export default function Network() {
const { t } = useTranslation('settings');
Expand Down
4 changes: 2 additions & 2 deletions src/containers/floating/ShareRewardModal/ShareRewardModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import gemImage from '../../main/Airdrop/AirdropGiftTracker/images/gem.png';
import { useEffect, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { GIFT_GEMS, useAirdropStore } from '@app/store/useAirdropStore';
import formatBalance from '@app/utils/formatBalance';
import { formatNumber, FormatPreset } from '@app/utils/formatters';

export type PaperWalletModalSectionType = 'Connect' | 'QRCode';

Expand Down Expand Up @@ -54,7 +54,7 @@ export default function ShareRewardModal() {
const gemsValue = (referralQuestPoints?.pointsForClaimingReferral || GIFT_GEMS).toLocaleString();
const block = item?.blockHeight || 0;
const reward = item?.amount || 0;
const earningsFormatted = useMemo(() => formatBalance(reward).toLowerCase(), [reward]);
const earningsFormatted = useMemo(() => formatNumber(reward, FormatPreset.TXTM_COMPACT).toLowerCase(), [reward]);

const shareUrl = `${airdropUrl}/download/${referralCode}?bh=${block}`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useWalletStore } from '@app/store/useWalletStore';
import { BlackButton, Text, Title } from '../../styles';
import { WalletText, Warning, Wrapper } from './styles';
import { useFormatBalance } from '@app/utils/formatBalance';
import { Trans, useTranslation } from 'react-i18next';
import LoadingSvg from '@app/components/svgs/LoadingSvg';
import { formatNumber, FormatPreset } from '@app/utils/formatters';

interface Props {
onButtonClick: () => void;
Expand All @@ -14,7 +14,7 @@ export default function ProtectIntro({ onButtonClick, isLoading }: Props) {
const { t } = useTranslation(['staged-security'], { useSuspense: false });

const balance = useWalletStore((state) => state.balance);
const formatted = useFormatBalance(balance || 0);
const formatted = formatNumber(balance || 0, FormatPreset.TXTM_COMPACT);

return (
<Wrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import GemsAnimation from '../GemsAnimation/GemsAnimation';
import { Background, Wrapper } from './styles';
import { Number, Text, TextBottom, TextBottomPosition } from '../styles';
import { useTranslation } from 'react-i18next';
import { useFormatNumber } from '@app/hooks/useFormatNumber';
import { formatNumber, FormatPreset } from '@app/utils/formatters';

interface Props {
gems: number;
Expand All @@ -12,7 +12,7 @@ interface Props {

export default function BonusGems({ gems, onAnimationComplete }: Props) {
const { t } = useTranslation('airdrop', { useSuspense: false });
const formatNumber = useFormatNumber();
const formattedNumber = formatNumber(gems, FormatPreset.DECIMAL_COMPACT);

useEffect(() => {
const timer = setTimeout(() => {
Expand All @@ -30,7 +30,7 @@ export default function BonusGems({ gems, onAnimationComplete }: Props) {
exit={{ opacity: 0, y: -20 }}
transition={{ delay: 0.5 }}
>
{formatNumber(gems, 1)}
{formattedNumber}
</Number>

<Text
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { AnimatePresence } from 'framer-motion';

import { EarningsContainer, EarningsWrapper, RecapText, WinText, WinWrapper } from './Earnings.styles.ts';
import { useFormatBalance } from '@app/utils/formatBalance.ts';

import CharSpinner from '@app/components/CharSpinner/CharSpinner.tsx';
import { Trans, useTranslation } from 'react-i18next';
import { useBlockchainVisualisationStore } from '@app/store/useBlockchainVisualisationStore.ts';
import { formatNumber, FormatPreset } from '@app/utils/formatters.ts';

const variants = {
visible: {
Expand Down Expand Up @@ -36,7 +36,7 @@ export default function Earnings() {

const displayEarnings = replayItem?.amount || recapData?.totalEarnings || earnings;

const formatted = useFormatBalance(displayEarnings || 0, 1);
const formatted = formatNumber(displayEarnings || 0, FormatPreset.TXTM_COMPACT);

const recapText = recapData?.totalEarnings ? (
<RecapText>
Expand Down
9 changes: 4 additions & 5 deletions src/containers/main/SideBar/Miner/Miner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import Tile from './components/Tile.tsx';
import { MinerContainer, TileContainer, Unit } from './styles.ts';

import ModeSelect from './components/ModeSelect.tsx';
import { formatHashrate } from '@app/utils/formatHashrate.ts';

import { useMiningStore } from '@app/store/useMiningStore.ts';
import { useFormatBalance } from '@app/utils/formatBalance.ts';
import { Typography } from '@app/components/elements/Typography.tsx';

import { useAppConfigStore } from '@app/store/useAppConfigStore.ts';
Expand All @@ -17,6 +15,7 @@ import {
ExpandableTileItem,
ExpandedContentTile,
} from '@app/containers/main/SideBar/Miner/components/ExpandableTile.styles.ts';
import { formatHashrate, formatNumber, FormatPreset } from '@app/utils/formatters.ts';

export default function Miner() {
const theme = useTheme();
Expand Down Expand Up @@ -46,9 +45,9 @@ export default function Miner() {
const totalEarnings = cpu_estimated_earnings + gpu_estimated_earnings;
const earningsLoading = totalEarnings <= 0 && (isWaitingForCPUHashRate || isWaitingForGPUHashRate);

const totalEarningsFormatted = useFormatBalance(totalEarnings);
const estimatedBalanceFormatted = useFormatBalance(cpu_estimated_earnings);
const gpuEstimatedEarnings = useFormatBalance(gpu_estimated_earnings);
const totalEarningsFormatted = formatNumber(totalEarnings, FormatPreset.TXTM_COMPACT);
const estimatedBalanceFormatted = formatNumber(cpu_estimated_earnings, FormatPreset.TXTM_COMPACT);
const gpuEstimatedEarnings = formatNumber(gpu_estimated_earnings, FormatPreset.TXTM_COMPACT);

return (
<MinerContainer>
Expand Down
4 changes: 2 additions & 2 deletions src/containers/main/SideBar/Miner/components/Tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { StatWrapper, TileItem, TileTop, Unit } from '../styles';
import truncateString from '@app/utils/truncateString.ts';
import { Typography } from '@app/components/elements/Typography.tsx';
import { Chip } from '@app/components/elements/Chip.tsx';
import { formatPercent } from '@app/utils/formatNumber.ts';
import { colorsAll } from '@app/theme/palettes/colors.ts';
import { SpinnerIcon } from '@app/components/elements/loaders/SpinnerIcon.tsx';
import { formatNumber, FormatPreset } from '@app/utils/formatters';

export interface TileProps {
title: string;
Expand All @@ -18,7 +18,7 @@ export interface TileProps {
function Tile({ title, stats, chipValue = 0, unit, isLoading = false, useLowerCase = false }: TileProps) {
const chipRange = Math.ceil(chipValue / 10);
const chipColor = colorsAll.ramp[chipRange];
const chipText = formatPercent(chipValue);
const chipText = formatNumber(chipValue, FormatPreset.PERCENT);

return (
<TileItem layoutId={`tile-item-${title}`}>
Expand Down
5 changes: 2 additions & 3 deletions src/containers/main/SideBar/components/Wallet/HistoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { Typography } from '@app/components/elements/Typography.tsx';
import { useTheme } from 'styled-components';
import { TariSvg } from '@app/assets/icons/tari.tsx';

import { useFormatBalance } from '@app/utils/formatBalance.ts';
import { useTranslation } from 'react-i18next';
import { useCallback, useMemo, useState } from 'react';
import { AnimatePresence } from 'framer-motion';
Expand All @@ -25,8 +24,8 @@ import { useShareRewardStore } from '@app/store/useShareRewardStore.ts';
import { Transaction } from '@app/types/wallet.ts';
import { GIFT_GEMS, useAirdropStore } from '@app/store/useAirdropStore.ts';
import { useAppConfigStore } from '@app/store/useAppConfigStore.ts';

import { ReplaySVG } from '@app/assets/icons/replay';
import { formatNumber, FormatPreset } from '@app/utils/formatters.ts';

interface HistoryItemProps {
item: Transaction;
Expand Down Expand Up @@ -57,7 +56,7 @@ export default function HistoryItem({ item }: HistoryItemProps) {
const handleWinReplay = useBlockchainVisualisationStore((s) => s.handleWinReplay);

const { t } = useTranslation('sidebar', { useSuspense: false });
const earningsFormatted = useFormatBalance(item.amount).toLowerCase();
const earningsFormatted = formatNumber(item.amount, FormatPreset.TXTM_COMPACT).toLowerCase();
const referralQuestPoints = useAirdropStore((s) => s.referralQuestPoints);
const airdropTokens = useAirdropStore((s) => s.airdropTokens);

Expand Down
16 changes: 10 additions & 6 deletions src/containers/main/SideBar/components/Wallet/Wallet.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useCallback, useState } from 'react';
import { useBlockchainVisualisationStore } from '@app/store/useBlockchainVisualisationStore';
import { useFormatBalance } from '@app/utils/formatBalance.ts';
import CharSpinner from '@app/components/CharSpinner/CharSpinner.tsx';
import {
BalanceVisibilityButton,
Expand All @@ -24,6 +23,7 @@ import useFetchTx from '@app/hooks/mining/useTransactions.ts';
import { usePaperWalletStore } from '@app/store/usePaperWalletStore.ts';
import { useAppConfigStore } from '@app/store/useAppConfigStore.ts';
import SyncTooltip from './SyncTooltip/SyncTooltip.tsx';
import { formatNumber, FormatPreset } from '@app/utils/formatters.ts';

export default function Wallet() {
const { t } = useTranslation('sidebar', { useSuspense: false });
Expand All @@ -37,12 +37,13 @@ export default function Wallet() {
const recapCount = useBlockchainVisualisationStore((s) => s.recapCount);
const setRecapCount = useBlockchainVisualisationStore((s) => s.setRecapCount);

const fetchTx = useFetchTx();
const formatted = useFormatBalance(balance || 0);
const sizing = formatted.length <= 6 ? 50 : formatted.length <= 8 ? 44 : 32;

const [showBalance, setShowBalance] = useState(true);
const [showHistory, setShowHistory] = useState(false);
const [showLongBalance, setShowLongBalance] = useState(false);

const fetchTx = useFetchTx();
const formatted = formatNumber(balance || 0, showLongBalance ? FormatPreset.TXTM_LONG : FormatPreset.TXTM_COMPACT);
const sizing = formatted.length <= 6 ? 50 : formatted.length <= 8 ? 44 : 32;

const toggleBalanceVisibility = () => setShowBalance((prev) => !prev);
const displayValue = balance === null ? '-' : showBalance ? formatted : '*****';
Expand All @@ -63,7 +64,10 @@ export default function Wallet() {
};

const balanceMarkup = (
<WalletBalanceContainer>
<WalletBalanceContainer
onMouseOver={() => setShowLongBalance(true)}
onMouseOut={() => setShowLongBalance(false)}
>
<Stack direction="row" alignItems="center">
<Typography variant="span" style={{ fontSize: '15px' }}>
{t('wallet-balance')}
Expand Down
9 changes: 0 additions & 9 deletions src/hooks/useFormatNumber.ts

This file was deleted.

20 changes: 0 additions & 20 deletions src/utils/formatBalance.ts

This file was deleted.

15 changes: 0 additions & 15 deletions src/utils/formatHashrate.ts

This file was deleted.

12 changes: 0 additions & 12 deletions src/utils/formatNumber.ts

This file was deleted.

66 changes: 66 additions & 0 deletions src/utils/formatters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import i18n from 'i18next';

export enum FormatPreset {
PERCENT = 'percent',
TXTM_COMPACT = 'txtm-compact',
TXTM_LONG = 'txtm-crypto',
DECIMAL_COMPACT = 'decimal-compact',
}

const removeDecimals = (value: number, decimals: number) => {
return value / Math.pow(10, decimals);
};

const removeTXTMCryptoDecimals = (value: number) => {
return removeDecimals(value, 6);
};

const formatValue = (value: number, options: Intl.NumberFormatOptions = {}): string =>
Intl.NumberFormat(i18n.language, options).format(value);

const formatPercent = (value = 0) => formatValue(value, { style: 'percent', maximumFractionDigits: 2 });

const formatTXTMCompact = (value: number) =>
formatValue(removeTXTMCryptoDecimals(value), {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
notation: 'compact',
style: 'decimal',
});

const formatTXTMLong = (value: number) =>
formatValue(removeTXTMCryptoDecimals(value), { maximumFractionDigits: 2, notation: 'standard', style: 'decimal' });

const formatDecimalCompact = (value: number) => formatValue(value, { maximumFractionDigits: 2, style: 'decimal' });

export function formatNumber(value: number, preset: FormatPreset): string {
switch (preset) {
case FormatPreset.PERCENT:
return formatPercent(value);
case FormatPreset.TXTM_COMPACT:
return formatTXTMCompact(value);
case FormatPreset.TXTM_LONG:
return formatTXTMLong(value);
case FormatPreset.DECIMAL_COMPACT:
return formatDecimalCompact(value);
default:
console.error('Unknown format preset:', preset);
return '-';
}
}

export function formatHashrate(hashrate: number, joinUnit = true): string {
if (hashrate < 1000) {
return joinUnit ? hashrate + ' H/s' : hashrate.toFixed(2);
} else if (hashrate < 1000000) {
return (hashrate / 1000).toFixed(2) + (joinUnit ? ' kH/s' : 'k');
} else if (hashrate < 1000000000) {
return (hashrate / 1000000).toFixed(2) + (joinUnit ? ' MH/s' : 'M');
} else if (hashrate < 1000000000000) {
return (hashrate / 1000000000).toFixed(2) + (joinUnit ? ' GH/s' : 'G');
} else if (hashrate < 1000000000000000) {
return (hashrate / 1000000000000).toFixed(2) + (joinUnit ? ' TH/s' : 'T');
} else {
return (hashrate / 1000000000000000).toFixed(2) + (joinUnit ? ' PH/s' : 'P');
}
}

0 comments on commit 643d847

Please sign in to comment.