-
+
-
-
+
+
+
+
+
+
+ Discount will be applied:
+
+
+
+
+
+
+
+
+ Loading products...
+
+
+
+
+
Payment Link Generated!
+
+ Copy this link and send it to the prospect:
+
+
+
+
+
+
+
+
+
+
-
+
-
@@ -1214,6 +1378,10 @@
Member Context
renderAccount();
document.getElementById('loading').style.display = 'none';
document.getElementById('content').style.display = 'block';
+
+ // Load additional data asynchronously
+ loadAddieResearch();
+ loadMemberInsights();
} catch (error) {
console.error('Error loading account:', error);
document.getElementById('loading').textContent = 'Error loading account';
@@ -1376,17 +1544,7 @@
Member Context
// Domains
if (a.domains && a.domains.length > 0) {
- let domainsHtml = '';
- for (const d of a.domains) {
- domainsHtml += `
-
${escapeHtml(d.domain)}
-
- ${d.is_primary ? 'Primary' : ''}
- ${d.verified ? 'Verified' : ''}
-
-
`;
- }
- document.getElementById('domainsList').innerHTML = domainsHtml;
+ renderDomains(a.domains);
}
// Domain Health
@@ -1950,7 +2108,7 @@
org.workos_organization_id !== accountId)
+ .sort((a, b) => (a.name || '').localeCompare(b.name || ''))
+ .forEach(org => {
+ const option = document.createElement('option');
+ option.value = org.workos_organization_id;
+ option.textContent = org.name;
+ if (org.workos_organization_id === accountData.parent_organization_id) {
+ option.selected = true;
+ }
+ select.appendChild(option);
+ });
+ } catch (error) {
+ console.error('Error loading parent org options:', error);
+ }
+ }
+
function toggleDisqualifyReason() {
document.getElementById('disqualifyReasonGroup').style.display =
document.getElementById('editDisqualified').checked ? 'block' : 'none';
@@ -1972,6 +2165,7 @@ No domains linked
';
+ return;
+ }
+
+ container.innerHTML = `
+ ${domains.map(d => {
+ const escapedDomain = escapeHtml(d.domain);
+ const badges = [];
+ if (d.is_primary) badges.push('Primary');
+ if (d.verified) badges.push('Verified');
+ badges.push(`${d.source === 'workos' ? 'WorkOS' : 'Manual'}`);
+
+ return `
+ -
+
+ ${escapedDomain}
+ ${badges.join(' ')}
+
+
+ ${!d.verified ? `` : ''}
+ ${!d.is_primary ? `` : ''}
+
+
+
+ `;
+ }).join('')}
+
`;
+
+ // Remove last border
+ const lastItem = container.querySelector('li:last-child');
+ if (lastItem) {
+ lastItem.style.borderBottom = 'none';
+ }
+
+ // Event delegation for domain actions
+ container.onclick = handleDomainAction;
+ }
+
+ function handleDomainAction(e) {
+ const btn = e.target.closest('[data-action]');
+ if (!btn) return;
+
+ const domainItem = btn.closest('[data-domain]');
+ if (!domainItem) return;
+
+ const domain = domainItem.dataset.domain;
+ const action = btn.dataset.action;
+
+ if (action === 'verify') {
+ verifyDomain(domain, btn);
+ } else if (action === 'set-primary') {
+ setDomainPrimary(domain, btn);
+ } else if (action === 'remove') {
+ removeDomain(domain, btn);
+ }
+ }
+
+ async function verifyDomain(domain, btn) {
+ const originalText = btn ? btn.textContent : '';
+ if (btn) {
+ btn.disabled = true;
+ btn.textContent = 'Verifying...';
+ }
+
+ try {
+ const response = await fetch(`/api/admin/organizations/${accountId}/domains`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ domain: domain.toLowerCase() })
+ });
+
+ if (!response.ok) {
+ if (response.status === 401) {
+ window.AdminNav?.redirectToLogin?.();
+ return;
+ }
+ const data = await response.json().catch(() => ({}));
+ throw new Error(data.error || 'Failed to verify domain');
+ }
+
+ location.reload();
+ } catch (error) {
+ console.error('Error verifying domain:', error);
+ alert('Error: ' + error.message);
+ if (btn) {
+ btn.disabled = false;
+ btn.textContent = originalText;
+ }
+ }
+ }
+
+ async function setDomainPrimary(domain, btn) {
+ const originalText = btn ? btn.textContent : '';
+ if (btn) {
+ btn.disabled = true;
+ btn.textContent = 'Setting...';
+ }
+
+ try {
+ const response = await fetch(`/api/admin/organizations/${accountId}/domains/${encodeURIComponent(domain)}/primary`, {
+ method: 'PUT'
+ });
+
+ if (!response.ok) {
+ if (response.status === 401) {
+ window.AdminNav?.redirectToLogin?.();
+ return;
+ }
+ const data = await response.json().catch(() => ({}));
+ throw new Error(data.error || 'Failed to set primary domain');
+ }
+
+ location.reload();
+ } catch (error) {
+ console.error('Error setting primary domain:', error);
+ alert('Error: ' + error.message);
+ if (btn) {
+ btn.disabled = false;
+ btn.textContent = originalText;
+ }
+ }
+ }
+
+ async function removeDomain(domain, btn) {
+ if (!confirm(`Remove domain "${escapeHtml(domain)}" from this organization?`)) return;
+
+ if (btn) {
+ btn.disabled = true;
+ }
+
+ try {
+ const response = await fetch(`/api/admin/organizations/${accountId}/domains/${encodeURIComponent(domain)}`, {
+ method: 'DELETE'
+ });
+
+ if (!response.ok) {
+ if (response.status === 401) {
+ window.AdminNav?.redirectToLogin?.();
+ return;
+ }
+ const data = await response.json().catch(() => ({}));
+ throw new Error(data.error || 'Failed to remove domain');
+ }
+
+ location.reload();
+ } catch (error) {
+ console.error('Error removing domain:', error);
+ alert('Error: ' + error.message);
+ if (btn) {
+ btn.disabled = false;
+ }
+ }
+ }
+
// Enrichment refresh
async function refreshEnrichment() {
try {
@@ -2032,16 +2386,479 @@
+
+ ${date.toLocaleDateString()} ${date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}
+ ${interaction.user_name ? ` • Conversation with ${escapeHtml(interaction.user_name)}` : ''}
+
+
+ ${escapeHtml(interaction.summary || interaction.output_text?.substring(0, 200) || 'No summary')}
+ ${interaction.output_text?.length > 200 ? '...' : ''}
+
+ ${interaction.tools_used?.length > 0 ? `
+
+ Tools: ${interaction.tools_used.join(', ')}
+
+ ` : ''}
+
+ `;
+ }).join('');
+
+ // Remove last border
+ const lastItem = container.querySelector('.research-item:last-child');
+ if (lastItem) {
+ lastItem.style.borderBottom = 'none';
+ }
+
+ } catch (error) {
+ console.error('Error loading Addie research:', error);
+ card.style.display = 'none';
+ }
+ }
+
+ // =========================================================================
+ // Member Insights
+ // =========================================================================
+
+ async function loadMemberInsights() {
+ const card = document.getElementById('memberInsightsCard');
+ const container = document.getElementById('memberInsightsList');
+
+ try {
+ const response = await fetch(`/api/admin/organizations/${accountId}/member-insights`);
+
+ if (!response.ok) {
+ if (response.status === 404) {
+ card.style.display = 'none';
+ return;
+ }
+ throw new Error('Failed to load member insights');
+ }
+
+ const data = await response.json();
+
+ if (!data.insights || data.insights.length === 0) {
+ card.style.display = 'none';
+ return;
+ }
+
+ card.style.display = 'block';
+
+ // Group insights by member
+ const byMember = {};
+ data.insights.forEach(insight => {
+ const key = insight.member_name || insight.slack_user_id || 'Unknown';
+ if (!byMember[key]) {
+ byMember[key] = [];
+ }
+ byMember[key].push(insight);
+ });
+
+ container.innerHTML = Object.entries(byMember).map(([member, insights]) => `
+
+
${escapeHtml(member)}
+ ${insights.map(insight => `
+
+
+ ${escapeHtml(insight.insight_type)}
+
+ ${escapeHtml(insight.value)}
+ ${insight.confidence ? `
+
+ (${insight.confidence})
+
+ ` : ''}
+
+ `).join('')}
+
+ `).join('');
+
+ } catch (error) {
+ console.error('Error loading member insights:', error);
+ card.style.display = 'none';
+ }
+ }
+
+ // =========================================================================
+ // Payment Link Functions
+ // =========================================================================
+
function openPaymentLinkModal() {
- // Redirect to old page for now
- window.location.href = `/admin/organizations/${accountId}`;
+ document.getElementById('paymentLinkOrgName').textContent = `For: ${accountData?.name || 'Unknown'}`;
+ document.getElementById('paymentLinkProducts').innerHTML = 'Loading products...';
+ document.getElementById('paymentLinkProducts').style.display = 'block';
+ document.getElementById('paymentLinkResult').style.display = 'none';
+
+ // Show discount notice if org has a discount
+ const discountNotice = document.getElementById('paymentLinkDiscountNotice');
+ if (accountData.discount_percent || accountData.discount_amount_cents) {
+ discountNotice.style.display = 'block';
+ let discountText = '';
+ if (accountData.discount_percent) {
+ discountText = `${accountData.discount_percent}% off`;
+ } else {
+ discountText = `$${(accountData.discount_amount_cents / 100).toFixed(0)} off`;
+ }
+ if (accountData.stripe_promotion_code) {
+ discountText += ` (code: ${accountData.stripe_promotion_code})`;
+ }
+ document.getElementById('paymentLinkDiscountText').textContent = discountText;
+ document.getElementById('applyDiscountToPaymentLink').checked = true;
+ } else {
+ discountNotice.style.display = 'none';
+ }
+
+ openModal('paymentLinkModal');
+ loadPaymentLinkProducts();
}
- // Invoice (placeholder)
+ async function loadPaymentLinkProducts() {
+ try {
+ const response = await fetch(`/api/admin/prospects/${accountId}/payment-link`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({})
+ });
+
+ if (!response.ok) {
+ throw new Error('Failed to load products');
+ }
+
+ const data = await response.json();
+
+ if (data.needs_selection && data.products) {
+ paymentLinkProductsData = data.products;
+ renderPaymentLinkProducts(data.products);
+ }
+ } catch (error) {
+ console.error('Error loading products:', error);
+ document.getElementById('paymentLinkProducts').innerHTML =
+ '
Failed to load products. Please try again.
';
+ }
+ }
+
+ let paymentLinkProductsData = [];
+
+ function renderPaymentLinkProducts(products) {
+ const container = document.getElementById('paymentLinkProducts');
+
+ if (products.length === 0) {
+ container.innerHTML = '
No products available for this account type.
';
+ return;
+ }
+
+ container.innerHTML = products.map((product, index) => {
+ const price = new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD'
+ }).format(product.amount_cents / 100);
+
+ const displayName = escapeHtml(product.display_name);
+ const tiers = product.revenue_tiers?.length > 0
+ ? `
(${product.revenue_tiers.map(t => escapeHtml(t)).join(', ')})`
+ : '';
+
+ return `
+
+ `;
+ }).join('');
+
+ // Event delegation for product selection
+ container.onclick = function(e) {
+ const btn = e.target.closest('[data-product-index]');
+ if (!btn) return;
+ const index = parseInt(btn.dataset.productIndex, 10);
+ const product = paymentLinkProductsData[index];
+ if (product) {
+ generatePaymentLink(product.lookup_key);
+ }
+ };
+ }
+
+ async function generatePaymentLink(lookupKey) {
+ const container = document.getElementById('paymentLinkProducts');
+ container.innerHTML = '
Generating payment link...
';
+
+ try {
+ const applyDiscount = document.getElementById('applyDiscountToPaymentLink')?.checked;
+ const body = { lookup_key: lookupKey };
+
+ if (applyDiscount && accountData.stripe_coupon_id) {
+ body.coupon_id = accountData.stripe_coupon_id;
+ } else if (applyDiscount && accountData.stripe_promotion_code) {
+ body.promotion_code = accountData.stripe_promotion_code;
+ }
+
+ const response = await fetch(`/api/admin/prospects/${accountId}/payment-link`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body)
+ });
+
+ const data = await response.json();
+
+ if (!response.ok) {
+ throw new Error(data.message || data.error || 'Failed to generate payment link');
+ }
+
+ if (data.success && data.payment_url) {
+ container.style.display = 'none';
+ document.getElementById('paymentLinkDiscountNotice').style.display = 'none';
+ document.getElementById('paymentLinkUrl').value = data.payment_url;
+ document.getElementById('paymentLinkResult').style.display = 'block';
+ } else {
+ throw new Error(data.message || 'Unknown error');
+ }
+ } catch (error) {
+ console.error('Error generating payment link:', error);
+ container.innerHTML = `
Error: ${escapeHtml(error.message)}
`;
+ }
+ }
+
+ function copyPaymentLink() {
+ const input = document.getElementById('paymentLinkUrl');
+ input.select();
+ navigator.clipboard.writeText(input.value).then(() => {
+ showToast('Payment link copied to clipboard!');
+ }).catch(() => {
+ document.execCommand('copy');
+ showToast('Payment link copied to clipboard!');
+ });
+ }
+
+ // =========================================================================
+ // Invoice Functions
+ // =========================================================================
+
+ let selectedInvoiceProduct = null;
+ let invoiceProductsData = [];
+
function openInvoiceModal() {
- // Redirect to old page for now
- window.location.href = `/admin/organizations/${accountId}`;
+ selectedInvoiceProduct = null;
+
+ document.getElementById('invoiceOrgName').textContent = `For: ${accountData?.name || 'Unknown'}`;
+ document.getElementById('invoiceProducts').innerHTML = 'Loading products...';
+ document.getElementById('invoiceProductSection').style.display = 'block';
+ document.getElementById('invoiceBillingSection').style.display = 'none';
+ document.getElementById('invoiceResult').style.display = 'none';
+ document.getElementById('sendInvoiceBtn').style.display = 'none';
+ document.getElementById('invoiceForm').reset();
+
+ // Pre-fill from account data
+ if (accountData) {
+ document.getElementById('invoiceContactName').value = accountData.prospect_contact_name || '';
+ document.getElementById('invoiceContactEmail').value = accountData.prospect_contact_email || '';
+ document.getElementById('invoiceCompanyName').value = accountData.name || '';
+ }
+
+ openModal('invoiceModal');
+ loadInvoiceProducts();
+ }
+
+ async function loadInvoiceProducts() {
+ try {
+ const response = await fetch('/api/admin/products');
+ if (!response.ok) throw new Error('Failed to load products');
+
+ const data = await response.json();
+ invoiceProductsData = data.products.filter(p => p.is_invoiceable);
+
+ renderInvoiceProducts(invoiceProductsData);
+ } catch (error) {
+ console.error('Error loading products:', error);
+ document.getElementById('invoiceProducts').innerHTML =
+ '
Failed to load products. Please try again.
';
+ }
+ }
+
+ function renderInvoiceProducts(products) {
+ const container = document.getElementById('invoiceProducts');
+
+ if (products.length === 0) {
+ container.innerHTML = '
No invoiceable products available.
';
+ return;
+ }
+
+ container.innerHTML = products.map((product, index) => {
+ const price = new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD'
+ }).format(product.amount_cents / 100);
+
+ const interval = product.billing_interval ? `/${product.billing_interval}` : '';
+ const displayName = escapeHtml(product.display_name || product.product_name);
+ const description = product.description ? escapeHtml(product.description) : '';
+
+ return `
+
+ `;
+ }).join('');
+
+ // Event delegation for product selection
+ container.onclick = function(e) {
+ const btn = e.target.closest('[data-product-index]');
+ if (!btn) return;
+ const index = parseInt(btn.dataset.productIndex, 10);
+ const product = invoiceProductsData[index];
+ if (product) {
+ selectInvoiceProduct(product);
+ }
+ };
+ }
+
+ function selectInvoiceProduct(product) {
+ const displayName = product.display_name || product.product_name;
+ selectedInvoiceProduct = {
+ lookupKey: product.lookup_key,
+ productName: displayName,
+ amountCents: product.amount_cents
+ };
+
+ const price = new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD'
+ }).format(product.amount_cents / 100);
+
+ document.getElementById('selectedProductDisplay').innerHTML = `
+
${escapeHtml(displayName)} -
${price}
+ `;
+
+ document.getElementById('invoiceProductSection').style.display = 'none';
+ document.getElementById('invoiceBillingSection').style.display = 'block';
+ document.getElementById('sendInvoiceBtn').style.display = 'inline-block';
+ }
+
+ async function submitInvoice(event) {
+ event.preventDefault();
+
+ if (!selectedInvoiceProduct) {
+ alert('Please select a product first');
+ return;
+ }
+
+ const btn = document.getElementById('sendInvoiceBtn');
+ btn.disabled = true;
+ btn.textContent = 'Sending...';
+
+ const data = {
+ lookup_key: selectedInvoiceProduct.lookupKey,
+ company_name: document.getElementById('invoiceCompanyName').value,
+ contact_name: document.getElementById('invoiceContactName').value,
+ contact_email: document.getElementById('invoiceContactEmail').value,
+ billing_address: {
+ line1: document.getElementById('invoiceAddressLine1').value,
+ line2: document.getElementById('invoiceAddressLine2').value || undefined,
+ city: document.getElementById('invoiceCity').value,
+ state: document.getElementById('invoiceState').value,
+ postal_code: document.getElementById('invoicePostalCode').value,
+ country: document.getElementById('invoiceCountry').value,
+ }
+ };
+
+ try {
+ const response = await fetch(`/api/admin/prospects/${accountId}/invoice`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ });
+
+ if (!response.ok) {
+ const error = await response.json();
+ throw new Error(error.error || error.message || 'Failed to send invoice');
+ }
+
+ const result = await response.json();
+
+ if (result.success && result.invoice_url) {
+ document.getElementById('invoiceBillingSection').style.display = 'none';
+ document.getElementById('sendInvoiceBtn').style.display = 'none';
+ document.getElementById('invoiceUrl').value = result.invoice_url;
+ document.getElementById('invoiceResult').style.display = 'block';
+
+ // Refresh page to show the new pending invoice
+ setTimeout(() => location.reload(), 2000);
+ } else {
+ throw new Error(result.message || 'Unknown error');
+ }
+ } catch (error) {
+ console.error('Error sending invoice:', error);
+ alert('Error: ' + error.message);
+ } finally {
+ btn.disabled = false;
+ btn.textContent = 'Send Invoice';
+ }
+ }
+
+ function copyInvoiceLink() {
+ const input = document.getElementById('invoiceUrl');
+ input.select();
+ navigator.clipboard.writeText(input.value).then(() => {
+ showToast('Invoice link copied to clipboard!');
+ }).catch(() => {
+ document.execCommand('copy');
+ showToast('Invoice link copied to clipboard!');
+ });
}
// AI Enrichment