core: throttle lock wallet query

This commit is contained in:
theborakompanioni 2026-03-24 22:55:00 +01:00
parent 9435632382
commit 0aaa055ccd
No known key found for this signature in database
GPG key ID: E8070AF0053AAC0D
5 changed files with 38 additions and 37 deletions

View file

@ -100,17 +100,6 @@ const withI18next = (Story: React.ComponentType, context: GlobalContext) => {
)
}
export const withJamDisplayContent = (Story: React.ComponentType) => {
const queryClient = new QueryClient()
return (
<JamDisplayContextProvider>
<Story />
</JamDisplayContextProvider>
)
}
// Use only when necessary! Try to pass data from queries to
// components so they can be tested independently from an API.
export const withQueryClient = (Story: React.ComponentType) => {
const queryClient = new QueryClient()
return (
@ -120,7 +109,16 @@ export const withQueryClient = (Story: React.ComponentType) => {
)
}
export const withJamDisplayContent = (Story: React.ComponentType) => {
const queryClient = new QueryClient()
return (
<JamDisplayContextProvider>
<Story />
</JamDisplayContextProvider>
)
}
// export decorators for storybook to wrap your stories in
export const decorators = [withTheme, withMemoryRouter, withI18next, withJamDisplayContent]
export const decorators = [withTheme, withMemoryRouter, withI18next, withQueryClient, withJamDisplayContent]
export default preview

View file

@ -2,7 +2,7 @@ import { lazy, Suspense, useEffect, useMemo, useState } from 'react'
import type { PropsWithChildren } from 'react'
import { lockwalletOptions } from '@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query'
import { token } from '@joinmarket-webui/joinmarket-api-ts/jm'
import { QueryClientProvider, useQuery } from '@tanstack/react-query'
import { QueryClientProvider, useMutation, useQuery } from '@tanstack/react-query'
import type { TFunction } from 'i18next'
import { ThemeProvider } from 'next-themes'
import { useTranslation } from 'react-i18next'
@ -41,7 +41,7 @@ import { JamWalletInfoContextProvider } from '@/context/JamWalletInfoContextProv
import { useApiClient } from '@/hooks/useApiClient'
import { useFeeConfigValidation } from '@/hooks/useFeeConfigValidation'
import { useRefreshSession } from '@/hooks/useRefreshSession'
import { queryClient } from '@/lib/queryClient'
import { queryClient, withMutationDelay } from '@/lib/queryClient'
import { setIntervalDebounced, walletDisplayName, type WalletFileName } from '@/lib/utils'
import { authStore } from '@/store/authStore'
import { jamSettingsStore, useDeveloperMode } from '@/store/jamSettingsStore'
@ -95,12 +95,26 @@ function App() {
client,
path: { walletname: encodeURIComponent(walletFileName || '') },
}),
staleTime: 1,
gcTime: 1,
enabled: false,
},
queryClient,
)
const lockWalletMutation = useMutation(
{
scope: { id: 'lock-wallet' },
mutationFn: withMutationDelay(
async () => {
return await lockWalletQuery.refetch({ throwOnError: true })
},
{
throttle: 210,
},
),
retry: false,
},
queryClient,
)
const [lockWalletDialogContext, setLockWalletDialogContext] = useState<LockWalletDialogContext>()
const doOnLogout = async (navigate: NavigateFunction) => {
@ -125,7 +139,7 @@ function App() {
const doOnLockWalletConfirm = async (navigate: NavigateFunction, t: TFunction<'translation', undefined>) => {
if (!walletFileName) return
try {
await lockWalletQuery.refetch({ throwOnError: true })
await lockWalletMutation.mutateAsync()
toast.success(
t('wallets.wallet_preview.alert_wallet_locked_successfully', { walletName: walletDisplayName(walletFileName) }),
)
@ -251,7 +265,6 @@ function App() {
open={lockWalletDialogContext?.open}
onOpenChange={() => setLockWalletDialogContext(undefined)}
onConfirm={() => doOnLockWalletConfirm(lockWalletDialogContext?.navigate, lockWalletDialogContext?.t)}
isLocking={lockWalletQuery.isFetching}
makerRunning={makerRunning}
coinjoinInProgress={coinjoinInProgress}
/>

View file

@ -1,4 +1,5 @@
import { type ComponentProps } from 'react'
import { useMutation } from '@tanstack/react-query'
import { AlertTriangleIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Alert, AlertDescription } from '@/components/ui/alert'
@ -12,7 +13,6 @@ type LockWalletConfirmDialogProps = WithRequiredProperty<
'open' | 'onOpenChange'
> & {
onConfirm: () => Promise<void>
isLocking: boolean
makerRunning: boolean
coinjoinInProgress: boolean
}
@ -21,13 +21,17 @@ export const LockWalletConfirmDialog = ({
open,
onOpenChange,
onConfirm,
isLocking,
makerRunning,
coinjoinInProgress,
...dialogProps
}: LockWalletConfirmDialogProps) => {
const { t } = useTranslation()
const confirmMutation = useMutation({
mutationFn: onConfirm,
retry: false,
})
return (
<Dialog open={open} onOpenChange={onOpenChange} {...dialogProps}>
<DialogContent className="max-w-md">
@ -50,11 +54,11 @@ export const LockWalletConfirmDialog = ({
)}
<p className="text-muted-foreground">{t('wallets.wallet_preview.modal_lock_wallet_alternative_action_text')}</p>
<DialogFooter>
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={isLocking}>
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={confirmMutation.isPending}>
{t('global.cancel')}
</Button>
<Button variant="default" onClick={() => void onConfirm()} disabled={isLocking}>
{isLocking ? (
<Button variant="default" onClick={() => void onConfirm()} disabled={confirmMutation.isPending}>
{confirmMutation.isPending ? (
<>
<Spinner className="motion-reduce:hidden" />
{t('wallets.wallet_preview.button_locking')}

View file

@ -1,13 +1,11 @@
import type { ComponentProps } from 'react'
import type { Meta, StoryObj } from '@storybook/react-vite'
import { AppNavbar } from '@/components/layout/AppNavbar'
import { withQueryClient } from '../../../.storybook/preview'
const meta: Meta<typeof AppNavbar> = {
title: 'Layout/AppNavbar',
component: AppNavbar,
tags: ['autodocs'],
decorators: [withQueryClient],
}
export default meta

View file

@ -25,7 +25,6 @@ export const Default: Story = {
args: {
coinjoinInProgress: false,
makerRunning: false,
isLocking: false,
onConfirm: async () => alert('Confirm clicked!'),
},
}
@ -34,7 +33,6 @@ export const MakerRunning: Story = {
args: {
coinjoinInProgress: false,
makerRunning: true,
isLocking: false,
onConfirm: async () => alert('Confirm clicked!'),
},
}
@ -43,16 +41,6 @@ export const CoinjoinInProgress: Story = {
args: {
coinjoinInProgress: true,
makerRunning: false,
isLocking: false,
onConfirm: async () => alert('Confirm clicked!'),
},
}
export const Locking: Story = {
args: {
coinjoinInProgress: true,
makerRunning: false,
isLocking: true,
onConfirm: async () => alert('Confirm clicked!'),
},
}