feat: add real time updates - #13833
Conversation
Subscribe to Gravity's ConversationsChannel (over the existing app-wide ActionCable connection) while the inbox tab or a conversation is open. The channel broadcasts a minimal signal when Impulse delivers a message; in response we refetch the affected Relay connections and refresh the unread badge, so new messages appear without pull-to-refresh. - useConversationsWebsocket: screen-scoped channel subscription hook, gated by the AREnableConversationsRealtime feature flag (off by default) and the user's session token - Conversation screen refetches when an event matches the open thread - Inbox list refetches on any event while the tab is active Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YQB2YVTL96ynGhYNTgbz2d
…annels fix
The mock had `channels: {}` on the cable mock instead of the
channelsHolder mock, matching the pre-fix code that incorrectly
referenced `cable.channels`. CI was failing because the real fix
(delete channelsHolder.channels[channelKey]) now throws against this
stale mock shape.
- track last marked message id so messages arriving on an open thread still get marked as read - debounce received websocket events (leading + trailing) to collapse bursts into at most two refetches - refetch on socket reconnect via a new onConnected callback so nothing broadcast during a drop is lost - unsubscribe the raw subscription if setChannel returns nothing - memoize message grouping in Messages and the partner offer event so the FlatList data prop keeps a stable identity - document why from_principal events are not filtered out Co-Authored-By: Claude Fable 5 <[email protected]>
Deliver received events directly; keeping the behavior simple is preferred over collapsing bursts. Co-Authored-By: Claude Fable 5 <[email protected]> Assisted-by: Claude:Fable-5 [claude-code]
cf537a8 to
14d7539
Compare
| useConversationsWebsocket({ | ||
| subscriptionKey: "inbox", | ||
| enabled: isActiveTab, | ||
| onEvent: () => { | ||
| refreshConversations() | ||
| GlobalStore.actions.bottomTabs.fetchCurrentUnreadConversationCount() | ||
| }, | ||
| // Catch up on anything broadcast while the socket was down. | ||
| onConnected: () => { | ||
| refreshConversations() | ||
| GlobalStore.actions.bottomTabs.fetchCurrentUnreadConversationCount() | ||
| }, | ||
| }) |
There was a problem hiding this comment.
isActiveTab tracks the inner Bids/Inquiries tab, not whether the Inbox screen is on screen. Inbox stays mounted when the user switches bottom tabs (isVisible is never passed from routes.tsx:1004, so Inbox.tsx:173 always gets false), so once someone opens Inquiries the subscription stays open and every incoming message runs refetchConnection(PAGE_SIZE) plus an unread-count fetch while the app is showing Home/Search/etc.
There's an existing helper for this: useIsFocusedInTab("inbox") (src/app/utils/hooks/useIsFocusedInTab.ts), so enabled: isActiveTab && isFocusedInTab.
Also, onEvent and onConnected are the same body — worth hoisting to one const handleUpdate = () => {...}.
| channel.on("received", handleReceived) | ||
| channel.on("connected", handleConnected) |
There was a problem hiding this comment.
No rejected or disconnected listener. If Gravity rejects the subscription (expired/invalid access_token, channel not deployed) the hook stays silent and conversations just never update in real time — indistinguishable from "no messages arrived". AuctionSocketContext wires both (AuctionSocketContext.tsx:70-73); at minimum logging rejected would make rollout failures visible.
ReviewSummaryAdds a The hook follows the existing Two unrelated fixes ride along and both look right: Issues Found🟡 Important — 🟢 Suggestion — 🟢 Suggestion — Areas ReviewedPerformance — the Security — the user access token travels in the subscription identifier over wss, same shape as the auction channel's Testing — Questions for Author
|
🎉 Beta Versions Generated (commit:
|
Description
This PR adds real-time conversation updates using websockets by introducing a new
useConversationsWebsockethook that subscribes to Gravity's ConversationsChannel. When messages are delivered to the user's conversations, the hook triggers a refetch of conversation data and updates the unread count.Key changes:
useConversationsWebsockethook that manages websocket subscriptions to conversation eventsGravityWebsocketContextfor cable managementAREnableConversationsRealtimeto allow safe rolloutImplementation details:
subscriptionKeyto allow multiple simultaneous subscriptions (e.g., inbox list + open conversation)🎉 Beta Versions Generated
iOS 🍏
9.13.0 (2026.07.16.10) - Available on Firebase
Screen.Recording.2026-07-15.at.16.19.03.mov
PR Checklist
AREnableConversationsRealtimeuseConversationsWebsocketChangelog updates
Changelog updates
Dev changes
useConversationsWebsockethookhttps://claude.ai/code/session_01YQB2YVTL96ynGhYNTgbz2d