fix(tickets): refresh status and resources in detail panel after update
Some checks failed
Mirror to GitHub / mirror (push) Successful in 3s
CI / backend (pull_request) Failing after 17m32s
CI / frontend (pull_request) Failing after 48s
CI / e2e (pull_request) Has been skipped

Status update was returning only new_status (string) and the parent list's
onStatusUpdated only set status_name. The <select> was bound to status_id,
which never changed — so it visually reverted to the old status even though
the PATCH succeeded.

- Backend: include new_status_id in the status-update response.
- Panel: own currentStatusId/currentStatusName state so the select reflects
  the change immediately and survives stale parent snapshots.
- Parent list: update status_id on both the row and selectedTicket so the
  list row stays in sync when the panel stays open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 21:28:48 +00:00
parent 60851b400a
commit 04ff2ea301
6 changed files with 33 additions and 11 deletions

View File

@@ -16,7 +16,7 @@ import type { PSAResource } from '@/types/tickets'
interface Props {
ticket: PSATicketSearchResult
onClose: () => void
onStatusUpdated?: (ticketId: number, newStatus: string) => void
onStatusUpdated?: (ticketId: number, newStatus: string, newStatusId: number) => void
onSelectRelated?: (ticketId: number) => void
}
@@ -37,6 +37,11 @@ export function TicketDetailPanel({ ticket, onClose, onStatusUpdated, onSelectRe
const [contextLoading, setContextLoading] = useState(true)
const [resourcesLoading, setResourcesLoading] = useState(true)
// Local status state so the select reflects updates immediately, independent
// of the parent list's stale `selectedTicket` snapshot.
const [currentStatusId, setCurrentStatusId] = useState<number | null>(ticket.status_id ?? null)
const [currentStatusName, setCurrentStatusName] = useState<string | null>(ticket.status_name ?? null)
const ticketIdNum = Number(ticket.id)
const loadResources = useCallback(() => {
@@ -51,6 +56,8 @@ export function TicketDetailPanel({ ticket, onClose, onStatusUpdated, onSelectRe
setContext(null)
setResources([])
setStatuses([])
setCurrentStatusId(ticket.status_id ?? null)
setCurrentStatusName(ticket.status_name ?? null)
Promise.all([
psaContextApi.getTicketContext(ticketIdNum),
@@ -69,10 +76,13 @@ export function TicketDetailPanel({ ticket, onClose, onStatusUpdated, onSelectRe
setContextLoading(false)
setResourcesLoading(false)
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ticket.id, ticketIdNum])
function handleStatusUpdated(ticketId: number, newStatus: string) {
onStatusUpdated?.(ticketId, newStatus)
function handleStatusUpdated(ticketId: number, newStatus: string, newStatusId: number) {
setCurrentStatusId(newStatusId)
setCurrentStatusName(newStatus)
onStatusUpdated?.(ticketId, newStatus, newStatusId)
}
return (
@@ -96,6 +106,8 @@ export function TicketDetailPanel({ ticket, onClose, onStatusUpdated, onSelectRe
{/* Header with status selector — optimistic, no loading gate */}
<TicketDetailHeader
ticket={ticket}
currentStatusId={currentStatusId}
currentStatusName={currentStatusName}
statuses={statuses}
onStatusUpdated={handleStatusUpdated}
/>