+ list.innerHTML = '
No organizations added yet. Use "+ Add Org" to add parties to this deal.
';
+ return;
+ }
+ list.innerHTML = orgs.map(o => {
+ const rc = roleColors[o.role] || 'bg-gray-500/20 text-gray-300';
+ const roleLabel = { buyer: 'Buyer', seller: 'Seller', ib: 'IB Advisor', advisor: 'Advisor' }[o.role] || o.role || '?';
+ const perms = o.permissions || {};
+ const members = o.members || [];
+ const dlBadge = { full: '📥 Full download', watermark: '📥 Watermarked', none: '🚫 No download' }[perms.download] || '📥 Watermarked';
+ return `
+
+
- ${escHtml(d.org_name || d.name || 'Unknown')}
- ${d.role || '?'}
+ ${escHtml(o.org_name || 'Unknown')}
+ ${roleLabel}
+
+
+ ${dlBadge}
+ ${perms.upload ? '📤 Upload' : ''}
+ ${perms.add_request_lists ? '➕ Add lists' : ''}
+ ${perms.edit_request_lists ? '✏️ Edit lists' : ''}
+ ${perms.folder_access === 'all' ? '📂 All folders' : '📂 Assigned only'}
- ${d.domains ? `
${(Array.isArray(d.domains)?d.domains:[d.domains]).map(dm=>`@${dm}`).join('')}
` : ''}
+
+
+ ${members.length > 0 ? `
+
+ ${members.map(m => `
+
${(m.name||m.email||'?')[0].toUpperCase()}
+
+
${escHtml(m.name||m.email)}
+ ${m.title ? `
${escHtml(m.title)}
` : ''}
+
+
`).join('')}
+
+
` : ''}
+
`;
+ }).join('');
+ } catch(e) { console.error(e); }
+ }
+
+ // ---- Add Org Modal ----
+ let orgSearchTimeout;
+ let memberCount = 0;
+
+ function openAddOrgModal() {
+ document.getElementById('addOrgModal').classList.remove('hidden');
+ document.getElementById('addOrgError').classList.add('hidden');
+ document.getElementById('addOrgName').value = '';
+ document.getElementById('addOrgId').value = '';
+ document.getElementById('memberRows').innerHTML = '';
+ memberCount = 0;
+ setOrgType('buyer', document.querySelector('[data-type="buyer"]'));
+ addMemberRow();
+ loadGlobalOrgs();
+ }
+
+ function closeAddOrgModal() {
+ document.getElementById('addOrgModal').classList.add('hidden');
+ document.getElementById('orgNameDropdown').classList.add('hidden');
+ }
+
+ async function loadGlobalOrgs() {
+ if (allGlobalOrgs.length) return;
+ try {
+ const res = await fetchAPI('/api/orgs');
+ allGlobalOrgs = await res.json() || [];
+ } catch(e) { allGlobalOrgs = []; }
+ }
+
+ function setOrgType(type, btn) {
+ document.querySelectorAll('.org-type-btn').forEach(b => {
+ b.classList.remove('border-[#c9a84c]', 'text-[#c9a84c]', 'bg-[#c9a84c]/10');
+ b.classList.add('border-white/[0.08]', 'text-[#94a3b8]');
+ });
+ if (btn) {
+ btn.classList.add('border-[#c9a84c]', 'text-[#c9a84c]', 'bg-[#c9a84c]/10');
+ btn.classList.remove('border-white/[0.08]', 'text-[#94a3b8]');
+ }
+ document.getElementById('addOrgType').value = type;
+ }
+
+ function orgNameSearch(q) {
+ clearTimeout(orgSearchTimeout);
+ const dd = document.getElementById('orgNameDropdown');
+ const orgId = document.getElementById('addOrgId');
+ orgId.value = '';
+ if (!q) { dd.classList.add('hidden'); return; }
+ orgSearchTimeout = setTimeout(() => {
+ const matches = allGlobalOrgs.filter(o => {
+ const d = parseData(o.data_text);
+ return (d.name || '').toLowerCase().includes(q.toLowerCase());
+ });
+ if (!matches.length) {
+ dd.innerHTML = `
No match — will create "${escHtml(q)}" as new org
`;
+ } else {
+ dd.innerHTML = matches.map(o => {
+ const d = parseData(o.data_text);
+ const name = d.name || 'Unnamed';
+ return `
+ ${escHtml(name)}
+ ${d.role || ''}
`;
}).join('');
}
- loadTeam();
- } catch(e) {}
+ dd.classList.remove('hidden');
+ }, 200);
}
- async function loadTeam() {
+ function selectOrg(orgId, orgName, role, el) {
+ document.getElementById('addOrgId').value = orgId;
+ document.getElementById('addOrgName').value = orgName;
+ if (role) setOrgType(role, document.querySelector(`[data-type="${role}"]`));
+ document.getElementById('orgNameDropdown').classList.add('hidden');
+ }
+
+ function addMemberRow() {
+ const idx = memberCount++;
+ const row = document.createElement('div');
+ row.className = 'grid grid-cols-[1fr_1fr_1fr_auto] gap-2 items-center';
+ row.id = 'member-row-' + idx;
+ row.innerHTML = `
+
+
+
+
`;
+ document.getElementById('memberRows').appendChild(row);
+ }
+
+ async function submitAddOrg() {
+ const name = document.getElementById('addOrgName').value.trim();
+ const existingOrgId = document.getElementById('addOrgId').value;
+ const role = document.getElementById('addOrgType').value;
+ const errEl = document.getElementById('addOrgError');
+ const btn = document.getElementById('addOrgSubmitBtn');
+ if (!name) { errEl.textContent = 'Organization name is required'; errEl.classList.remove('hidden'); return; }
+
+ // Collect members
+ const members = [];
+ document.querySelectorAll('#memberRows > div').forEach(row => {
+ const idx = row.id.replace('member-row-', '');
+ const n = document.getElementById('mname-' + idx)?.value.trim();
+ const e = document.getElementById('memail-' + idx)?.value.trim();
+ const t = document.getElementById('mtitle-' + idx)?.value.trim();
+ if (n || e) members.push({ name: n || '', email: e || '', title: t || '' });
+ });
+
+ const perms = {
+ download: document.getElementById('permDownload').value,
+ upload: document.getElementById('permUpload').checked,
+ add_request_lists: document.getElementById('permAddLists').checked,
+ edit_request_lists: document.getElementById('permEditLists').checked,
+ folder_access: document.getElementById('permFolderAccess').value,
+ };
+
+ btn.disabled = true; btn.textContent = 'Adding...'; errEl.classList.add('hidden');
+
try {
- const res = await fetchAPI('/api/projects/' + projectID + '/members');
- const members = await res.json();
- const section = document.getElementById('teamMembersSection');
- if (!section) return;
- if (!members || members.length === 0) {
- section.innerHTML = `
-
Team Members
-
No team members yet.
-
`;
- return;
+ let orgId = existingOrgId;
+ if (!orgId) {
+ // Create new global org first
+ const createRes = await fetchAPI('/api/orgs', { method: 'POST', body: JSON.stringify({ name, domains: [], role, website: '' }) });
+ if (!createRes.ok) { const e = await createRes.json(); throw new Error(e.error || 'Failed to create org'); }
+ const created = await createRes.json();
+ orgId = created.entry_id || created.org_id;
}
- section.innerHTML = `
-
Team Members
-
${members.map(m => `
-
-
${(m.name||m.email||'?')[0].toUpperCase()}
-
-
${escHtml(m.name || m.email)}
- ${m.name ? `
${escHtml(m.email)}
` : ''}
-
-
${m.role || 'member'}
-
`).join('')}
-
-
`;
- } catch(e) {}
+ // Add to deal
+ const addRes = await fetchAPI('/api/projects/' + projectID + '/orgs', {
+ method: 'POST', body: JSON.stringify({ org_id: orgId, role, domain_lock: false })
+ });
+ if (!addRes.ok) { const e = await addRes.json(); throw new Error(e.error || 'Failed to add org to deal'); }
+ const added = await addRes.json();
+
+ // Update with permissions + members
+ if (added.deal_org_id) {
+ await fetchAPI('/api/projects/' + projectID + '/entries/' + added.deal_org_id, {
+ method: 'PUT',
+ body: JSON.stringify({
+ project_id: projectID, parent_id: projectID, type: 'deal_org', depth: 1,
+ data: JSON.stringify({ org_id: orgId, role, domain_lock: false, permissions: perms, members }),
+ version: 1
+ })
+ });
+ }
+
+ closeAddOrgModal();
+ loadOrgs();
+ } catch(e) {
+ errEl.textContent = e.message;
+ errEl.classList.remove('hidden');
+ } finally {
+ btn.disabled = false; btn.textContent = 'Add to Deal';
+ }
+ }
+
+ // ---- Permissions Modal ----
+ function openPermModal(dealOrgId, orgId, role, version, permsJson) {
+ let perms = {};
+ try { perms = JSON.parse(permsJson) || {}; } catch(e) {}
+ document.getElementById('permModalDealOrgId').value = dealOrgId;
+ document.getElementById('permModalOrgId').value = orgId;
+ document.getElementById('permModalRole').value = role;
+ document.getElementById('permModalVersion').value = version;
+ const roleLabel = { buyer: 'Buyer', seller: 'Seller', ib: 'IB Advisor', advisor: 'Advisor' }[role] || role;
+ document.getElementById('permModalTitle').textContent = 'Permissions — ' + roleLabel;
+ document.getElementById('pmDownload').value = perms.download || 'watermark';
+ document.getElementById('pmUpload').checked = !!perms.upload;
+ document.getElementById('pmAddLists').checked = !!perms.add_request_lists;
+ document.getElementById('pmEditLists').checked = !!perms.edit_request_lists;
+ document.getElementById('pmFolderAccess').value = perms.folder_access || 'assigned';
+ document.getElementById('permModal').classList.remove('hidden');
+ }
+
+ function closePermModal() { document.getElementById('permModal').classList.add('hidden'); }
+
+ async function savePermissions() {
+ const dealOrgId = document.getElementById('permModalDealOrgId').value;
+ const orgId = document.getElementById('permModalOrgId').value;
+ const role = document.getElementById('permModalRole').value;
+ const version = parseInt(document.getElementById('permModalVersion').value) || 1;
+ const perms = {
+ download: document.getElementById('pmDownload').value,
+ upload: document.getElementById('pmUpload').checked,
+ add_request_lists: document.getElementById('pmAddLists').checked,
+ edit_request_lists: document.getElementById('pmEditLists').checked,
+ folder_access: document.getElementById('pmFolderAccess').value,
+ };
+ try {
+ await fetchAPI('/api/projects/' + projectID + '/entries/' + dealOrgId, {
+ method: 'PUT',
+ body: JSON.stringify({
+ project_id: projectID, parent_id: projectID, type: 'deal_org', depth: 1,
+ data: JSON.stringify({ org_id: orgId, role, domain_lock: false, permissions: perms }),
+ version
+ })
+ });
+ closePermModal();
+ loadOrgs();
+ } catch(e) { alert('Failed to save permissions'); }
+ }
+
+ function openPermissionsTemplateModal() {
+ alert('Coming soon: set default permissions templates per org type for all deals.');
}
function switchTab(name, el) {