diff --git a/src/components/layout/AppNavbar.tsx b/src/components/layout/AppNavbar.tsx index 2d4b6df9..58088d36 100644 --- a/src/components/layout/AppNavbar.tsx +++ b/src/components/layout/AppNavbar.tsx @@ -60,11 +60,11 @@ const WalletPreview = ({
{rescanInfo?.rescanning === true ? (
- {rescanInfo.progress !== undefined - ? t('navbar.text_rescan_in_progress_with_progress', { - progress: Math.floor(rescanInfo.progress * 100), - }) - : t('navbar.text_rescan_in_progress')} + {rescanInfo.progressInPercentage === undefined + ? t('navbar.text_rescan_in_progress') + : t('navbar.text_rescan_in_progress_with_progress', { + progress: rescanInfo.progressInPercentage, + })}
) : ( <> diff --git a/src/components/settings/RescanChainPage.test.tsx b/src/components/settings/RescanChainPage.test.tsx index a9f343bc..21324ed9 100644 --- a/src/components/settings/RescanChainPage.test.tsx +++ b/src/components/settings/RescanChainPage.test.tsx @@ -87,7 +87,7 @@ const renderPage = async () => { describe('RescanChainPage', () => { beforeEach(() => { vi.clearAllMocks() - rescanInfo = { updatedAt: 0, rescanning: false, progress: undefined } + rescanInfo = { updatedAt: 0, rescanning: false, progress: undefined, progressInPercentage: undefined } }) it('renders the form and navigates back', async () => { @@ -105,7 +105,7 @@ describe('RescanChainPage', () => { }) it('shows the in-progress alert with progress', async () => { - rescanInfo = { updatedAt: 0, rescanning: true, progress: 42 } + rescanInfo = { updatedAt: 0, rescanning: true, progress: 0.4221, progressInPercentage: '42.2' } await renderPage() expect(screen.getByText(/app.alert_rescan_in_progress_with_progress/)).toBeInTheDocument() }) @@ -113,15 +113,15 @@ describe('RescanChainPage', () => { it('submits a valid block height through the mutation', async () => { await renderPage() const input = screen.getByPlaceholderText('rescan_chain.placeholder_blockheight') - fireEvent.change(input, { target: { value: '700000' } }) + fireEvent.change(input, { target: { value: String(700_000) } }) fireEvent.submit(input.closest('form')!) - await waitFor(() => expect(mutateAsync).toHaveBeenCalledWith(700000)) + await waitFor(() => expect(mutateAsync).toHaveBeenCalledWith(700_000)) }) it('mutationFn calls the rescan API and returns data', async () => { await renderPage() - await expect(mutationConfig.mutationFn(700000)).resolves.toBe('ok') + await expect(mutationConfig.mutationFn(700_000)).resolves.toBe('ok') expect(rescanblockchainMock).toHaveBeenCalled() }) diff --git a/src/components/settings/RescanChainPage.tsx b/src/components/settings/RescanChainPage.tsx index 45b7dc5c..2fc8426f 100644 --- a/src/components/settings/RescanChainPage.tsx +++ b/src/components/settings/RescanChainPage.tsx @@ -124,7 +124,6 @@ export const RescanChainPage = ({ walletFileName }: RescanChainProps) => { setRescanInfo({ updatedAt: Date.now(), rescanning: true, - progress: undefined, }) }, onError: (error: unknown) => { @@ -133,7 +132,6 @@ export const RescanChainPage = ({ walletFileName }: RescanChainProps) => { setRescanInfo({ updatedAt: Date.now(), rescanning: false, - progress: undefined, }) const reason = getErrorReason(error, t('global.errors.reason_unknown')) @@ -181,10 +179,10 @@ export const RescanChainPage = ({ walletFileName }: RescanChainProps) => {
- {rescanInfo?.progress === undefined + {rescanInfo?.progressInPercentage === undefined ? t('app.alert_rescan_in_progress') : t('app.alert_rescan_in_progress_with_progress', { - progress: rescanInfo.progress, + progress: rescanInfo.progressInPercentage, })}
diff --git a/src/context/JamSessionInfoContext.ts b/src/context/JamSessionInfoContext.ts index 70f7fae6..685efe3b 100644 --- a/src/context/JamSessionInfoContext.ts +++ b/src/context/JamSessionInfoContext.ts @@ -1,11 +1,13 @@ import { createContext, useContext, type Dispatch, type SetStateAction } from 'react' import type { SendFormValues } from '@/components/send/types' import type { WalletFileName } from '@/lib/utils' +import type { Factor } from '@/types/global' export interface RescanInfo { updatedAt: number rescanning: boolean - progress?: number + progress?: Factor + progressInPercentage?: string } export interface PaymentAttempt { diff --git a/src/context/JamSessionInfoContextProvider.tsx b/src/context/JamSessionInfoContextProvider.tsx index 0f75861a..26eef026 100644 --- a/src/context/JamSessionInfoContextProvider.tsx +++ b/src/context/JamSessionInfoContextProvider.tsx @@ -7,7 +7,7 @@ import { createJSONStorage, persist } from 'zustand/middleware' import { JAM_RESCAN_PROGRESS_INTERVAL } from '@/constants/jam' import { useApiClient } from '@/hooks/useApiClient' import { withQueryDelay } from '@/lib/queryClient' -import type { WalletFileName } from '@/lib/utils' +import { factorToPercentage, type WalletFileName } from '@/lib/utils' import { jmSessionStore } from '@/store/jmSessionStore' import { JamSessionInfoContext } from './JamSessionInfoContext' import type { PaymentAttempt, RescanInfo, TakerInfo } from './JamSessionInfoContext' @@ -92,10 +92,12 @@ export const JamSessionInfoContextProvider = ({ const isRescanning = getrescaninfoQuery.data.rescanning || state?.rescanning === true const rescanningFinished = getrescaninfoQuery.data.rescanning === false && state?.rescanning === true + const progress = rescanningFinished ? 1 : getrescaninfoQuery.data.progress setRescanInfo({ updatedAt: getrescaninfoQuery.dataUpdatedAt, rescanning: isRescanning, - progress: rescanningFinished ? 1 : getrescaninfoQuery.data.progress, + progress: progress, + progressInPercentage: progress === undefined ? undefined : factorToPercentage(progress).toFixed(1), }) } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 8ab64db5..e6f0ffd0 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,7 +1,7 @@ import { type ClassValue, clsx } from 'clsx' import { twMerge } from 'tailwind-merge' import { JM_WALLET_FILE_EXTENSION, type OfferType } from '@/constants/jm' -import type { Milliseconds, MnemonicPhrase } from '@/types/global' +import type { Factor, Milliseconds, MnemonicPhrase } from '@/types/global' const HORIZONTAL_ELLIPSIS = '\u2026' // Horizontal Ellipsis `…` @@ -145,14 +145,6 @@ export const BITCOIN_GENESIS_DATE = new Date('2009-01-03T18:15:05Z') export const DUMMY_SEED_PHRASE: MnemonicPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'.split(' ') -export const percentageToFactorString = (val: number, precision = 6) => { - return (val / 100).toFixed(precision) -} - -export const percentageToFactor = (val: number, precision = 6) => { - return Number(percentageToFactorString(val, precision)) -} - export const isValidNumber = (val: unknown): val is number => { return Number.isFinite(val) } @@ -215,13 +207,21 @@ export const formatSats = (value: number) => { }) } -export const factorToPercentage = (val: number, precision = 6) => { +export const factorToPercentage = (val: Factor, precision = 6) => { // Value cannot just be multiplied // e.g. ✗ 0.000027 * 100 == 0.0026999999999999997 // but: ✓ Number((0.000027 * 100).toFixed(6)) = 0.0027 return Number((val * 100).toFixed(precision)) } +export const percentageToFactorString = (val: number, precision = 6) => { + return (val / 100).toFixed(precision) +} + +export const percentageToFactor = (val: number, precision = 6): Factor => { + return Number(percentageToFactorString(val, precision)) +} + export type SemanticVersion = { major: number; minor: number; patch: number; raw?: string } export const UNKNOWN_VERSION: SemanticVersion = { major: 0, minor: 0, patch: 0, raw: 'unknown' }