From 5d0aad7f38d829ab7537ef1944de480dbd08dec1 Mon Sep 17 00:00:00 2001 From: Dev-makeem <332608801+Dev-makeem@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:25:52 +0100 Subject: [PATCH 1/4] fix: honour the polling abort signal in the wallet overview (#508) --- src/app/dashboard/wallets/[id]/page.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/dashboard/wallets/[id]/page.tsx b/src/app/dashboard/wallets/[id]/page.tsx index e9961fd..db54d97 100644 --- a/src/app/dashboard/wallets/[id]/page.tsx +++ b/src/app/dashboard/wallets/[id]/page.tsx @@ -100,12 +100,11 @@ export default function WalletOverview({ // Silently re-fetch balances + recent transactions in the background so a new deposit shows up // without a manual refresh — no loading indicator here, that's only for explicit refresh actions. const pollFn = useCallback( - async () => { + async (signal: AbortSignal) => { if (!token) return; - const controller = new AbortController(); await Promise.all([ - getBalances(token, id, { signal: controller.signal }).then(setBalances).catch(() => {}), - listRecentTransactions(token, id, { signal: controller.signal }).then(setTxns).catch(() => {}), + getBalances(token, id, { signal }).then(setBalances).catch(() => {}), + listRecentTransactions(token, id, { signal }).then(setTxns).catch(() => {}), ]); }, [token, id], From a9fca37bc387b58eed4357c9ad58e68f8750d2cf Mon Sep 17 00:00:00 2001 From: Dev-makeem <332608801+Dev-makeem@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:25:52 +0100 Subject: [PATCH 2/4] fix: ignore stale wallet page responses on the dashboard home (#509) --- src/app/dashboard/page.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 6457393..e1958d4 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import Link from "next/link"; import { useAuth } from "@/lib/useAuth"; import { displayName } from "@/lib/auth"; @@ -28,11 +28,15 @@ export default function DashboardHome() { const [pageIndex, setPageIndex] = useState(0); const [nextCursor, setNextCursor] = useState(null); const [loadingPage, setLoadingPage] = useState(false); + const cancelPrevLoad = useRef<(() => void) | null>(null); const loadPage = useCallback( (before: string | null) => { if (!token) return; let aborted = false; + // Cancel the previous request so a slow older page can't overwrite the current one. + cancelPrevLoad.current?.(); + cancelPrevLoad.current = () => { aborted = true; }; setLoadingPage(true); setWallets(null); listWalletsPage(token, { before }) From 58e84221a49741049e29f00b9c0d4d0be2f95423 Mon Sep 17 00:00:00 2001 From: Dev-makeem <332608801+Dev-makeem@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:25:52 +0100 Subject: [PATCH 3/4] fix: drop stale audit log responses after a newer search (#510) --- src/app/dashboard/audit/page.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/app/dashboard/audit/page.tsx b/src/app/dashboard/audit/page.tsx index ed27511..9c1a079 100644 --- a/src/app/dashboard/audit/page.tsx +++ b/src/app/dashboard/audit/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { useAuth } from "@/lib/useAuth"; import { listAuditLogsPage, type AuditLog } from "@/lib/audit"; import { errorMessage } from "@/lib/api"; @@ -36,18 +36,23 @@ export default function AuditLogsPage() { const [pageIndex, setPageIndex] = useState(0); const [nextCursor, setNextCursor] = useState(null); const [error, setError] = useState(null); + const requestId = useRef(0); const load = useCallback( (before: string | null) => { if (!token) return; + // Only the latest request may update state, so an older slow response is dropped. + const id = ++requestId.current; setLogs(null); setError(null); listAuditLogsPage(token, { category, search, before }) .then((page) => { + if (id !== requestId.current) return; setLogs(page.data); setNextCursor(page.next_cursor); }) .catch((err) => { + if (id !== requestId.current) return; setError(errorMessage(err, "Failed to load audit logs.")); setLogs([]); }); From 6cbb02767e3a1b93133b587e994b2081cae4b9fd Mon Sep 17 00:00:00 2001 From: Dev-makeem <332608801+Dev-makeem@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:25:52 +0100 Subject: [PATCH 4/4] fix: stop attributing every audit row to the signed-in user (#511) --- src/app/dashboard/audit/page.tsx | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/app/dashboard/audit/page.tsx b/src/app/dashboard/audit/page.tsx index 9c1a079..c588e75 100644 --- a/src/app/dashboard/audit/page.tsx +++ b/src/app/dashboard/audit/page.tsx @@ -7,6 +7,7 @@ import { errorMessage } from "@/lib/api"; import { Pagination } from "@/components/dashboard/Pagination"; import { DashboardShell } from "@/components/dashboard/DashboardShell"; import { PageSpinner } from "@/components/OctoSpinner"; +import { RelativeTime } from "@/components/RelativeTime"; const CATEGORIES = [ { value: "all", label: "All categories" }, @@ -128,7 +129,6 @@ export default function AuditLogsPage() { Activity - User Category IP Address Time @@ -148,7 +148,6 @@ export default function AuditLogsPage() { · {l.target} )} - {user.email} - {timeAgo(l.created_at)} + )) @@ -207,7 +206,7 @@ function Row({ return ( {children} @@ -215,16 +214,3 @@ function Row({ ); } - -function timeAgo(iso: string): string { - const diff = Date.now() - new Date(iso).getTime(); - const s = Math.floor(diff / 1000); - if (s < 60) return "just now"; - const m = Math.floor(s / 60); - if (m < 60) return `${m} minute${m === 1 ? "" : "s"} ago`; - const h = Math.floor(m / 60); - if (h < 24) return `${h} hour${h === 1 ? "" : "s"} ago`; - const d = Math.floor(h / 24); - if (d < 30) return `${d} day${d === 1 ? "" : "s"} ago`; - return new Date(iso).toLocaleDateString(); -}