From 5ddb9a5f00a555654039507d49e7dcc089547a5b Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Tue, 11 Aug 2026 19:43:58 +0200 Subject: [PATCH] feat: add recheck button to OrderbookEmptyAlert --- src/components/send/SendForm.tsx | 11 ++++++++-- src/components/sweep/SweepPage.tsx | 11 ++++++++-- .../ui/jam/OrderbookEmptyAlert.test.tsx | 20 +++++++++++++++++-- src/components/ui/jam/OrderbookEmptyAlert.tsx | 19 +++++++++++++++--- src/hooks/useQueryOrderbook.ts | 7 ++++++- src/i18n/locales/en/translation.json | 2 ++ 6 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/components/send/SendForm.tsx b/src/components/send/SendForm.tsx index e8e7125f..d102b020 100644 --- a/src/components/send/SendForm.tsx +++ b/src/components/send/SendForm.tsx @@ -186,7 +186,12 @@ export function SendForm({ const { hasOrders, - queryResult: { isLoading: orderbookCheckIsLoading, isError: orderbookCheckIsError }, + queryResult: { + isLoading: orderbookCheckIsLoading, + isFetching: orderbookCheckIsFetching, + isError: orderbookCheckIsError, + refetch: orderbookRefetch, + }, } = useQueryOrderbook() const destinationAddressInfo = useMemo(() => { @@ -369,7 +374,9 @@ export function SendForm({ {hasCoinjoinPreconditionWarning && coinjoinPreconditionSummary && ( )} - {isCoinJoin && !orderbookCheckIsLoading && !orderbookCheckIsError && !hasOrders && } + {isCoinJoin && !orderbookCheckIsLoading && !orderbookCheckIsError && !hasOrders && ( + + )}
diff --git a/src/components/sweep/SweepPage.tsx b/src/components/sweep/SweepPage.tsx index 2a62bd60..bbc95e4c 100644 --- a/src/components/sweep/SweepPage.tsx +++ b/src/components/sweep/SweepPage.tsx @@ -76,7 +76,12 @@ export const SweepPage = ({ walletFileName }: SweepPageProps) => { const [alertMessage, setAlertMessage] = useState() const { hasOrders, - queryResult: { isLoading: orderbookCheckIsLoading, isError: orderbookCheckIsError }, + queryResult: { + isLoading: orderbookCheckIsLoading, + isError: orderbookCheckIsError, + isFetching: orderbookCheckIsFetching, + refetch: orderbookRefetch, + }, } = useQueryOrderbook() const feeConfigValidation = useFeeConfigValidation({ walletFileName }) @@ -290,7 +295,9 @@ export const SweepPage = ({ walletFileName }: SweepPageProps) => { setShowFeeConfigDialog(true)} className="mb-4" /> )} - {!orderbookCheckIsLoading && !orderbookCheckIsError && !hasOrders && } + {!orderbookCheckIsLoading && !orderbookCheckIsError && !hasOrders && ( + + )} {alertMessage && ( diff --git a/src/components/ui/jam/OrderbookEmptyAlert.test.tsx b/src/components/ui/jam/OrderbookEmptyAlert.test.tsx index 3eebb623..aae12d42 100644 --- a/src/components/ui/jam/OrderbookEmptyAlert.test.tsx +++ b/src/components/ui/jam/OrderbookEmptyAlert.test.tsx @@ -20,11 +20,27 @@ vi.mock('react-router-dom', () => ({ })) describe('OrderbookEmptyAlert', () => { - it('renders title, description and link to orderbook page', () => { - render() + it('renders title, description, button and link to orderbook page', () => { + render( {}} />) expect(screen.getByText('orderbook.alert_precheck_empty_title')).toBeInTheDocument() expect(screen.getByText(/orderbook.alert_precheck_empty_description/u)).toBeInTheDocument() expect(screen.getByRole('link')).toHaveAttribute('href', '/orderbook') + + const actionCheck = screen.getByRole('button', { name: 'orderbook.alert_precheck_empty_text_button_check' }) + expect(actionCheck).toBeEnabled() + + const actionChecking = screen.queryByRole('button', { name: 'orderbook.alert_precheck_empty_text_button_checking' }) + expect(actionChecking).not.toBeInTheDocument() + }) + + it('disables button while checking', () => { + render( {}} />) + + const actionChecking = screen.getByRole('button', { name: 'orderbook.alert_precheck_empty_text_button_checking' }) + expect(actionChecking).toBeDisabled() + + const actionCheck = screen.queryByRole('button', { name: 'orderbook.alert_precheck_empty_text_button_check' }) + expect(actionCheck).not.toBeInTheDocument() }) }) diff --git a/src/components/ui/jam/OrderbookEmptyAlert.tsx b/src/components/ui/jam/OrderbookEmptyAlert.tsx index 01aa6f13..9b602fc7 100644 --- a/src/components/ui/jam/OrderbookEmptyAlert.tsx +++ b/src/components/ui/jam/OrderbookEmptyAlert.tsx @@ -1,14 +1,17 @@ -import { AlertTriangleIcon } from 'lucide-react' +import { AlertTriangleIcon, RefreshCwIcon } from 'lucide-react' import { Trans, useTranslation } from 'react-i18next' import { Link } from 'react-router-dom' -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { Alert, AlertAction, AlertDescription, AlertTitle } from '@/components/ui/alert' import { routes } from '@/constants/routes' +import { Button } from '../button' interface OrderbookEmptyAlertProps { className?: string + isChecking?: boolean + onCheckClick?: () => Promise } -export const OrderbookEmptyAlert = ({ className }: OrderbookEmptyAlertProps) => { +export const OrderbookEmptyAlert = ({ className, isChecking, onCheckClick }: OrderbookEmptyAlertProps) => { const { t } = useTranslation() return ( @@ -23,6 +26,16 @@ export const OrderbookEmptyAlert = ({ className }: OrderbookEmptyAlertProps) => }} /> + {onCheckClick && ( + + + + )} ) } diff --git a/src/hooks/useQueryOrderbook.ts b/src/hooks/useQueryOrderbook.ts index 5a248535..bcef2c88 100644 --- a/src/hooks/useQueryOrderbook.ts +++ b/src/hooks/useQueryOrderbook.ts @@ -1,5 +1,6 @@ import { useQuery, type UseQueryResult } from '@tanstack/react-query' import { fetchOrderbook, type OrderbookResponse } from '@/lib/api/orderbook' +import { withQueryDelay } from '@/lib/queryClient' export type UseQueryOrderbookResult = { hasOrders: boolean @@ -9,7 +10,11 @@ export type UseQueryOrderbookResult = { export function useQueryOrderbook(): UseQueryOrderbookResult { const queryResult = useQuery({ queryKey: ['orderbook-precheck'], - queryFn: fetchOrderbook, + queryFn: withQueryDelay(fetchOrderbook, { + // avoid flickering and let user briefly know that something is happening in the background + delayBefore: 1_000, + }), + staleTime: 30 * 1_000, retry: false, }) diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index 67830fec..5357883a 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -755,6 +755,8 @@ "alert_empty_orderbook": "Orderbook is empty", "alert_precheck_empty_title": "No active makers found", "alert_precheck_empty_description": "Your local Orderbook appears to be empty right now. Collaborative transactions might fail. Please check <1>your local Orderbook.", + "alert_precheck_empty_text_button_check": "Check again", + "alert_precheck_empty_text_button_checking": "Checking...", "error_loading_orderbook_failed": "Error while loading the orderbook. Your current local setup might not support fetching the orderbook. Reason: {{ reason }}", "text_offer_type_absolute": "absolute", "text_offer_type_relative": "relative",