diff --git a/src/components/earn/fidelity-bond/useFidelityBondMutations.ts b/src/components/earn/fidelity-bond/useFidelityBondMutations.ts
index 51249c08..c47f4d5a 100644
--- a/src/components/earn/fidelity-bond/useFidelityBondMutations.ts
+++ b/src/components/earn/fidelity-bond/useFidelityBondMutations.ts
@@ -26,16 +26,19 @@ export function useFidelityBondMutations({
const freezeUtxo = useMutation({
...freezeMutation({ client }),
+ retry: false,
onError: (error) => setErrorWithReason(error, t('global.errors.error_freezing_utxos')),
})
const unfreezeUtxo = useMutation({
...freezeMutation({ client }),
+ retry: false,
onError: (error) => setErrorWithReason(error, t(unfreezeErrorKey)),
})
const directSend = useMutation({
...directsendMutation({ client }),
+ retry: false,
onError: (error) => setErrorWithReason(error, t(sendErrorKey)),
})
diff --git a/src/components/wallet/WalletJarsDetailsContent.test.tsx b/src/components/wallet/WalletJarsDetailsContent.test.tsx
index b9559bcf..0059db97 100644
--- a/src/components/wallet/WalletJarsDetailsContent.test.tsx
+++ b/src/components/wallet/WalletJarsDetailsContent.test.tsx
@@ -5,8 +5,13 @@ import type { AccountMeta, AccountSummary, AddressMeta, AddressSummary, Jar } fr
import type { Utxo } from '@/hooks/useQueryUtxos'
import { WalletJarsDetailsContent } from './WalletJarsDetailsContent'
-const walletInfoRefetch = vi.hoisted(() => vi.fn())
-const toastMocks = vi.hoisted(() => ({ success: vi.fn(), warning: vi.fn() }))
+const { walletInfoRefetch, toastMocks, ...mocks } = vi.hoisted(() => ({
+ walletInfoRefetch: vi.fn(),
+ toastMocks: { success: vi.fn(), warning: vi.fn() },
+ rescanning: false,
+ takerRunning: false,
+ makerRunning: false,
+}))
vi.mock('sonner', () => ({
toast: {
@@ -50,6 +55,14 @@ vi.mock('../ui/jam/Balance', () => ({
Balance: ({ valueString }: { valueString: string }) => {valueString},
}))
+vi.mock('@/context/JamSessionInfoContext', () => ({
+ useJamSessionInfoContext: () => ({
+ takerInfo: { running: mocks.takerRunning },
+ rescanInfo: { rescanning: mocks.rescanning },
+ makerInfo: { running: mocks.makerRunning },
+ }),
+}))
+
const makeUtxo = (overrides: Partial): Utxo =>
({
address: 'bc1qwallet-a',
@@ -146,32 +159,51 @@ describe('WalletJarsDetailsContent', () => {
walletInfoRefetch.mockResolvedValue({})
toastMocks.success.mockReset()
toastMocks.warning.mockReset()
+ mocks.rescanning = false
+ mocks.takerRunning = false
+ mocks.makerRunning = false
+ // vi.resetAllMocks()
+ })
+
+ it('renders successfully', () => {
+ render()
+
+ const jarTab = screen.getByRole('tab', { name: jars[0].name })
+ expect(jarTab).toHaveAttribute('data-state', 'active')
+ expect(screen.getByText('bc1qwallet-a')).toBeInTheDocument()
})
it('renders selected jar UTXOs and debug details', async () => {
const user = userEvent.setup()
+ const jar = jars[1]
- render()
+ render()
- expect(screen.getByRole('tab', { name: 'One' })).toHaveAttribute('data-state', 'active')
+ const jarTab = screen.getByRole('tab', { name: jar.name })
+ expect(jarTab).toHaveAttribute('data-state', 'active')
expect(screen.getByText('bc1qwallet-b')).toBeInTheDocument()
- await user.click(screen.getByRole('tab', { name: /Dev/u }))
+ const devTab = screen.getByRole('tab', { name: /Dev/u })
+ await user.click(devTab)
expect(screen.getByText('activeJar:')).toBeInTheDocument()
})
it('switches jars with keyboard shortcuts and shows missing account information', async () => {
const user = userEvent.setup()
+ const jar = jars[1]
- render()
+ render()
expect(screen.getByText('bc1qwallet-b')).toBeInTheDocument()
await user.keyboard('{ArrowLeft}')
+
expect(screen.getByText('bc1qwallet-a')).toBeInTheDocument()
- await user.click(screen.getByRole('tab', { name: 'One' }))
+ await user.click(screen.getByRole('tab', { name: jar.name }))
+
await user.click(screen.getByRole('tab', { name: 'jar_details.title_tab_jar_details' }))
+
expect(screen.getByText('jar_details.utxo_list.alert_no_account_info_title')).toBeInTheDocument()
})
@@ -180,7 +212,10 @@ describe('WalletJarsDetailsContent', () => {
render()
+ expect(screen.getByText('bc1qwallet-a')).toBeInTheDocument()
+
await user.keyboard('{ArrowRight}')
+
expect(screen.getByText('bc1qwallet-a')).toBeInTheDocument()
})
@@ -192,7 +227,11 @@ describe('WalletJarsDetailsContent', () => {
it('refreshes wallet info from the utxos tab', async () => {
const user = userEvent.setup()
render()
- await user.click(screen.getByRole('button', { name: 'global.refresh' }))
+
+ const refreshButton = screen.getByRole('button', { name: 'global.refresh' })
+ expect(refreshButton).toBeEnabled()
+
+ await user.click(refreshButton)
expect(walletInfoRefetch).toHaveBeenCalled()
})
@@ -200,11 +239,18 @@ describe('WalletJarsDetailsContent', () => {
const user = userEvent.setup()
render()
+ const freezeButton = screen.getByRole('button', { name: 'jar_details.utxo_list.button_freeze' })
+ expect(freezeButton).toBeDisabled()
+
const dataRow = screen.getAllByRole('row').find((row) => within(row).queryByText('bc1qwallet-b'))!
await user.click(within(dataRow).getByRole('checkbox'))
- await user.click(screen.getByRole('button', { name: 'jar_details.utxo_list.button_freeze' }))
- await waitFor(() => expect(toastMocks.success).toHaveBeenCalled())
+ expect(freezeButton).toBeEnabled()
+
+ await user.click(freezeButton)
+ await waitFor(() =>
+ expect(toastMocks.success).toHaveBeenCalledWith('jar_details.utxo_list.toast_freeze_success:{"count":1}'),
+ )
expect(walletInfoRefetch).toHaveBeenCalled()
})
@@ -212,10 +258,39 @@ describe('WalletJarsDetailsContent', () => {
const user = userEvent.setup()
render()
+ const unfreezeButton = screen.getByRole('button', { name: 'jar_details.utxo_list.button_unfreeze' })
+ expect(unfreezeButton).toBeDisabled()
+
const dataRow = screen.getAllByRole('row').find((row) => within(row).queryByText('bc1qwallet-c'))!
await user.click(within(dataRow).getByRole('checkbox'))
- await user.click(screen.getByRole('button', { name: 'jar_details.utxo_list.button_unfreeze' }))
- await waitFor(() => expect(toastMocks.success).toHaveBeenCalled())
+ expect(unfreezeButton).toBeEnabled()
+
+ await user.click(unfreezeButton)
+ await waitFor(() =>
+ expect(toastMocks.success).toHaveBeenCalledWith('jar_details.utxo_list.toast_unfreeze_success:{"count":1}'),
+ )
+ expect(walletInfoRefetch).toHaveBeenCalled()
+ })
+
+ it.each(['taker', 'maker', 'rescan'])('disables freeze/unfreeze if rescan/maker/taker is running', async (value) => {
+ const user = userEvent.setup()
+ mocks.takerRunning = value === 'taker'
+ mocks.makerRunning = value === 'maker'
+ mocks.rescanning = value === 'rescan'
+
+ render()
+
+ const freezeButton = screen.getByRole('button', { name: 'jar_details.utxo_list.button_freeze' })
+ expect(freezeButton).toBeDisabled()
+
+ const unfreezeButton = screen.getByRole('button', { name: 'jar_details.utxo_list.button_unfreeze' })
+ expect(unfreezeButton).toBeDisabled()
+
+ const dataRow = screen.getAllByRole('row').find((row) => within(row).queryByText('bc1qwallet-b'))!
+ await user.click(within(dataRow).getByRole('checkbox'))
+
+ expect(freezeButton).toBeDisabled()
+ expect(unfreezeButton).toBeDisabled()
})
})
diff --git a/src/components/wallet/WalletJarsDetailsContent.tsx b/src/components/wallet/WalletJarsDetailsContent.tsx
index 595f15f3..e145599b 100644
--- a/src/components/wallet/WalletJarsDetailsContent.tsx
+++ b/src/components/wallet/WalletJarsDetailsContent.tsx
@@ -6,6 +6,7 @@ import type { TFunction } from 'i18next'
import { AlertTriangleIcon, RefreshCwIcon, ThermometerSnowflakeIcon, ThermometerSunIcon } from 'lucide-react'
import { Trans, useTranslation } from 'react-i18next'
import { toast } from 'sonner'
+import { useJamSessionInfoContext } from '@/context/JamSessionInfoContext'
import {
useAccountSummary,
useAddressSummary,
@@ -57,6 +58,7 @@ interface UtxosContentProps {
export const UtxosContent = ({ enabled, walletFileName, addressSummary, jar }: UtxosContentProps) => {
const { t } = useTranslation()
+ const { takerInfo, rescanInfo, makerInfo } = useJamSessionInfoContext()
const { refetch: walletInfoRefetch, isFetching: walletInfoIsFetching } = useJamWalletInfoContext()
const client = useApiClient()
@@ -127,8 +129,12 @@ export const UtxosContent = ({ enabled, walletFileName, addressSummary, jar }: U
return tableEntries.filter((entry) => entry.tags.some((tag) => tag.value === 'reused')).length
}, [tableEntries])
- // TODO: makerRunning, takerRunner, rescanRunning, etc.
- const operationsEnabled = enabled && !(walletInfoIsFetching || freezeUtxos.isPending || unfreezeUtxos.isPending)
+ const operationsEnabled =
+ enabled &&
+ !makerInfo.running &&
+ !takerInfo.running &&
+ !rescanInfo.rescanning &&
+ !(walletInfoIsFetching || freezeUtxos.isPending || unfreezeUtxos.isPending)
const enableRowSelection = enabled && !(freezeUtxos.isPending || unfreezeUtxos.isPending)
const onFreezeClick = async () => {