From ef9973e0f8147647fcee5cfbce7a4c1f1e243bd3 Mon Sep 17 00:00:00 2001 From: Freezyyy-arch <305543353+Freezyyy-arch@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:27:34 +0100 Subject: [PATCH 1/4] fix: return the load promise so usePolling's overlap guard works (#507) --- src/app/dashboard/wallets/[id]/payment-links/page.tsx | 2 +- src/app/dashboard/wallets/[id]/transactions/page.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/dashboard/wallets/[id]/payment-links/page.tsx b/src/app/dashboard/wallets/[id]/payment-links/page.tsx index a5ae12b..63e465f 100644 --- a/src/app/dashboard/wallets/[id]/payment-links/page.tsx +++ b/src/app/dashboard/wallets/[id]/payment-links/page.tsx @@ -55,7 +55,7 @@ export default function PaymentLinksPage({ (before: string | null, opts?: { silent?: boolean }) => { if (!token) return; if (!opts?.silent) setRefreshing(true); - listPaymentLinksPage(asAuthToken(token), asWalletId(id), { before }) + return listPaymentLinksPage(asAuthToken(token), asWalletId(id), { before }) .then((page) => { setLinks(page.data); setNextCursor(page.next_cursor); diff --git a/src/app/dashboard/wallets/[id]/transactions/page.tsx b/src/app/dashboard/wallets/[id]/transactions/page.tsx index e5d2a96..7486750 100644 --- a/src/app/dashboard/wallets/[id]/transactions/page.tsx +++ b/src/app/dashboard/wallets/[id]/transactions/page.tsx @@ -47,7 +47,7 @@ export default function TransactionsPage({ (before: string | null, opts?: { silent?: boolean }) => { if (!token) return; if (!opts?.silent) setRefreshing(true); - listTransactionsPage(token, id, { before }) + return listTransactionsPage(token, id, { before }) .then((page) => { setTxns(page.data); setNextCursor(page.next_cursor); From 221f20a0d387cd0ef07a386cd1241cfc8097a0d7 Mon Sep 17 00:00:00 2001 From: Freezyyy-arch <305543353+Freezyyy-arch@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:27:34 +0100 Subject: [PATCH 2/4] fix: ignore stale page responses so polling cannot overwrite navigation (#506) --- src/app/dashboard/wallets/[id]/payment-links/page.tsx | 7 ++++++- src/app/dashboard/wallets/[id]/transactions/page.tsx | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/dashboard/wallets/[id]/payment-links/page.tsx b/src/app/dashboard/wallets/[id]/payment-links/page.tsx index 63e465f..100df8a 100644 --- a/src/app/dashboard/wallets/[id]/payment-links/page.tsx +++ b/src/app/dashboard/wallets/[id]/payment-links/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { use, useCallback, useEffect, useState } from "react"; +import { use, useCallback, useEffect, useRef, useState } from "react"; import { useAuth } from "@/lib/useAuth"; import { useWallet } from "@/lib/useWallet"; import { PaymentLinkList } from "@/components/payment-links/PaymentLinkList"; @@ -51,12 +51,17 @@ export default function PaymentLinksPage({ const [pageIndex, setPageIndex] = useState(0); const [nextCursor, setNextCursor] = useState(null); + // Latest non-silent request id; a response that no longer matches it is stale and dropped. + const latestReq = useRef(0); + const load = useCallback( (before: string | null, opts?: { silent?: boolean }) => { if (!token) return; + const reqId = opts?.silent ? latestReq.current : ++latestReq.current; if (!opts?.silent) setRefreshing(true); return listPaymentLinksPage(asAuthToken(token), asWalletId(id), { before }) .then((page) => { + if (reqId !== latestReq.current) return; setLinks(page.data); setNextCursor(page.next_cursor); setError(null); diff --git a/src/app/dashboard/wallets/[id]/transactions/page.tsx b/src/app/dashboard/wallets/[id]/transactions/page.tsx index 7486750..8907404 100644 --- a/src/app/dashboard/wallets/[id]/transactions/page.tsx +++ b/src/app/dashboard/wallets/[id]/transactions/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { use, useCallback, useEffect, useMemo, useState } from "react"; +import { use, useCallback, useEffect, useRef, useMemo, useState } from "react"; import { useAuth } from "@/lib/useAuth"; import { useWallet } from "@/lib/useWallet"; import { @@ -43,12 +43,17 @@ export default function TransactionsPage({ const [pageIndex, setPageIndex] = useState(0); const [nextCursor, setNextCursor] = useState(null); + // Latest non-silent request id; a response that no longer matches it is stale and dropped. + const latestReq = useRef(0); + const load = useCallback( (before: string | null, opts?: { silent?: boolean }) => { if (!token) return; + const reqId = opts?.silent ? latestReq.current : ++latestReq.current; if (!opts?.silent) setRefreshing(true); return listTransactionsPage(token, id, { before }) .then((page) => { + if (reqId !== latestReq.current) return; setTxns(page.data); setNextCursor(page.next_cursor); setError(null); From 5453549ccf9028748587471563cf5a8755e0697d Mon Sep 17 00:00:00 2001 From: Freezyyy-arch <305543353+Freezyyy-arch@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:27:46 +0100 Subject: [PATCH 3/4] fix: label payment link stats by what they compute (#505) --- src/app/dashboard/wallets/[id]/payment-links/page.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/dashboard/wallets/[id]/payment-links/page.tsx b/src/app/dashboard/wallets/[id]/payment-links/page.tsx index 100df8a..106374a 100644 --- a/src/app/dashboard/wallets/[id]/payment-links/page.tsx +++ b/src/app/dashboard/wallets/[id]/payment-links/page.tsx @@ -153,14 +153,14 @@ export default function PaymentLinksPage({
- - + +
From 9fb88950418e6d22c1f737cd437898d4987835ea Mon Sep 17 00:00:00 2001 From: Freezyyy-arch <305543353+Freezyyy-arch@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:27:46 +0100 Subject: [PATCH 4/4] fix: label address search as covering loaded addresses only (#504) --- src/components/addresses/AddressSearchBox.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/addresses/AddressSearchBox.tsx b/src/components/addresses/AddressSearchBox.tsx index e76de9f..c14a0aa 100644 --- a/src/components/addresses/AddressSearchBox.tsx +++ b/src/components/addresses/AddressSearchBox.tsx @@ -16,8 +16,8 @@ export function AddressSearchBox({ onChange }: { onChange: (query: string) => vo type="search" value={value} onChange={(e) => setValue(e.target.value)} - placeholder="Search by customer reference" - aria-label="Search addresses by customer reference" + placeholder="Search loaded addresses by customer reference" + aria-label="Search loaded addresses by customer reference" className="w-full max-w-sm rounded-xl border border-border bg-surface-raised px-4 py-2 text-sm text-foreground placeholder:text-muted/60 focus:border-burgundy-bright focus:outline-none" /> );