What happens
On the Transfers page, cancelling (or accepting/declining) a transfer works on the server, but the
"Recent" list below still shows the transfer as "pending". It only shows the correct status after a
manual page refresh or opening the page in a new tab.
This puts two contradictory things on the same screen at the same time: the transfer disappears
from "Outgoing (pending)" as expected, while the Recent list right underneath still calls it
pending.
A user who cancels and still sees "pending" will reasonably think the cancel failed, and try again.
Steps to reproduce
- Log in as user A. Send 1 token to user B's wallet.
(You are redirected to the Transfers page — that is the only way in, there is no nav button.)
- The transfer appears under "Outgoing (pending)" and also in the "Recent" list below.
- Tap Cancel.
- The transfer correctly disappears from "Outgoing (pending)".
- Look at the "Recent" list -> it STILL says pending.
- Refresh the page -> it now correctly says cancelled.
Same behaviour for Accept (stays "pending" instead of showing completed) and Decline.
Reproduces every time.
Root cause
The page uses two separate data sources, and only one of them refreshes:
apps/web/src/app/(protected)/transfers/page.tsx:115
const { transfers: pending, accept, decline, cancel } = usePendingTransfers();
-> usePendingTransfers wraps each action in withReload (usePendingTransfers.ts:46-51),
which calls load() after the action succeeds. This is why the pending sections update
correctly.
apps/web/src/app/(protected)/transfers/page.tsx:116
const { transfers: history } = useGetTransfers(20);
-> useGetTransfers loads once on mount and never again. It does not even expose a reload
function: packages/wallet/src/hooks/useGetTransfers.ts:35 returns only
{ transfers, isTransfersLoading, error }.
So the page has no way to refresh the history list after an action.
Suggested fix
- Have useGetTransfers expose a reload function, the same way usePendingTransfers does
(usePendingTransfers.ts:57 returns reload: load).
- Call it after a successful accept / decline / cancel on the Transfers page, so both lists update
together.
Notes
- The action itself is correct — the server state really does change to cancelled/completed. This is
purely a stale-display problem.
- Please do not fix this by adding a page reload. The two lists should just refetch.
What happens
On the Transfers page, cancelling (or accepting/declining) a transfer works on the server, but the
"Recent" list below still shows the transfer as "pending". It only shows the correct status after a
manual page refresh or opening the page in a new tab.
This puts two contradictory things on the same screen at the same time: the transfer disappears
from "Outgoing (pending)" as expected, while the Recent list right underneath still calls it
pending.
A user who cancels and still sees "pending" will reasonably think the cancel failed, and try again.
Steps to reproduce
(You are redirected to the Transfers page — that is the only way in, there is no nav button.)
Same behaviour for Accept (stays "pending" instead of showing completed) and Decline.
Reproduces every time.
Root cause
The page uses two separate data sources, and only one of them refreshes:
apps/web/src/app/(protected)/transfers/page.tsx:115
const { transfers: pending, accept, decline, cancel } = usePendingTransfers();
-> usePendingTransfers wraps each action in withReload (usePendingTransfers.ts:46-51),
which calls load() after the action succeeds. This is why the pending sections update
correctly.
apps/web/src/app/(protected)/transfers/page.tsx:116
const { transfers: history } = useGetTransfers(20);
-> useGetTransfers loads once on mount and never again. It does not even expose a reload
function: packages/wallet/src/hooks/useGetTransfers.ts:35 returns only
{ transfers, isTransfersLoading, error }.
So the page has no way to refresh the history list after an action.
Suggested fix
(usePendingTransfers.ts:57 returns
reload: load).together.
Notes
purely a stale-display problem.