From 4faf05fee9f0c8aef59437de739ebbd2fa7333ca Mon Sep 17 00:00:00 2001 From: maaz519 Date: Wed, 22 Jul 2026 19:23:57 +0530 Subject: [PATCH] feat(messaging-ui): start direct messages + groups (Slack-style people picker) Add a 'New message' + on the Direct messages section that opens a people picker (NewConversation): pick one person -> DM, two or more -> group with an optional name, via the adapter's existing openThread({participantIds, membership, subject}). Expose directory() on MessagingAdapter (org people list); MockAdapter implements it + dedupes 1:1 DMs. 72 tests green. Co-Authored-By: Claude Opus 4.8 --- .../insignia-iios-messaging-ui-0.1.0.tgz | Bin 25341 -> 26316 bytes packages/iios-messaging-ui/src/adapter.ts | 4 + .../iios-messaging-ui/src/adapters/mock.ts | 13 +++ .../src/components/messenger.tsx | 44 ++++++-- .../src/components/new-conversation.test.tsx | 66 ++++++++++++ .../src/components/new-conversation.tsx | 97 ++++++++++++++++++ packages/iios-messaging-ui/src/styles.css | 26 +++++ 7 files changed, 241 insertions(+), 9 deletions(-) create mode 100644 packages/iios-messaging-ui/src/components/new-conversation.test.tsx create mode 100644 packages/iios-messaging-ui/src/components/new-conversation.tsx diff --git a/packages/iios-messaging-ui/insignia-iios-messaging-ui-0.1.0.tgz b/packages/iios-messaging-ui/insignia-iios-messaging-ui-0.1.0.tgz index c7622b028aeda06a22e2625cacc34bfb48367f08..c3164274fc2cc6ffe4e2683a82866b30f4169cb8 100644 GIT binary patch delta 26015 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 diff --git a/packages/iios-messaging-ui/src/adapter.ts b/packages/iios-messaging-ui/src/adapter.ts index 1670e96..3ea31f5 100644 --- a/packages/iios-messaging-ui/src/adapter.ts +++ b/packages/iios-messaging-ui/src/adapter.ts @@ -61,6 +61,10 @@ export interface MessagingAdapter { * Absent => the composer offers no autocomplete (you can still type @text). */ listMembers?(threadId: string): Promise; + /** The people you can start a conversation with (org directory). Drives the "New message" + * people picker. Absent => the UI hides DM/group creation (you can still open channels). */ + directory?(): Promise; + // ── Channels (optional capability) ────────────────────────────── // A channel is just a third membership beyond dm/group: a discoverable, joinable room. // Implement all four to enable the channels UI; absent => the UI hides channels entirely. diff --git a/packages/iios-messaging-ui/src/adapters/mock.ts b/packages/iios-messaging-ui/src/adapters/mock.ts index d3c8ad7..e75b370 100644 --- a/packages/iios-messaging-ui/src/adapters/mock.ts +++ b/packages/iios-messaging-ui/src/adapters/mock.ts @@ -159,7 +159,20 @@ export class MockAdapter implements MessagingAdapter { }); } + async directory(): Promise { + return MOCK_PEOPLE.map((p) => ({ ...p })); + } + async openThread(p: { participantIds: string[]; membership?: Membership; subject?: string }): Promise<{ threadId: string }> { + // A DM to someone you already have reuses the existing 1:1 thread (dedupe, like the live door). + if ((p.membership ?? (p.participantIds.length === 1 ? 'dm' : 'group')) === 'dm' && p.participantIds.length === 1) { + const target = p.participantIds[0]; + for (const [id, t] of this.threads) { + if (t.membership === 'dm' && t.participants.length === 2 && t.participants.includes(ME) && t.participants.includes(target)) { + return { threadId: id }; + } + } + } const membership = p.membership ?? (p.participantIds.length === 1 ? 'dm' : 'group'); const threadId = `th_mock_${this.seq++}`; this.threads.set(threadId, { diff --git a/packages/iios-messaging-ui/src/components/messenger.tsx b/packages/iios-messaging-ui/src/components/messenger.tsx index 9a5b198..2b7e54e 100644 --- a/packages/iios-messaging-ui/src/components/messenger.tsx +++ b/packages/iios-messaging-ui/src/components/messenger.tsx @@ -3,6 +3,7 @@ import { useConversations } from '../hooks/use-conversations'; import { useAdapter } from '../provider'; import { ConversationList } from './conversation-list'; import { ChannelBrowser } from './channel-browser'; +import { NewConversation } from './new-conversation'; import { Thread } from './thread'; import { ThreadPane } from './thread-pane'; @@ -15,28 +16,41 @@ export function Messenger() { const { conversations, loading, error, refetch } = useConversations(); const adapter = useAdapter(); const channelsSupported = typeof adapter.browseChannels === 'function'; + const directorySupported = typeof adapter.directory === 'function'; const [selected, setSelected] = useState(null); const [browsing, setBrowsing] = useState(false); + const [composing, setComposing] = useState(false); // "New message" people picker open const [activeRoot, setActiveRoot] = useState(null); // open thread pane's root message useEffect(() => { - if (browsing) return; + if (browsing || composing) return; if (selected && conversations.some((c) => c.threadId === selected)) return; setSelected(conversations[0]?.threadId ?? null); - }, [conversations, selected, browsing]); + }, [conversations, selected, browsing, composing]); - // Switching conversations (or into browse) closes any open thread pane. - useEffect(() => setActiveRoot(null), [selected, browsing]); + // Switching conversations (or into browse/compose) closes any open thread pane. + useEffect(() => setActiveRoot(null), [selected, browsing, composing]); const channels = useMemo(() => conversations.filter((c) => c.membership === 'channel'), [conversations]); const dms = useMemo(() => conversations.filter((c) => c.membership !== 'channel'), [conversations]); function pick(threadId: string): void { setBrowsing(false); + setComposing(false); setSelected(threadId); } + function openBrowse(): void { + setComposing(false); + setBrowsing(true); + } + + function openCompose(): void { + setBrowsing(false); + setComposing(true); + } + return (
@@ -77,12 +96,19 @@ export function Messenger() { pick(threadId); }} /> + ) : composing ? ( + { + refetch(); + pick(threadId); + }} + /> ) : ( )} - {!browsing && selected && activeRoot ? ( + {!browsing && !composing && selected && activeRoot ? ( setActiveRoot(null)} /> ) : null}
diff --git a/packages/iios-messaging-ui/src/components/new-conversation.test.tsx b/packages/iios-messaging-ui/src/components/new-conversation.test.tsx new file mode 100644 index 0000000..ab26ccd --- /dev/null +++ b/packages/iios-messaging-ui/src/components/new-conversation.test.tsx @@ -0,0 +1,66 @@ +import { describe, it, expect } from 'vitest'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { MessagingProvider } from '../provider'; +import { MockAdapter } from '../adapters/mock'; +import { Messenger } from './messenger'; + +function mount(adapter = new MockAdapter()) { + render( + + + , + ); + return adapter; +} + +describe('MockAdapter directory + openThread', () => { + it('directory lists people you can message', async () => { + const a = new MockAdapter(); + const people = await a.directory(); + expect(people.some((p) => p.name === 'Dan Whitaker')).toBe(true); + }); + + it('one participant opens a dm; two+ open a group with a subject', async () => { + const a = new MockAdapter(); + const dm = await a.openThread({ participantIds: ['pp_dan'], membership: 'dm' }); + const list = await a.listConversations(); + expect(list.find((c) => c.threadId === dm.threadId)?.membership).toBe('dm'); + + const group = await a.openThread({ participantIds: ['pp_dan', 'pp_priya'], membership: 'group', subject: 'Roof crew' }); + const g = (await a.listConversations()).find((c) => c.threadId === group.threadId); + expect(g?.membership).toBe('group'); + expect(g?.title).toBe('Roof crew'); + }); + + it('opening a dm with the same person reuses the existing thread', async () => { + const a = new MockAdapter(); + const first = await a.openThread({ participantIds: ['pp_priya'], membership: 'dm' }); + const second = await a.openThread({ participantIds: ['pp_priya'], membership: 'dm' }); + expect(second.threadId).toBe(first.threadId); + }); +}); + +describe(' new conversation flow', () => { + it('opens the picker from the Direct messages +, and starting a chat leaves the picker', async () => { + mount(); + // Open the "New message" picker. + fireEvent.click(await screen.findByTitle('New message')); + expect(await screen.findByText('New message')).toBeTruthy(); + + // Pick a person and start a DM. + fireEvent.click(await screen.findByText('Dan Whitaker')); + fireEvent.click(screen.getByText('Start chat')); + + // The picker closes (we're back in a thread view — the picker heading is gone). + await waitFor(() => expect(screen.queryByText('Start chat')).toBeNull()); + }); + + it('selecting two people switches the action to group create', async () => { + mount(); + fireEvent.click(await screen.findByTitle('New message')); + fireEvent.click(await screen.findByText('Dan Whitaker')); + fireEvent.click(await screen.findByText('Priya Nair')); + expect(screen.getByText(/Create group \(2\)/)).toBeTruthy(); + expect(screen.getByLabelText('Group name')).toBeTruthy(); + }); +}); diff --git a/packages/iios-messaging-ui/src/components/new-conversation.tsx b/packages/iios-messaging-ui/src/components/new-conversation.tsx new file mode 100644 index 0000000..2436c8a --- /dev/null +++ b/packages/iios-messaging-ui/src/components/new-conversation.tsx @@ -0,0 +1,97 @@ +import { useEffect, useState } from 'react'; +import { useAdapter } from '../provider'; +import type { Person } from '../types'; + +/** + * Start a direct message or a group — Slack-style. Pick people from the org directory: one selected + * opens a DM (deduped by the adapter), two or more create a group with an optional name. Shown in + * the main pane like the channel browser. + */ +export function NewConversation({ onCreated }: { onCreated?: (threadId: string) => void }) { + const adapter = useAdapter(); + const [people, setPeople] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [q, setQ] = useState(''); + const [selected, setSelected] = useState([]); + const [name, setName] = useState(''); + const [busy, setBusy] = useState(false); + + useEffect(() => { + if (!adapter.directory) { + setLoading(false); + return; + } + let alive = true; + adapter + .directory() + .then((p) => { + if (alive) { + setPeople(p); + setError(null); + } + }) + .catch((e: unknown) => { + if (alive) setError(e instanceof Error ? e.message : String(e)); + }) + .finally(() => { + if (alive) setLoading(false); + }); + return () => { + alive = false; + }; + }, [adapter]); + + const filtered = people.filter((p) => p.name.toLowerCase().includes(q.trim().toLowerCase())); + const isGroup = selected.length > 1; + const canStart = selected.length >= 1 && !busy; + + function toggle(id: string): void { + setSelected((s) => (s.includes(id) ? s.filter((x) => x !== id) : [...s, id])); + } + + async function start(): Promise { + if (!canStart) return; + setBusy(true); + setError(null); + try { + const res = await adapter.openThread({ + participantIds: selected, + membership: isGroup ? 'group' : 'dm', + ...(isGroup && name.trim() ? { subject: name.trim() } : {}), + }); + onCreated?.(res.threadId); + } catch (e) { + setError(e instanceof Error ? e.message : String(e)); + } finally { + setBusy(false); + } + } + + return ( +
+
New message
+
+ setQ(e.target.value)} placeholder="Search people…" aria-label="Search people" /> + {isGroup ? ( + setName(e.target.value)} placeholder="Group name (optional)" aria-label="Group name" /> + ) : null} + {error ?
{error}
: null} +
+ {loading && people.length === 0 ?
Loading…
: null} + {!loading && filtered.length === 0 ?
No people found.
: null} + {filtered.map((p) => ( + + ))} +
+ +
+
+ ); +} diff --git a/packages/iios-messaging-ui/src/styles.css b/packages/iios-messaging-ui/src/styles.css index 0172ed0..43c8a81 100644 --- a/packages/iios-messaging-ui/src/styles.css +++ b/packages/iios-messaging-ui/src/styles.css @@ -500,6 +500,32 @@ gap: 5px; cursor: pointer; } +/* new conversation (DM / group) picker */ +.miu-newconv { + display: flex; + flex-direction: column; + gap: 10px; +} +.miu-person-row { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 10px; + border: 1px solid var(--miu-border); + border-radius: 10px; + background: var(--miu-panel); + cursor: pointer; +} +.miu-person-row:hover { + border-color: var(--miu-accent); +} +.miu-person-row.is-active { + border-color: var(--miu-accent); + background: color-mix(in srgb, var(--miu-accent) 10%, var(--miu-panel)); +} +.miu-person-row .miu-browser-name { + flex: 1 1 auto; +} .miu-browser-list { display: flex; flex-direction: column;