From 16729b2fa4ba96783cf0d33b5d094d6bf45faabd Mon Sep 17 00:00:00 2001 From: Sonny May Date: Tue, 10 Nov 2026 15:02:41 +0000 Subject: [PATCH] fix: ignore stale ticket detail responses in Tickets page Clicking one ticket and then another while the first request was slow let the older notes/history response overwrite the newly selected ticket's detail view, or clear its loading state early. A request counter ref now lets only the latest loadDetail call update state. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_0171zWziw9ByH85SW4Y3yUZM --- frontend/src/pages/Tickets.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/Tickets.jsx b/frontend/src/pages/Tickets.jsx index cabc416..18bc2e5 100644 --- a/frontend/src/pages/Tickets.jsx +++ b/frontend/src/pages/Tickets.jsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { api } from "../api"; import AISuggestions from "../components/AISuggestions"; import { LoadingState, ErrorState, InlineError } from "../components/AsyncState"; @@ -42,6 +42,9 @@ export default function Tickets() { const [detailLoading, setDetailLoading] = useState(false); const [saving, setSaving] = useState(false); const [noteSaving, setNoteSaving] = useState(false); + // Identifies the most recent detail request so a slow response for a + // previously clicked ticket can't overwrite the currently selected one. + const detailRequestRef = useRef(0); const load = async () => { setLoading(true); @@ -63,6 +66,7 @@ export default function Tickets() { }; const loadDetail = async (t) => { + const requestId = ++detailRequestRef.current; setSelected(t); setDetailError(null); setDetailLoading(true); @@ -73,12 +77,14 @@ export default function Tickets() { api.get(`/tickets/${t.id}/notes`), api.get(`/tickets/${t.id}/history`), ]); + if (requestId !== detailRequestRef.current) return; setNotes(ticketNotes); setHistory(ticketHistory); } catch (e) { + if (requestId !== detailRequestRef.current) return; setDetailError(e.message || String(e)); } finally { - setDetailLoading(false); + if (requestId === detailRequestRef.current) setDetailLoading(false); } };