[#442] Fix locations tab websocket sync for shot location changes#368
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Improves the useLocations hook’s real-time synchronization so the encounter Locations tab stays up-to-date when shot location changes occur elsewhere (e.g., shot counter character detail), including additional WebSocket payload handling and a fallback refetch path.
Changes:
- Extends
useLocationsWebSocket handling to accept multiple payload shapes and adds additional fight scoping. - Adds an encounter-driven fallback that refetches locations when shot→location assignments change.
- Makes the fallback refetch non-blocking (no loading flicker) by optionally skipping the loading state.
Comments suppressed due to low confidence (3)
src/hooks/useLocations.ts:153
fetchLocations(false)is triggered on every detected signature change from the encounter subscription, which can cause a burst of GET requests if multiple shot assignments change in quick succession (e.g., dragging several entities or rapid WS updates). Consider coalescing these refetches (debounce/throttle) or guarding against concurrent in-flightgetFightLocationscalls so the locations panel doesn’t spam the API and risk out-of-order updates overwriting newer state.
src/hooks/useLocations.ts:156- The new WebSocket-handling branches (accepting both array and wrapped payload shapes) plus the encounter-driven fallback refetch add several edge cases (payload shape variations, cross-fight filtering, signature-change detection) but there are currently no unit tests for
useLocations(while other hooks insrc/hooks/__tests__are covered). Adding tests that mocksubscribeToEntityandclient.getFightLocationswould help prevent regressions in this real-time sync logic.
useEffect(() => {
if (!fightId) return
const unsubscribe = subscribeToEntity("locations", (data: unknown) => {
const currentFightId = latestWsFightId.current
if (currentFightId && currentFightId !== fightId) {
return
}
const locationsData = Array.isArray(data)
? (data as Location[])
: data &&
typeof data === "object" &&
"locations" in (data as Record<string, unknown>) &&
Array.isArray((data as { locations: unknown }).locations)
? ((data as { locations: Location[] }).locations ?? [])
: null
if (!locationsData) return
const hasFightIds = locationsData.some(loc => !!loc.fight_id)
const isForThisFight =
locationsData.length === 0 ||
!hasFightIds ||
locationsData.some(loc => loc.fight_id === fightId)
if (!isForThisFight) return
// Update locations without loading state changes to avoid UI flicker.
setLocations(locationsData)
})
return unsubscribe
}, [fightId, subscribeToEntity])
return {
locations,
loading,
error,
refetch: fetchLocations,
}
}
src/hooks/useLocations.ts:146
- The fallback refetch subscribes to
encounterand builds a signature fromencounter.shotsusingshot.idandshot.location_id, but encounter shots in this codebase are shot groups shaped like{ shot, characters, vehicles }(seeLocationsPanel’sencounter.shots.forEach((shotGroup) => ...)). As written,shot.id/shot.location_idwill beundefined, so this signature won’t change when a character’s location changes, and the refetch won’t reliably run.
Adjust the signature logic to derive a stable mapping from the encounter payload that actually changes on shot-location edits (e.g., per character/vehicle shot_id + their location string), so location changes from the shot counter can trigger the refetch.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a regression where location changes made from shot counter character details did not consistently appear in the encounter Locations tab in real time.
Related Fizzy Card: #442 - Websocket Location updates
Changes
useLocationswebsocket handling to accept both array and wrapped payload shapesfight_idupdates to avoid cross-fight location updateslocation_idassignments changeFiles Changed
src/hooks/useLocations.ts- Improve real-time location sync robustness and add encounter fallback refetchTest Plan
npx eslint src/hooks/useLocations.ts