From fe01311f37a1fc96de65371cc99943e96dc6aac7 Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Wed, 12 Aug 2026 16:17:19 +1000 Subject: [PATCH] PM-5848: Refresh support ticket details after read What was broken After assigning a ticket from the Support ticket list, the detail screen could still show the ticket as unassigned and offer "Assign to me" until the page was refreshed. Root cause The asynchronous mark-read completion performed a data-bearing SWR mutation that could supersede an in-flight detail revalidation and preserve stale pre-assignment data. What was changed Changed the post-read cache update to a revalidation-only SWR mutation, ensuring the detail page reloads current server state without invalidating a concurrent assignment refresh. Any added/updated tests Updated the TicketDetailPage regression test to verify that completing the mark-read request triggers a zero-argument, revalidation-only mutation. --- .../ticket-details/TicketDetailPage.spec.tsx | 33 +++---------------- .../pages/ticket-details/TicketDetailPage.tsx | 4 +-- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/src/apps/support/src/pages/ticket-details/TicketDetailPage.spec.tsx b/src/apps/support/src/pages/ticket-details/TicketDetailPage.spec.tsx index 66b321d20..9567517b1 100644 --- a/src/apps/support/src/pages/ticket-details/TicketDetailPage.spec.tsx +++ b/src/apps/support/src/pages/ticket-details/TicketDetailPage.spec.tsx @@ -196,7 +196,7 @@ describe('TicketDetailPage reply access', () => { .toBeTruthy() }) - it('preserves freshly revalidated assignees when marking a ticket read completes', async () => { + it('revalidates fresh detail after marking the ticket read', async () => { const markReadRequest = createDeferred() mockedMarkRead.mockReturnValue(markReadRequest.promise) mockUseSWR.mockReturnValue({ @@ -211,35 +211,10 @@ describe('TicketDetailPage reply access', () => { await waitFor(() => { expect(mockMutate) - .toHaveBeenCalledWith(expect.any(Function), false) + .toHaveBeenCalledTimes(1) }) - - const updateCachedTicket = mockMutate.mock.calls[0][0] as ( - ticket?: SupportTicketDetail, - ) => SupportTicketDetail | undefined - const freshlyRevalidatedTicket: SupportTicketDetail = { - ...closedTicket, - assignees: [{ - assignedAt: '2026-08-07T01:30:00.000Z', - handle: 'support-staff', - userId: '67890', - }], - hasUnread: true, - responseCount: 1, - responses: [{ - createdAt: '2026-08-07T01:30:00.000Z', - id: 'response-1', - markdown: 'We are investigating.', - readBy: [], - userHandle: 'support-staff', - userId: '67890', - }], - } - - expect(updateCachedTicket(freshlyRevalidatedTicket)) - .toEqual({ ...freshlyRevalidatedTicket, hasUnread: false }) - expect(updateCachedTicket(undefined)) - .toBeUndefined() + expect(mockMutate.mock.calls[0]) + .toEqual([]) }) it('requires non-owner support staff to assign an open ticket before replying', () => { diff --git a/src/apps/support/src/pages/ticket-details/TicketDetailPage.tsx b/src/apps/support/src/pages/ticket-details/TicketDetailPage.tsx index 4df066db3..14eb8921a 100644 --- a/src/apps/support/src/pages/ticket-details/TicketDetailPage.tsx +++ b/src/apps/support/src/pages/ticket-details/TicketDetailPage.tsx @@ -75,9 +75,7 @@ export const TicketDetailPage: FC = () => { markedReadTicket.current = data.id markSupportTicketRead(data.id) - .then(() => mutate(current => (current - ? { ...current, hasUnread: false } - : current), false)) + .then(() => mutate()) .catch(() => undefined) }, [data, mutate])