// Founder Desk client — builds the weekly pack and manages the API key. (function () { 'use strict'; var $ = function (id) { return document.getElementById(id); }; function esc(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); } function gate(msg) { $('dGate').style.display = 'block'; $('dGate').innerHTML = msg; } function copyBtn(getText) { var b = document.createElement('button'); b.className = 'btn btn-secondary btn-sm d-copy'; b.textContent = 'Copy'; b.addEventListener('click', function () { if (navigator.clipboard) navigator.clipboard.writeText(getText()); b.textContent = 'Copied'; setTimeout(function () { b.textContent = 'Copy'; }, 1400); }); return b; } function item(tag, subject, body) { var d = document.createElement('div'); d.className = 'd-item'; var html = '
' + esc(tag) + '
'; if (subject) html += '
' + esc(subject) + '
'; html += '
' + esc(body) + '
'; d.innerHTML = html; d.appendChild(copyBtn(function () { return (subject ? subject + '\n\n' : '') + body; })); return d; } function section(title, why) { var s = document.createElement('div'); s.className = 'd-sec'; s.innerHTML = '

' + esc(title) + '

' + esc(why) + '
'; return s; } function renderPack(pack) { var host = $('dPack'); host.innerHTML = ''; if (!pack) return; if ((pack.posts || []).length) { var s1 = section('Social posts — one per angle', 'Post one a day. They deliberately take different angles so the week does not read as the same message five times.'); pack.posts.forEach(function (p) { s1.appendChild(item(p.angle, '', p.text)); }); host.appendChild(s1); } if ((pack.messages || []).length) { var s2 = section('Outreach messages', 'For the conversations that actually build the team — a first approach, a follow-up for someone gone quiet, and the pyramid-scheme answer.'); pack.messages.forEach(function (mm) { s2.appendChild(item(mm.label, '', mm.text)); }); host.appendChild(s2); } if ((pack.emails || []).length) { var s3 = section('Email for your list', 'Drop straight into your autoresponder.'); pack.emails.forEach(function (em) { s3.appendChild(item('Email', em.subject, em.body)); }); host.appendChild(s3); } if ((pack.textAds || []).length) { var s4 = section('Text ads', 'Ready to run from the Traffic Desk.'); var grid = document.createElement('div'); grid.className = 'd-ads'; pack.textAds.forEach(function (a) { var c = document.createElement('div'); c.className = 'd-ad'; var h = '
' + esc(a.subject) + '
'; (a.lines || []).forEach(function (l) { if (l) h += '
' + esc(l) + '
'; }); c.innerHTML = h; grid.appendChild(c); }); s4.appendChild(grid); host.appendChild(s4); } // Be straight about anything the engine could not produce, rather than // quietly handing over a short pack. if ((pack.problems || []).length) { var warn = document.createElement('div'); warn.className = 'd-item'; warn.style.borderColor = '#f0a05a'; warn.innerHTML = '
Incomplete
' + 'The engine could not finish: ' + esc(pack.problems.join(', ')) + '. Everything else above is fine — build again to retry the missing pieces.
'; host.appendChild(warn); } } function renderKey(info, freshKey) { var host = $('dKeyState'); if (freshKey) { host.innerHTML = '
Copy this now — it is shown once and never again.
' + '
' + esc(freshKey) + '
'; var b = copyBtn(function () { return freshKey; }); b.style.position = 'static'; b.style.marginTop = '8px'; host.appendChild(b); $('dIssue').textContent = 'Replace this key'; $('dRevoke').style.display = ''; return; } if (info && info.exists) { host.innerHTML = '
A key is active (' + esc(info.hint) + '), created ' + esc(String(info.createdAt || '').slice(0, 10)) + (info.lastUsedAt ? ', last used ' + esc(String(info.lastUsedAt).slice(0, 10)) : ', never used yet') + '. The key itself is stored hashed, so it cannot be shown again — create a new one if you have lost it.
'; $('dIssue').textContent = 'Replace this key'; $('dRevoke').style.display = ''; } else { host.innerHTML = '
No key yet.
'; $('dIssue').textContent = 'Create a key'; $('dRevoke').style.display = 'none'; } } async function build(btn) { btn.disabled = true; btn.innerHTML = 'Building your week — this takes a minute…'; $('dErr').style.display = 'none'; try { var r = await fetch('/api/public/suite-founder', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' }); var d = await r.json(); if (!r.ok) { $('dErr').textContent = d.error || 'That did not build — try again.'; $('dErr').style.display = 'block'; } else { renderPack(d.pack); if (d.meter) $('dMeter').textContent = d.meter.remaining + ' of ' + d.meter.limit + ' packs left this month'; } } catch (e) { $('dErr').textContent = 'Connection hiccup — try again.'; $('dErr').style.display = 'block'; } btn.disabled = false; btn.innerHTML = '👑 Build my week'; } async function issue() { if (!window.confirm('Create a new API key? Any existing key stops working immediately.')) return; try { var r = await fetch('/api/public/suite-founder', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ issueKey: true }) }); var d = await r.json(); if (r.ok) renderKey(d.info, d.key); } catch (e) {} } async function revoke() { if (!window.confirm('Revoke your API key? Anything using it stops working.')) return; try { var r = await fetch('/api/public/suite-founder', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ revokeKey: true }) }); var d = await r.json(); if (r.ok) renderKey(d.info, null); } catch (e) {} } async function boot() { try { var r = await fetch('/api/public/suite-founder'); if (r.status === 401) { gate('You’re not signed in yet. Open the Suite and connect the wallet that holds your position, then come back.'); return; } if (r.status === 403) { var g = await r.json(); gate((g.error || 'Not open for this position yet.') + ' See your Suite.'); return; } if (!r.ok) return; var d = await r.json(); $('dBody').style.display = 'block'; renderPack(d.pack); renderKey(d.key, null); if (d.meter) $('dMeter').textContent = d.meter.remaining + ' of ' + d.meter.limit + ' packs left this month'; if (d.writerReady === false) { $('dGo').disabled = true; $('dGo').textContent = 'The writer is warming up'; } } catch (e) {} } document.addEventListener('DOMContentLoaded', function () { boot(); $('dGo').addEventListener('click', function () { build(this); }); $('dIssue').addEventListener('click', issue); $('dRevoke').addEventListener('click', revoke); }); })();