Skip to content

frontend: useAccountSync hook#4121

Merged
thisconnect merged 4 commits into
BitBoxSwiss:masterfrom
thisconnect:frontend-sync-hook
May 13, 2026
Merged

frontend: useAccountSync hook#4121
thisconnect merged 4 commits into
BitBoxSwiss:masterfrom
thisconnect:frontend-sync-hook

Conversation

@thisconnect
Copy link
Copy Markdown
Collaborator

Before asking for reviews, here is a check list of the most common things you might need to consider:

  • updating the Changelog
  • writing unit tests
  • checking if your changes affect other coins or tokens in unintended ways
  • testing on multiple environments (Qt, Android, ...)
  • having an AI review your changes

@thisconnect thisconnect marked this pull request as ready for review May 11, 2026 06:42
@thisconnect thisconnect requested a review from a team as a code owner May 11, 2026 06:42
@thisconnect
Copy link
Copy Markdown
Collaborator Author

This hook could probably be used in various places but I'd like to get feedback before continuing.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request introduces a reusable useAccountSynced React hook for managing account-scoped asynchronous data fetching with race-condition protection. The hook is integrated into three market routes (BTCDirect, Bitrefill, and Pocket), each with varying levels of refactoring. The syncing message is centralized from aopp.syncing to account.syncing across components. BTCDirect gains explicit syncing state display via a new syncInProgress flag derived from API error state. The Pocket route undergoes substantial refactoring to use reactive URL synchronization and improved message origin verification. The BTCDirect API response type is annotated with a TODO for a future error code.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontends/web/src/api/market.ts (1)

83-91: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider addressing the TODO to improve type safety.

The errorMessage field is currently typed as string, but btcdirect.tsx (line 214) already checks for the specific value 'syncInProgress'. To improve type safety and make the error code explicit, consider using a discriminated union:

✨ Proposed type-safe approach
 export type TBTCDirectInfoResponse = {
   success: true;
   url: string;
   apiKey: string;
   address?: string;
 } | {
   success: false;
-  errorMessage: string; // TODO: add 'syncInProgress'
+  errorCode?: 'syncInProgress';
+  errorMessage?: string;
 };

Then update the usage in btcdirect.tsx to check errorCode instead:

const syncInProgress = !btcdirectInfo?.success && btcdirectInfo?.errorCode === 'syncInProgress';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/api/market.ts` around lines 83 - 91, The
TBTCDirectInfoResponse union uses a generic errorMessage:string which hides
specific error cases; update the error branch of TBTCDirectInfoResponse to use a
discriminated errorCode (e.g., errorCode: 'syncInProgress' | 'other' or a string
literal union) plus an optional human-readable message (e.g., message?: string)
so callers can pattern-match safely; then update consumers (notably the
btcdirect component usage that currently checks for 'syncInProgress') to test
btcdirectInfo?.errorCode === 'syncInProgress' instead of comparing errorMessage.
Ensure the exported type name TBTCDirectInfoResponse and the consumer check in
btcdirect are updated together.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/hooks/accounts.ts`:
- Around line 15-28: The hook currently swallows API errors and leaves callers
in a perpetual loading state; update the hook (the callApi callback and the
hook's return value) to surface errors: add an error state (e.g. const [error,
setError] = useState<Error|undefined>(undefined)), in callApi clear error on
start, setError(error) inside the catch, and ensure you still guard with
isMounted/current requestId before updating state; change the hook's return
signature from just result to an object like { data: result, error } (or
similar) so callers can show a toast/alert or fallback UI; also ensure you type
the caught error (Error|unknown) and normalize it before storing.

In `@frontends/web/src/routes/market/btcdirect.tsx`:
- Line 10: Remove the now-unused import useLoad from the module import list (the
line "import { useLoad } from '@/hooks/api';") since the code was migrated to
useAccountSynced; delete that import and ensure no remaining references to
useLoad exist in the file (verify usage in functions/components like the
component that previously called useLoad and confirm it uses useAccountSynced
instead).

---

