import { useState } from 'react'; import { Pressable, Text, TextInput, View } from 'react-native'; import { toast } from 'sonner-native'; import { BottomSheet } from '@/components/BottomSheet'; import { useAddMembers } from '@/hooks/use-member-management'; import { toUserMessage } from '@/lib/errors'; import { cn } from '@/lib/utils'; interface AddMembersSheetProps { open: boolean; onClose: () => void; networkId: string; } const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; /** * Invite people to a network by email. Mirrors desktop's add-members-dialog — * accepts one email at a time (comma/space/enter to commit), shows chips, and * submits the batch via `addMembers`. */ export function AddMembersSheet({ open, onClose, networkId, }: AddMembersSheetProps) { const [draft, setDraft] = useState(''); const [emails, setEmails] = useState([]); const addMembers = useAddMembers(networkId); const [prevOpen, setPrevOpen] = useState(open); if (open !== prevOpen) { setPrevOpen(open); if (open) { setDraft(''); setEmails([]); } } const commitDraft = (): string[] => { const candidate = draft.trim().toLowerCase().replace(/,$/, ''); if (!candidate) return emails; if (!EMAIL_RE.test(candidate)) { toast.error('Enter a valid email address'); return emails; } if (emails.includes(candidate)) { setDraft(''); return emails; } const next = [...emails, candidate]; setEmails(next); setDraft(''); return next; }; const removeEmail = (email: string) => setEmails((prev) => prev.filter((e) => e !== email)); const handleSubmit = async () => { const finalEmails = commitDraft(); if (finalEmails.length === 0) return; try { await addMembers.mutateAsync(finalEmails); toast.success( finalEmails.length === 1 ? 'Invitation sent' : `${finalEmails.length} invitations sent`, ); onClose(); } catch (err) { toast.error(toUserMessage(err)); } }; const canSubmit = !addMembers.isPending && (emails.length > 0 || EMAIL_RE.test(draft.trim().toLowerCase())); return ( Add members Existing users join right away; others get an email invite. {emails.length > 0 ? ( {emails.map((email) => ( removeEmail(email)} className="flex-row items-center bg-white/10 rounded-full pl-3 pr-2 py-1" > {email} × ))} ) : null} { if (text.endsWith(',') || text.endsWith(' ')) { setDraft(text); commitDraft(); } else { setDraft(text); } }} placeholder="name@example.com" placeholderTextColor="rgba(255,255,255,0.4)" autoFocus autoCapitalize="none" autoCorrect={false} keyboardType="email-address" returnKeyType="done" onSubmitEditing={() => commitDraft()} editable={!addMembers.isPending} className="text-white text-base bg-white/10 rounded-xl px-4 py-3 mt-4" /> {addMembers.isPending ? 'Sending…' : 'Send invites'} ); }