feat(messaging-ui): focusThreadId on Messenger + Inbox for search deep-links (0.1.6)

A host can pass focusThreadId to select/open a specific conversation — used by the
CRM's global search to jump to the exact thread. Mail switches to Open + selects the
matching item; messenger selects the thread. (Source for the already-published 0.1.6.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 14:35:22 +05:30
parent f5c89159f4
commit b3eb027071
3 changed files with 25 additions and 4 deletions
@@ -12,7 +12,7 @@ import { ThreadPane } from './thread-pane';
* with a channel browser when the adapter supports channels. Owns only selection + browse state;
* all data flows through the injected adapter via the hooks.
*/
export function Messenger() {
export function Messenger({ focusThreadId }: { focusThreadId?: string | null } = {}) {
const { conversations, loading, error, refetch } = useConversations();
const adapter = useAdapter();
const channelsSupported = typeof adapter.browseChannels === 'function';
@@ -32,6 +32,14 @@ export function Messenger() {
// Switching conversations (or into browse/compose) closes any open thread pane.
useEffect(() => setActiveRoot(null), [selected, browsing, composing]);
// Deep link (e.g. from global search): focus the requested conversation.
useEffect(() => {
if (!focusThreadId) return;
setBrowsing(false);
setComposing(false);
setSelected(focusThreadId);
}, [focusThreadId]);
const channels = useMemo(() => conversations.filter((c) => c.membership === 'channel'), [conversations]);
const dms = useMemo(() => conversations.filter((c) => c.membership !== 'channel'), [conversations]);
const selectedConversation = useMemo(() => conversations.find((c) => c.threadId === selected) ?? null, [conversations, selected]);