Outside diff comments:
In `@frontends/web/src/api/market.ts`:
- Around line 83-91: The TBTCDirectInfoResponse union uses a generic
errorMessage:string which hides specific error cases; update the error branch of
TBTCDirectInfoResponse to use a discriminated errorCode (e.g., errorCode:
'syncInProgress' | 'other' or a string literal union) plus an optional
human-readable message (e.g., message?: string) so callers can pattern-match
safely; then update consumers (notably the btcdirect component usage that
currently checks for 'syncInProgress') to test btcdirectInfo?.errorCode ===
'syncInProgress' instead of comparing errorMessage. Ensure the exported type
name TBTCDirectInfoResponse and the consumer check in btcdirect are updated
together.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0ecf86f3-1fc4-4d5c-9944-6ec7d0f7bd54

📥 Commits

Reviewing files that changed from the base of the PR and between efef487 and 2be1c32.

📒 Files selected for processing (5)
  • frontends/web/src/api/market.ts
  • frontends/web/src/components/aopp/aopp.tsx
  • frontends/web/src/hooks/accounts.ts
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/market/btcdirect.tsx

Comment thread frontends/web/src/hooks/account.ts
Comment thread frontends/web/src/routes/market/btcdirect.tsx
@thisconnect thisconnect force-pushed the frontend-sync-hook branch from 2be1c32 to 226d40e Compare May 11, 2026 06:50
@thisconnect thisconnect requested a review from shonsirsha May 11, 2026 13:03
Copy link
Copy Markdown
Collaborator

@shonsirsha shonsirsha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Fixed BTC Direct widget loading forever if accounts are not fully
synced yet.

How to test:
1) unlock device
2) stop make servewallet-mainnet
3) rm -rf appfolder.dev/cache/account-v0-*
4) rm appfolder.dev/accounts.json
5) make servewallet-mainnet
6) navigate to Market / BTC Direct
7) iframe should load after account is synced
@thisconnect thisconnect force-pushed the frontend-sync-hook branch from 226d40e to c67ac8b Compare May 13, 2026 11:45
@thisconnect
Copy link
Copy Markdown
Collaborator Author

