fix: Transaction Details offline — DB-first + honest offline state [PERA-4580]#1008
Merged
Conversation
# Conflicts: # pnpm-lock.yaml # pnpm-workspace.yaml
yasin-ce
approved these changes
Jul 24, 2026
yasin-ce
left a comment
Collaborator
There was a problem hiding this comment.
⚪ Nits
firstValid: 0n/lastValid: 0ninmapHistoryItemToDisplayableTransaction.ts:1253-1254are placeholders (the row doesn't store them). Fine if the detail display never surfaces validity rounds — worth a one-word confirm that nothing renders them as a literal0.- The
PaymentTransactionDisplayfixes (-algos→algos.negated(), dropping the bareDecimal(amount)wrapper) are genuine correctness improvements —-algoson aDecimalcoerces throughvalueOf, and bareDecimal(...)violates thenew Decimalconvention. Slightly tangential to "offline," but they're in a directly-touched display and clearly right, so I'd keep them; just calling it out so it's a conscious inclusion.
🔵 Questions / awareness
isErroris checked beforeisPausedinuseTransactionDetailsScreen.ts:635-643— the opposite ordering to sibling #1013, which deliberately prefers offline (isError && !hasInternet → offline). This one matches the documented §2 contract, and for a genuine offline error the typed copy is alreadyerrors.network.no_connection("You appear to be offline"), so it's honest either way. The only gap: a device that goes offline carrying a stale non-offline error (e.g. a priortimeout) shows the timeout screen with a Retry that just re-pauses. Intentional divergence from #1013, or should both surfaces agree?- The offline retry button calls
refetch()unconditionally (useTransactionDetailsScreen.ts:667-669) — nohasInternetshort-circuit like #1013's charts have. Harmless (react-query just re-pauses), but the two offline PRs handle the same retry two different ways; worth picking one pattern. AssetTransferDisplaynow hides the amount row entirely on a settled asset miss ((asset || isAssetPending)) rather than rendering with assumed decimals — good, honest. Confirm the opt-in path (transferType === 'opt-in', always amount-less) still reads right with the new guard.
…ne retry [PERA-4580] Align the Transaction Details screen with the PERA-4581 charts contract (PR #1013): a device that goes offline carrying a prior non-offline error (e.g. a timeout) now shows the offline surface via `isPaused || (isError && !hasInternet)` instead of a timeout screen with a Retry that just re-pauses. The retry also short-circuits while offline so it no longer fires a doomed request, matching the charts retry. Addresses review feedback on #1008.
# Conflicts: # pnpm-lock.yaml # pnpm-workspace.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Transaction Details now works offline instead of showing a misleading generic error or spinning forever:
historyTransactionparam); a newmapHistoryItemToDisplayableTransactionin@perawallet/wallet-core-transactionsconverts it to the displayable shape, so type, amounts, addresses, date, and fee render from local data with no network. The indexer fetch stays enabled online as enrichment and is preferred once it lands (online behavior unchanged).useTransactionDetailsScreenhook with regime-aware states — offline (isPaused→errors.network.no_connectioncopy + Retry) vs fetch error (typed PERA-4574 copy viagetNetworkErrorMessageKeys+ Retry) — replacing the unconditionalerrors.generalEmptyView. Paused fetches auto-resume on reconnect.AssetTransferDisplayonly shows a spinner while the asset query is genuinely pending; a settled miss shows "Asset unavailable" and self-hides the amount row rather than rendering an amount scaled with assumed decimals.AppCallTransactionDisplayguards the on-completion row (mapped rows don't carry it).innerTransactionCountthrough; when the full inner transactions aren't available locally, the screen shows "N Inner Transactions — Connect to the internet to view" instead of silently hiding the panel.Design notes:
nullforacfg/afrz/keyreg/hbrows (andaxferrows missing their asset summary) — the SQLite row is a lossy summary and can't honestly reconstruct those sub-structs, so offline those fall through to the offline state instead of fabricating details.historyTransactionwas added to bothSigningStackParamListandRootStackParamList(the history hooks navigate through the root stack); both carry the existing non-serializability caveat.Related Issues
Checklist
Additional Notes
pnpm pre-pushandpnpm buildclean.Decimal(...)call (missingnew) inPaymentTransactionDisplay.tsx.usePaymentTransactionDisplayunary-minus coercion is now fixed too:.negated()keeps the amount aDecimalend-to-end (new hook spec, 4 tests), and the downstreamnew Decimal(amount)re-wrap is gone.fast-uri@<4: 3.1.4; main's fix(ios): align Expo modules to the 57.0.7 set to resolve dyld crash #1009 landed its own fix (fast-uri@<4.1.1: ">=4.1.1") in the meantime, so the merge adopted main's version — this PR's remaining deps delta vs main is onlysvgo@<3.3.4: 3.3.4(GHSA-2p49-hgcm-8545, dev-only path via the svg transformer). Both audit gates (--prod --audit-level=moderateand informational--audit-level=low) are clean on the merged result.🤖 Generated with Claude Code