Feat/messaging ui foundation #10
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@insignia/iios-messaging-ui",
|
"name": "@insignia/iios-messaging-ui",
|
||||||
"version": "0.1.5",
|
"version": "0.1.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.js",
|
"module": "dist/index.js",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ThreadPane } from './thread-pane';
|
|||||||
* with a channel browser when the adapter supports channels. Owns only selection + browse state;
|
* with a channel browser when the adapter supports channels. Owns only selection + browse state;
|
||||||
* all data flows through the injected adapter via the hooks.
|
* 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 { conversations, loading, error, refetch } = useConversations();
|
||||||
const adapter = useAdapter();
|
const adapter = useAdapter();
|
||||||
const channelsSupported = typeof adapter.browseChannels === 'function';
|
const channelsSupported = typeof adapter.browseChannels === 'function';
|
||||||
@@ -32,6 +32,14 @@ export function Messenger() {
|
|||||||
// Switching conversations (or into browse/compose) closes any open thread pane.
|
// Switching conversations (or into browse/compose) closes any open thread pane.
|
||||||
useEffect(() => setActiveRoot(null), [selected, browsing, composing]);
|
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 channels = useMemo(() => conversations.filter((c) => c.membership === 'channel'), [conversations]);
|
||||||
const dms = 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]);
|
const selectedConversation = useMemo(() => conversations.find((c) => c.threadId === selected) ?? null, [conversations, selected]);
|
||||||
|
|||||||
@@ -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. */
|
/** 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<InboxState>('OPEN');
|
const [filter, setFilter] = useState<InboxState>('OPEN');
|
||||||
const { items, loading, error, transition, refetch } = useInbox(filter);
|
const { items, loading, error, transition, refetch } = useInbox(filter);
|
||||||
const compose = useCompose();
|
const compose = useCompose();
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||||
const [composing, setComposing] = useState(false);
|
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(() => {
|
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;
|
if (selectedId && items.some((i) => i.id === selectedId)) return;
|
||||||
setSelectedId(items[0]?.id ?? null);
|
setSelectedId(items[0]?.id ?? null);
|
||||||
}, [items, selectedId]);
|
}, [items, selectedId, focusThreadId]);
|
||||||
|
|
||||||
const selected = items.find((i) => i.id === selectedId) ?? null;
|
const selected = items.find((i) => i.id === selectedId) ?? null;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user