rebased

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/api/market.ts`:
- Around line 89-91: The failure branch of the API response type (the object
with success: false and errorMessage: string) should expose a typed
discriminator instead of relying on free-form messages: replace or augment
errorMessage with a field like errorCode: 'syncInProgress' | 'otherError' (or a
broader enum) and update the response union so the success=true and
success=false variants form a discriminated union; then update any consumers/UI
code that parse errorMessage to switch on response.errorCode (handling
'syncInProgress' explicitly) and keep errorMessage only for human-readable text.
Ensure you modify the response type declaration (the false-variant where
success: false is defined) and all call sites that inspect errorMessage.

In `@frontends/web/src/hooks/accounts.ts`:
- Line 5: The import in accounts.ts uses a relative path; update the import of
useMountedRef to use the repository path alias by replacing "import {
useMountedRef } from './mount';" with the alias-based import (e.g. import {
useMountedRef } from '@/hooks/mount') so it follows the frontends/web/src/ `@/`
mapping and matches other internal imports.
- Around line 15-24: The callApi flow leaves previous successful result in state
causing stale data to be visible if a subsequent fetch fails; modify callApi
(where apiRequestId.current is incremented) to clear result by calling
setResult(undefined) at the start of a new request (after computing requestId)
and only when the component is mounted and requestId === apiRequestId.current
(use isMounted.current and requestId checks) so you reset state for the current
request but avoid touching state for unmounted/obsolete requests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 02f1df84-41df-4b26-8f1c-3375c551dd3a

📥 Commits

Reviewing files that changed from the base of the PR and between 2be1c32 and c67ac8b.

📒 Files selected for processing (5)
  • frontends/web/src/api/market.ts
  • frontends/web/src/components/aopp/aopp.tsx
  • frontends/web/src/hooks/accounts.ts
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/market/btcdirect.tsx

Comment thread frontends/web/src/api/market.ts
Comment thread frontends/web/src/hooks/account.ts
Comment thread frontends/web/src/hooks/account.ts
@thisconnect thisconnect force-pushed the frontend-sync-hook branch from c67ac8b to 43e1722 Compare May 13, 2026 12:32
In case the account is still syncing show a 'syncing account'
message instead of just 'loading' to give the user better feedback.

Ensure that the account is properly synced and call BTC Direct info
once it is synced. This fixes a bug where BTC Direct hangs with
loading spinner in case the account was not fully synced.
@thisconnect thisconnect force-pushed the frontend-sync-hook branch from 43e1722 to 645e7f6 Compare May 13, 2026 13:31
@thisconnect thisconnect force-pushed the frontend-sync-hook branch from 645e7f6 to cb0e309 Compare May 13, 2026 13:50
@thisconnect
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontends/web/src/routes/market/bitrefill.tsx (1)

195-226: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle unsuccessful bitrefillInfo states explicitly.

Line 223 now keeps the loader visible whenever iframeLoaded is false, but the iframe is only mounted on Line 226 when bitrefillInfo?.success is true. If useAccountSynced() resolves to an unsuccessful result (for example while the account is still syncing), this route never clears the spinner and never shows a fallback state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontends/web/src/routes/market/bitrefill.tsx` around lines 195 - 226, The
spinner can hang forever because the iframe is only rendered when
bitrefillInfo?.success is true; update the render logic around bitrefillInfo,
iframeLoaded and Spinner so unsuccessful or non-success states are handled
explicitly: inside the agreedTerms branch (where bitrefillInfo and iframeLoaded
are checked) add a clear fallback/error UI (e.g., an error message or retry)
when bitrefillInfo exists but bitrefillInfo.success is false, and ensure Spinner
is only shown while waiting for either iframeLoaded or bitrefillInfo to be
undefined/pending; reference the bitrefillInfo variable, the iframeLoaded state,
the Spinner component and the BitrefillTerms branch to locate where to add the
fallback rendering and adjust the spinner condition.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/hooks/account.test.ts`:
- Around line 6-8: Replace the relative imports in account.test.ts with repo
path aliases: change the import of useAccountSynced (currently from './account')
to use the alias '@/hooks/account' and change the import of utils (currently
from './mount') to use '@/hooks/mount' so the file follows the
frontends/web/src/**/*.{ts,tsx} rule that requires '@/...' mappings to src/*.

In `@frontends/web/src/routes/market/pocket.tsx`:
- Around line 319-345: The spinner is shown only based on iframeLoaded, so when
pocketInfo?.success === false (no iframe mounts) the spinner never disappears;
update the Spinner render condition to also require that pocketInfo?.success is
not false (e.g., render Spinner when !iframeLoaded && pocketInfo?.success !==
false) so the Spinner hides when a failed pocket URL is returned; adjust any
related blocking overlay logic if needed and keep onIframeLoad/iframeRef
unchanged.

---

Outside diff comments:
In `@frontends/web/src/routes/market/bitrefill.tsx`:
- Around line 195-226: The spinner can hang forever because the iframe is only
rendered when bitrefillInfo?.success is true; update the render logic around
bitrefillInfo, iframeLoaded and Spinner so unsuccessful or non-success states
are handled explicitly: inside the agreedTerms branch (where bitrefillInfo and
iframeLoaded are checked) add a clear fallback/error UI (e.g., an error message
or retry) when bitrefillInfo exists but bitrefillInfo.success is false, and
ensure Spinner is only shown while waiting for either iframeLoaded or
bitrefillInfo to be undefined/pending; reference the bitrefillInfo variable, the
iframeLoaded state, the Spinner component and the BitrefillTerms branch to
locate where to add the fallback rendering and adjust the spinner condition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 59104196-f01a-474f-bc60-e3cd016b5bb4

📥 Commits

Reviewing files that changed from the base of the PR and between c67ac8b and cb0e309.

📒 Files selected for processing (8)
  • frontends/web/src/api/market.ts
  • frontends/web/src/components/aopp/aopp.tsx
  • frontends/web/src/hooks/account.test.ts
  • frontends/web/src/hooks/account.ts
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/market/bitrefill.tsx
  • frontends/web/src/routes/market/btcdirect.tsx
  • frontends/web/src/routes/market/pocket.tsx

Comment thread frontends/web/src/hooks/account.test.ts
Comment thread frontends/web/src/routes/market/pocket.tsx
} | {
success: false;
errorMessage: string;
errorMessage: string; // TODO: add 'syncInProgress'
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the backend gets cleaned up it would be nice to explicitly type all the known errors here. cc @bznein

@thisconnect thisconnect merged commit d48715d into BitBoxSwiss:master May 13, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants