// Adobe Sign → DocuSign Migrator — frontend app // Vanilla JS, no build step. const $ = id => document.getElementById(id); let adobeTemplates = []; // [{id, name, modifiedDate}] let dsTemplates = []; // [{id, name, lastModified}] let statusTemplates = []; // [{adobe_id, name, status, docusign_id, ...}] let authState = { adobe: false, docusign: false }; // ── Init ──────────────────────────────────────────────────────────────────── document.addEventListener('DOMContentLoaded', async () => { await refreshAuth(); await refreshTemplates(); await refreshHistory(); $('btn-migrate').addEventListener('click', onMigrate); $('btn-refresh').addEventListener('click', async () => { await refreshTemplates(); await refreshHistory(); }); }); // ── Auth ───────────────────────────────────────────────────────────────────── async function refreshAuth() { const resp = await fetch('/api/auth/status'); authState = await resp.json(); renderAuthBar(); } function renderAuthBar() { renderAuthBadge('badge-adobe', 'Adobe Sign', authState.adobe, '/api/auth/adobe/start', '/api/auth/adobe/disconnect'); renderAuthBadge('badge-docusign', 'DocuSign', authState.docusign, '/api/auth/docusign/start', '/api/auth/docusign/disconnect'); } function renderAuthBadge(id, label, connected, connectUrl, disconnectUrl) { const el = $(id); el.textContent = connected ? `✓ ${label}` : `Connect ${label}`; el.className = 'auth-badge' + (connected ? ' connected' : ''); el.onclick = () => { if (connected) { fetch(disconnectUrl).then(() => { authState[id.replace('badge-','')] = false; renderAuthBar(); refreshTemplates(); }); } else { window.location.href = connectUrl; } }; } // ── Templates ──────────────────────────────────────────────────────────────── async function refreshTemplates() { renderAdobeList([]); renderDsList([]); if (!authState.adobe || !authState.docusign) { setStatus(authState.adobe || authState.docusign ? 'Connect both platforms to see migration status.' : 'Connect Adobe Sign and DocuSign to get started.'); $('btn-migrate').disabled = true; return; } setStatus('Loading templates…'); try { const [statusResp, dsResp] = await Promise.all([ fetch('/api/templates/status'), fetch('/api/templates/docusign'), ]); statusTemplates = (await statusResp.json()).templates || []; dsTemplates = ((await dsResp.json()).templates || []); renderAdobeList(statusTemplates); renderDsList(dsTemplates); setStatus(`${statusTemplates.length} Adobe template(s) loaded.`); } catch (e) { setStatus('Error loading templates: ' + e.message); } } function renderAdobeList(items) { const ul = $('adobe-list'); if (!items.length) { ul.innerHTML = '
  • No templates found.
  • '; return; } ul.innerHTML = items.map(t => `
  • ${escHtml(t.name)} ${statusLabel(t.status)}
  • `).join(''); ul.querySelectorAll('.template-item').forEach(li => { li.addEventListener('click', e => { if (e.target.type === 'checkbox') return; const cb = li.querySelector('input[type=checkbox]'); cb.checked = !cb.checked; li.classList.toggle('selected', cb.checked); updateMigrateButton(); }); li.querySelector('input').addEventListener('change', () => { li.classList.toggle('selected', li.querySelector('input').checked); updateMigrateButton(); }); }); } function renderDsList(items) { const ul = $('ds-list'); if (!items.length) { ul.innerHTML = '
  • No templates found.
  • '; return; } ul.innerHTML = items.map(t => `
  • ${escHtml(t.name)} ${(t.lastModified || '').slice(0, 10)}
  • `).join(''); } function updateMigrateButton() { const checked = document.querySelectorAll('#adobe-list input[type=checkbox]:checked'); $('btn-migrate').disabled = checked.length === 0; } // ── Migration ───────────────────────────────────────────────────────────────── async function onMigrate() { const checked = [...document.querySelectorAll('#adobe-list input[type=checkbox]:checked')]; const ids = checked.map(cb => cb.dataset.id); if (!ids.length) return; $('btn-migrate').disabled = true; setStatus(`Migrating ${ids.length} template(s)…`); // Show spinners ids.forEach(id => { const spin = $('spin-' + id); if (spin) spin.textContent = '⏳'; }); try { const resp = await fetch('/api/migrate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ adobe_template_ids: ids }), }); const data = await resp.json(); let successCount = 0; (data.results || []).forEach(r => { const spin = $('spin-' + r.adobe_template_id); if (r.status === 'success') { successCount++; if (spin) spin.textContent = r.action === 'updated' ? '✏️' : '✅'; } else { if (spin) spin.textContent = '❌'; } }); setStatus(`Done: ${successCount}/${ids.length} succeeded.`); await refreshTemplates(); await refreshHistory(); } catch (e) { setStatus('Migration error: ' + e.message); } } // ── History ─────────────────────────────────────────────────────────────────── async function refreshHistory() { try { const resp = await fetch('/api/migrate/history'); const { history } = await resp.json(); renderHistory(history || []); } catch { renderHistory([]); } } function renderHistory(records) { const tbody = $('history-tbody'); if (!records.length) { tbody.innerHTML = 'No migrations yet.'; return; } tbody.innerHTML = [...records].reverse().slice(0, 50).map(r => ` ${(r.timestamp || '').replace('T', ' ').slice(0, 19)} ${escHtml(r.adobe_template_name || r.adobe_template_id || '')} ${escHtml(r.docusign_template_id || '—')} ${escHtml(r.action || '—')} ${r.status} `).join(''); } // ── Utilities ───────────────────────────────────────────────────────────────── function setStatus(msg) { $('status-msg').textContent = msg; } function statusLabel(s) { return { not_migrated: 'Not Migrated', migrated: 'Migrated', needs_update: 'Needs Update' }[s] || s; } function escHtml(str) { return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); }