// Primus IQ — Create Project Modal const CreateProjectModal = ({ open, onClose, onCreate }) => { const [name, setName] = React.useState(''); const [desc, setDesc] = React.useState(''); const [practice, setPractice] = React.useState(''); const [matches, setMatches] = React.useState([]); const [joining, setJoining] = React.useState({}); // { [projectId]: 'pending' | 'joined' | 'requested' } // Reset fields when the modal opens. React.useEffect(() => { if (!open) return; setName(''); setDesc(''); setPractice(''); setJoining({}); setMatches([]); }, [open]); // Debounced trigram (fuzzy) search for similar/duplicate projects as the name is typed. React.useEffect(() => { const q = name.trim(); if (!open || q.length < 2) { setMatches([]); return; } const t = setTimeout(() => { PrimusAPI.listProjects(q).then(d => setMatches((d || []).slice(0, 10))).catch(() => setMatches([])); }, 250); return () => clearTimeout(t); }, [name, open]); if (!open) return null; const practices = [ 'Public Policy Realization', 'Sector Potential Realization', 'Impact Realization', 'Economic Potential Realization', 'Data & Digital Strategy', 'Transaction Realization', ]; const trimmed = name.trim().toLowerCase(); // Exact (case-insensitive) duplicate is always among the trigram results (similarity 1.0). const exactDup = matches.find(p => (p.name || '').trim().toLowerCase() === trimmed); const handleJoin = async (p) => { setJoining(j => ({ ...j, [p.id]: 'pending' })); try { const res = await PrimusAPI.joinProject(p.id); setJoining(j => ({ ...j, [p.id]: res && res.status === 'approved' ? 'joined' : 'requested' })); } catch { setJoining(j => ({ ...j, [p.id]: undefined })); } }; return (
setName(e.target.value)} placeholder="e.g. GCC Renewables Capex 2026" style={fieldInput}/> {matches.length > 0 && (
{exactDup ? 'This project already exists' : 'Similar existing projects — join instead?'}
{/* ~3 rows visible, the rest scroll */}
{matches.map(p => { const isMember = !!p.membership; const st = joining[p.id]; return (
{p.name}
{p.practice}
{isMember ? ( Joined ) : st === 'joined' ? ( Joined ✓ ) : st === 'requested' ? ( Requested ✓ ) : ( )}
); })}
)}