diff --git a/packages/iios-messaging-ui/package.json b/packages/iios-messaging-ui/package.json index e785610..3274af2 100644 --- a/packages/iios-messaging-ui/package.json +++ b/packages/iios-messaging-ui/package.json @@ -1,6 +1,6 @@ { "name": "@insignia/iios-messaging-ui", - "version": "0.1.5", + "version": "0.1.6", "type": "module", "main": "dist/index.js", "module": "dist/index.js", diff --git a/packages/iios-messaging-ui/src/components/messenger.tsx b/packages/iios-messaging-ui/src/components/messenger.tsx index e28c2b7..dd2effc 100644 --- a/packages/iios-messaging-ui/src/components/messenger.tsx +++ b/packages/iios-messaging-ui/src/components/messenger.tsx @@ -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]); diff --git a/packages/iios-messaging-ui/src/inbox/inbox.tsx b/packages/iios-messaging-ui/src/inbox/inbox.tsx index a4e42b2..e3b5c8c 100644 --- a/packages/iios-messaging-ui/src/inbox/inbox.tsx +++ b/packages/iios-messaging-ui/src/inbox/inbox.tsx @@ -32,17 +32,30 @@ const timeOf = (iso?: string): string => { }; /** The unified inbox: work items + mail in one list; click a threaded row to read + reply. */ -export function Inbox() { +export function Inbox({ focusThreadId }: { focusThreadId?: string | null } = {}) { const [filter, setFilter] = useState('OPEN'); const { items, loading, error, transition, refetch } = useInbox(filter); const compose = useCompose(); const [selectedId, setSelectedId] = useState(null); const [composing, setComposing] = useState(false); + // Deep link (e.g. from global search): mail lives in the Open view, so switch there and let the + // selection effect pick the matching thread once the list loads. useEffect(() => { + if (focusThreadId) setFilter('OPEN'); + }, [focusThreadId]); + + useEffect(() => { + if (focusThreadId) { + const hit = items.find((i) => i.threadId === focusThreadId); + if (hit) { + setSelectedId(hit.id); + return; + } + } if (selectedId && items.some((i) => i.id === selectedId)) return; setSelectedId(items[0]?.id ?? null); - }, [items, selectedId]); + }, [items, selectedId, focusThreadId]); const selected = items.find((i) => i.id === selectedId) ?? null;