// Primus IQ — Projects Listing Screen const SAMPLE_PROJECTS = [ { id: 'p1', name: 'GCC Market Entry · Acme', desc: 'Sector Potential Realization — KSA vs UAE entry sequencing, pricing strategy, talent map.', tag: 'Sector Potential Realization', role: 'OWNER', files: 24, members: ['N', 'A', 'P'], more: 8, updated: '24 May' }, { id: 'p2', name: 'Globex APAC Reorg', desc: 'Impact Realization — operating model redesign across 6 markets, change roadmap with cost guardrails.', tag: 'Impact Realization', role: 'MEMBER', files: 38, members: ['N', 'M'], more: 4, updated: '22 May' }, { id: 'p3', name: 'India Public Policy 2026', desc: 'Policy track for FY26 — state-level digital governance benchmarks and procurement reform notes.', tag: 'Public Policy Realization', role: 'OWNER', files: 12, members: ['N', 'V'], more: 20, updated: '18 May' }, { id: 'p4', name: 'TCFD · Portfolio Co.', desc: 'Climate disclosure rollup across 18 portfolio companies — Scope 1/2 baselines, gap remediation.', tag: 'Economic Potential Realization', role: 'MEMBER', files: 19, members: ['N', 'S'], more: 5, updated: '12 May' }, ]; const DISCOVER_PROJECTS = [ { id: 'd1', name: 'Indian MSME Financing', desc: 'Quarterly research on fintech, NBFC and public scheme penetration in MSME credit.', tag: 'Economic Potential Realization', owner: 'A. Mehta', members: 9, files: 47, updated: '23 May' }, { id: 'd2', name: 'Healthcare Supply Atlas', desc: 'Live corpus on global pharma logistics — 220 papers, 40 interviews, monthly refresh.', tag: 'Transaction Realization', owner: 'P. Rao', members: 32, files: 220, updated: '20 May' }, { id: 'd3', name: 'Auto OEM EV Roadmap', desc: 'Buy-side diligence for an EV component supplier — capacity, IP, customer concentration.', tag: 'Sector Potential Realization', owner: 'V. Kumar', members: 6, files: 31, updated: '19 May' }, { id: 'd4', name: 'PSU Disinvestment Track', desc: 'Cross-firm track of PSU strategic-sale candidates, valuation desks and timelines.', tag: 'Public Policy Realization', owner: 'S. Iyer', members: 14, files: 88, updated: '17 May' }, { id: 'd5', name: 'GCC Renewables 2026', desc: 'Annual thought-leadership flagship — 80pp report covering capex, regulation, partnerships.', tag: 'Economic Potential Realization', owner: 'N. Singh', members: 12, files: 65, updated: '20 May' }, { id: 'd6', name: 'CSR Effectiveness Index', desc: 'Multi-state index of CSR spend efficiency — quantitative model + interview corpus.', tag: 'Impact Realization', owner: 'R. Banerjee', members: 8, files: 28, updated: '14 May' }, ]; const adaptProject = (p) => ({ id: p.id, name: p.name, desc: p.description || '', tag: p.practice || '', role: p.membership ? p.membership.toUpperCase() : null, membership: p.membership || null, hasPendingRequest: p.has_pending_request || false, files: p.artifact_count || 0, memberCount: p.member_count || 0, members: (p.members || []).slice(0, 3).map(m => (m.full_name || '?')[0].toUpperCase()), more: Math.max(0, (p.member_count || 0) - 3), updated: p.created_at ? new Date(p.created_at).toLocaleDateString('en-IN', { day: 'numeric', month: 'short' }) : '—', }); const YoursProjectCard = ({ p, onClick, onInvite }) => (
{ e.currentTarget.style.borderColor = 'var(--maroon-20)'; e.currentTarget.style.boxShadow = '0 6px 18px rgba(60,30,20,0.06)'; e.currentTarget.style.transform = 'translateY(-1px)'; }} onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--line)'; e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }} >

{p.name}

{p.role && {p.role}}

{p.desc}

{p.tag}
{p.files} {p.memberCount} · {p.updated}
{p.role === 'OWNER' && onInvite && ( )}
); const DiscoverProjectCard = ({ p, onOpenProject, onJoined }) => { const [requested, setRequested] = React.useState(p.hasPendingRequest || false); const isMember = !!p.membership; const isOwner = p.membership === 'owner'; const handleRequestJoin = async (e) => { e.stopPropagation(); setRequested(true); try { await PrimusAPI.joinProject(p.id); // Leadership auto-joins → refresh so it moves into "Your projects"; others get pending state. if (onJoined) onJoined(); } catch { setRequested(false); } }; return (
e.currentTarget.style.borderColor = isMember ? 'var(--maroon-20)' : 'var(--line-2)'} onMouseLeave={e => e.currentTarget.style.borderColor = 'var(--line)'} onClick={() => isMember && onOpenProject && onOpenProject(p.id)} >

{p.name}

{p.files} files · {p.memberCount} members · {p.updated}
{isMember && {p.role}}

{p.desc}

{p.tag}
{isMember ? 'You have access.' : 'Membership required'} {!isMember && ( )} {isMember && ( )}
); }; const ProjectsListing = ({ setRoute, openCreate, openInvite, projects, onOpenProject, currentUser, onJoined }) => { const [tab, setTab] = React.useState(0); const [q, setQ] = React.useState(''); // Only Management / Leadership may create projects (mirrors backend RBAC). const canCreateProject = currentUser?.tier === 'management' || currentUser?.tier === 'leadership'; // Instant client-side filter — the full list is already loaded, so no network round-trip. const allData = projects ? projects.map(adaptProject) : []; const myData = allData.filter(p => p.membership !== null); const discData = allData; const data = tab === 0 ? myData : discData; const ql = q.trim().toLowerCase(); const filtered = ql ? data.filter(p => (p.name || '').toLowerCase().includes(ql) || (p.desc || '').toLowerCase().includes(ql)) : data; return (

Projects

Workspaces with their own files, instructions and chat history.

{canCreateProject && ( )}
{['Your projects', 'Discover'].map((t, i) => ( ))}
setQ(e.target.value)} placeholder={tab === 0 ? 'Filter your projects' : 'Search all projects in the firm'} />
{tab === 1 && (
Discover surfaces every project across Primus Partners. Request to join, or browse public deliverables.
)}
{filtered.map(p => tab === 0 ? onOpenProject ? onOpenProject(p.id) : setRoute('project-detail')} onInvite={openInvite} /> : )}
{filtered.length === 0 && (
{q ? `No projects match "${q}".` : tab === 0 ? No projects yet. : 'No firm-wide projects found.'}
)}
); }; Object.assign(window, { SAMPLE_PROJECTS, DISCOVER_PROJECTS, adaptProject, YoursProjectCard, DiscoverProjectCard, ProjectsListing, });