// Auth: connect/disconnect Adobe Sign and Docusign, auth status chips import { api } from './api.js'; import { state, setState } from './state.js'; import { escHtml } from './utils.js'; // ── Refresh auth state and update chips ──────────────────────────────────── export async function refreshAuth() { try { const data = await api.auth.status(); setState('auth', { adobe: !!data.adobe, docusign: !!data.docusign, adobeLabel: data.adobe_label || 'Adobe Sign', docusignLabel: data.docusign_label || 'Docusign', }); } catch (e) { console.warn('Auth status failed:', e.message); } renderAuthChips(); } // ── Render connection pills in top bar ───────────────────────────────────── export function renderAuthChips() { renderChip('chip-adobe', state.auth.adobe, 'Adobe Sign', onClickAdobe); renderChip('chip-docusign', state.auth.docusign, 'Docusign', onClickDocusign); } function renderChip(id, connected, label, onClick) { const el = document.getElementById(id); if (!el) return; el.className = 'conn-pill ' + (connected ? 'connected' : 'disconnected'); el.innerHTML = `${escHtml(label)}`; el.onclick = onClick; } // ── Click handlers ───────────────────────────────────────────────────────── async function onClickAdobe() { if (state.auth.adobe) { await disconnect('adobe'); } else { await connectAdobeEnv(); } } async function onClickDocusign() { if (state.auth.docusign) { await disconnect('docusign'); } else { await connectDocusign(); } } async function disconnect(platform) { setChipConnecting(platform === 'adobe' ? 'chip-adobe' : 'chip-docusign'); try { await api.auth.disconnect(platform); setState('auth', { ...state.auth, [platform]: false }); renderAuthChips(); // Reload templates (they'll be empty without auth) const { refreshTemplates } = await import('./templates.js'); refreshTemplates(); } catch (e) { console.error('Disconnect failed:', e.message); renderAuthChips(); } } async function connectAdobeEnv() { setChipConnecting('chip-adobe'); try { const data = await api.auth.connectAdobe(); if (data.connected) { setState('auth', { ...state.auth, adobe: true }); renderAuthChips(); const { refreshTemplates } = await import('./templates.js'); refreshTemplates(); } else if (data.error && data.error.includes('No Adobe Sign credentials')) { renderAuthChips(); showAdobeOAuthDialog(); } else { renderAuthChips(); showToast('Adobe Sign error: ' + (data.error || 'unknown'), 'error'); } } catch (e) { renderAuthChips(); showAdobeOAuthDialog(); } } async function connectDocusign() { setChipConnecting('chip-docusign'); try { const data = await api.auth.connectDocusign(); if (data.connected) { setState('auth', { ...state.auth, docusign: true }); renderAuthChips(); const { refreshTemplates } = await import('./templates.js'); refreshTemplates(); } else if (data.authorization_required && data.authorization_url) { window.location.href = data.authorization_url; } else { renderAuthChips(); showToast('Docusign error: ' + (data.error || 'unknown'), 'error'); } } catch (e) { renderAuthChips(); showToast('Docusign connection failed: ' + e.message, 'error'); } } function setChipConnecting(id) { const el = document.getElementById(id); if (!el) return; el.className = 'conn-pill connecting'; el.innerHTML = ``; } // ── Adobe OAuth dialog (manual redirect URL paste) ───────────────────────── async function showAdobeOAuthDialog() { const { url } = await api.auth.adobeUrl().catch(() => ({ url: '#' })); const existing = document.getElementById('adobe-auth-dialog'); if (existing) existing.remove(); const dialog = document.createElement('div'); dialog.id = 'adobe-auth-dialog'; dialog.innerHTML = ` `; document.body.appendChild(dialog); document.getElementById('adobe-dialog-close').onclick = () => dialog.remove(); document.getElementById('adobe-dialog-cancel').onclick = () => dialog.remove(); document.getElementById('adobe-dialog-submit').onclick = () => submitAdobeCode(dialog); document.getElementById('adobe-redirect-input').addEventListener('keydown', e => { if (e.key === 'Enter') submitAdobeCode(dialog); }); } async function submitAdobeCode(dialog) { const url = document.getElementById('adobe-redirect-input').value.trim(); if (!url) return; const submitBtn = document.getElementById('adobe-dialog-submit'); const errorEl = document.getElementById('adobe-dialog-error'); submitBtn.disabled = true; submitBtn.textContent = 'Connecting…'; errorEl.textContent = ''; try { const data = await api.auth.exchangeAdobe(url); dialog.remove(); setState('auth', { ...state.auth, adobe: true }); renderAuthChips(); const { refreshTemplates } = await import('./templates.js'); refreshTemplates(); } catch (e) { errorEl.textContent = e.data?.error || e.message || 'Connection failed.'; submitBtn.disabled = false; submitBtn.textContent = 'Connect'; } } // ── Toast notification ───────────────────────────────────────────────────── export function showToast(message, type = 'info') { let container = document.getElementById('toast-container'); if (!container) { container = document.createElement('div'); container.id = 'toast-container'; container.style.cssText = 'position:fixed;bottom:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:8px;'; document.body.appendChild(container); } const toast = document.createElement('div'); const colors = { info: 'var(--cobalt-light)', error: 'var(--error-bg)', success: 'var(--success-bg)' }; const borders = { info: 'var(--cobalt)', error: 'var(--error)', success: 'var(--success)' }; toast.style.cssText = ` padding:10px 16px;border-radius:6px;font-size:13px;font-weight:500; background:${colors[type]||colors.info};border:1px solid ${borders[type]||borders.info}; box-shadow:var(--shadow-md);max-width:360px;animation:fadeIn 0.2s ease; `; toast.textContent = message; container.appendChild(toast); setTimeout(() => toast.remove(), 4000); }