Autoreconcile and don't bother with toast

This commit is contained in:
Jack Kingsman
2026-02-27 16:38:08 -08:00
parent 194852ed16
commit 60455cdd7b
3 changed files with 24 additions and 4 deletions

View File

@@ -173,6 +173,7 @@ export function App() {
fetchOlderMessages,
addMessageIfNew,
updateMessageAck,
triggerReconcile,
} = useConversationMessages(activeConversation);
const {
@@ -182,6 +183,7 @@ export function App() {
incrementUnread,
markAllRead,
trackNewMessage,
refreshUnreads,
} = useUnreadCounts(channels, contacts, activeConversation);
// Determine if active contact is a repeater (used for routing to dashboard)
@@ -227,10 +229,12 @@ export function App() {
});
},
onReconnect: () => {
toast.warning('Unstable connection', {
description: 'Please refresh the page to ensure all messages are correctly loaded.',
duration: 10000,
});
// Silently recover any data missed during the disconnect window
triggerReconcile();
refreshUnreads();
fetchAllContacts()
.then((data) => setContacts(data))
.catch(console.error);
},
onMessage: (msg: Message) => {
const activeConv = activeConversationRef.current;
@@ -299,6 +303,9 @@ export function App() {
setConfig,
activeConversationRef,
setContacts,
triggerReconcile,
refreshUnreads,
fetchAllContacts,
]
);

View File

@@ -66,6 +66,7 @@ interface UseConversationMessagesResult {
fetchOlderMessages: () => Promise<void>;
addMessageIfNew: (msg: Message) => boolean;
updateMessageAck: (messageId: number, ackCount: number, paths?: MessagePath[]) => void;
triggerReconcile: () => void;
}
export function useConversationMessages(
@@ -258,6 +259,15 @@ export function useConversationMessages(
}
}, [activeConversation, loadingOlder, hasOlderMessages, messages, applyPendingAck]);
// Trigger a background reconciliation for the current conversation.
// Used after WebSocket reconnects to silently recover any missed messages.
const triggerReconcile = useCallback(() => {
const conv = activeConversation;
if (!conv || conv.type === 'raw' || conv.type === 'map' || conv.type === 'visualizer') return;
const controller = new AbortController();
reconcileFromBackend(conv, controller.signal);
}, [activeConversation]); // eslint-disable-line react-hooks/exhaustive-deps
// Background reconciliation: silently fetch from backend after a cache restore
// and only update state if something differs (missed WS message, stale ack, etc.).
// No-ops on the happy path — zero rerenders when cache is already consistent.
@@ -435,5 +445,6 @@ export function useConversationMessages(
fetchOlderMessages,
addMessageIfNew,
updateMessageAck,
triggerReconcile,
};
}

View File

@@ -17,6 +17,7 @@ interface UseUnreadCountsResult {
incrementUnread: (stateKey: string, hasMention?: boolean) => void;
markAllRead: () => void;
trackNewMessage: (msg: Message) => void;
refreshUnreads: () => Promise<void>;
}
export function useUnreadCounts(
@@ -170,5 +171,6 @@ export function useUnreadCounts(
incrementUnread,
markAllRead,
trackNewMessage,
refreshUnreads: fetchUnreads,
};
}