import { useState } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faUserPlus, faTrash, faPlus } from '@fortawesome/pro-duotone-svg-icons'; import { Input } from '@/components/base/input/input'; import { Select } from '@/components/base/select/select'; import { Button } from '@/components/base/buttons/button'; // Multi-email invite form. Uses the platform's sendInvitations mutation which // takes a list of emails; the invited members all get the same role (the // platform doesn't support per-email roles in a single call). If the admin // needs different roles, they invite in multiple batches, or edit roles // afterwards via the team listing. // // Role selection is optional — leaving it blank invites members without a // role, matching the platform's default. When a role is selected, the caller // is expected to apply it via updateWorkspaceMemberRole after the invited // member accepts (this form just reports the selected roleId back). export type RoleOption = { id: string; label: string; supportingText?: string; }; export type InviteMemberFormValues = { emails: string[]; roleId: string; }; const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; type InviteMemberFormProps = { value: InviteMemberFormValues; onChange: (value: InviteMemberFormValues) => void; roles: RoleOption[]; }; export const InviteMemberForm = ({ value, onChange, roles }: InviteMemberFormProps) => { const [draft, setDraft] = useState(''); const addEmail = (rawValue?: string) => { const source = (rawValue ?? draft).trim(); if (!source) return; const trimmed = source.replace(/,+$/, '').trim(); if (!trimmed) return; if (!EMAIL_REGEX.test(trimmed)) return; if (value.emails.includes(trimmed)) { setDraft(''); return; } onChange({ ...value, emails: [...value.emails, trimmed] }); setDraft(''); }; const removeEmail = (email: string) => { onChange({ ...value, emails: value.emails.filter((e) => e !== email) }); }; // The Input component wraps react-aria TextField which doesn't expose // onKeyDown via its typed props — so we commit on comma via the onChange // handler instead. Users can also press the Add button or tab onto it. const handleChange = (next: string) => { if (next.endsWith(',')) { addEmail(next); return; } setDraft(next); }; return (
Type a comma to add multiple emails, or click Add.
{value.emails.length} invitee{value.emails.length === 1 ? '' : 's'}