diff --git a/src/components/NewMessageDialog.tsx b/src/components/NewMessageDialog.tsx
index ff61712..8adb246 100644
--- a/src/components/NewMessageDialog.tsx
+++ b/src/components/NewMessageDialog.tsx
@@ -18,7 +18,7 @@ import { useCrewmates } from '@/hooks/useCrewmates';
import { useFollowing } from '@/hooks/useFollowing';
import { genUserName } from '@/lib/genUserName';
import { cn } from '@/lib/utils';
-import { MessageCircle, Search, Users, UserCheck, ArrowRight } from 'lucide-react';
+import { MessageCircle, Search, Users, UserCheck, ArrowRight, CheckCircle2 } from 'lucide-react';
interface NewMessageDialogProps {
open: boolean;
@@ -38,10 +38,12 @@ function PersonRow({
candidate,
query,
onPick,
+ selected,
}: {
candidate: Candidate;
query: string;
onPick: (pubkey: string) => void;
+ selected: boolean;
}) {
const author = useAuthor(candidate.pubkey);
const metadata = author.data?.metadata;
@@ -59,7 +61,10 @@ function PersonRow({
);
}
@@ -91,6 +100,7 @@ export function NewMessageDialog({ open, onOpenChange }: NewMessageDialogProps)
const [query, setQuery] = useState('');
const [rawError, setRawError] = useState('');
+ const [selected, setSelected] = useState([]);
// Merge crew-mates (with shared-crew hints) and followed accounts, de-duped.
const candidates = useMemo(() => {
@@ -122,13 +132,35 @@ export function NewMessageDialog({ open, onOpenChange }: NewMessageDialogProps)
const crewCandidates = candidates.filter((c) => c.group === 'crew');
const followingCandidates = candidates.filter((c) => c.group === 'following');
- const goToConversation = (pubkey: string) => {
+ const reset = () => {
onOpenChange(false);
setQuery('');
setRawError('');
+ setSelected([]);
+ };
+
+ const goToConversation = (pubkey: string) => {
+ reset();
navigate(`/messages/${nip19.npubEncode(pubkey)}`);
};
+ /** Add/remove a person from the group selection. */
+ const toggleSelected = (pubkey: string) =>
+ setSelected((prev) =>
+ prev.includes(pubkey) ? prev.filter((p) => p !== pubkey) : [...prev, pubkey],
+ );
+
+ /** One person → 1:1 thread; two or more → an encrypted group thread. */
+ const startChat = () => {
+ if (selected.length === 0) return;
+ const to =
+ selected.length === 1
+ ? `/messages/${nip19.npubEncode(selected[0])}`
+ : `/messages/group/${selected.join(',')}`;
+ reset();
+ navigate(to);
+ };
+
// If the query looks like a raw key, offer to open it directly.
const trimmed = query.trim();
const looksLikeNpub = trimmed.startsWith('npub1');
@@ -163,7 +195,7 @@ export function NewMessageDialog({ open, onOpenChange }: NewMessageDialogProps)
New Message
- Search your people by name, or paste an npub to message anyone.
+ Search your people by name, or paste an npub to message anyone. Select two or more to start a group.
@@ -224,7 +256,8 @@ export function NewMessageDialog({ open, onOpenChange }: NewMessageDialogProps)
key={c.pubkey}
candidate={c}
query={query}
- onPick={goToConversation}
+ selected={selected.includes(c.pubkey)}
+ onPick={toggleSelected}
/>
))}
@@ -241,7 +274,8 @@ export function NewMessageDialog({ open, onOpenChange }: NewMessageDialogProps)
key={c.pubkey}
candidate={c}
query={query}
- onPick={goToConversation}
+ selected={selected.includes(c.pubkey)}
+ onPick={toggleSelected}
/>
))}
@@ -251,6 +285,19 @@ export function NewMessageDialog({ open, onOpenChange }: NewMessageDialogProps)
)}
)}
+
+ {selected.length > 0 && (
+
+
{selected.length} selected
+
+
+ )}