← back to Consulting Intake
public/admin/index.html
68 lines
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>Consulting Intake · Growth & Social Command Center</title>
<style>
:root{--ink:#14110e;--bg:#12100e;--panel:#1c1915;--gold:#c6a765;--line:#2c2823;--txt:#e9e2d6}
*{box-sizing:border-box}
body{margin:0;font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--txt)}
header{padding:16px 24px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center}
header h1{font-size:16px;font-weight:600;letter-spacing:.08em;margin:0}
header .eyebrow{color:var(--gold);font-size:11px;letter-spacing:.28em;text-transform:uppercase}
header a{color:var(--gold);text-decoration:none;font-size:13px}
.wrap{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:16px;padding:20px 24px}
.panel{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:16px 18px}
.panel h2{font-size:13px;letter-spacing:.14em;text-transform:uppercase;color:var(--gold);margin:0 0 10px;display:flex;justify-content:space-between;align-items:center}
.panel h2 .tag{font-size:10px;color:#8a8272;letter-spacing:.06em}
textarea{width:100%;min-height:150px;background:#0e0c0a;color:#cfe6cf;border:1px solid var(--line);border-radius:4px;font-family:'SF Mono',ui-monospace,monospace;font-size:12px;padding:10px;resize:vertical}
button{background:var(--gold);color:#12100e;border:0;padding:8px 16px;font-weight:600;letter-spacing:.08em;font-size:12px;border-radius:4px;cursor:pointer;margin-top:8px}
button:hover{filter:brightness(1.08)}
.saved{color:#7ad17a;font-size:12px;margin-left:10px}
.note{font-size:12px;color:#8a8272;margin:0 0 8px}
</style>
</head>
<body>
<header>
<div><div class="eyebrow">Integrated Social · Growth</div><h1>Consulting Intake — Command Center</h1></div>
<div><a href="/portal">← Deliverable</a> <a href="/">Sign-in</a></div>
</header>
<div class="wrap" id="wrap"></div>
<script>
// Each panel is a live-editable view of one data bucket. Edit the JSON, Save,
// and the server rewrites data/<bucket>.json. Script runners (competitors-scan,
// best-times, ig-pull, places-read, gen-media) repopulate these from real data.
const PANELS = [
['socials','Connected Accounts','Instagram · Facebook · TikTok · YouTube · LinkedIn · GBP'],
['best-times','Best Times to Post','per-platform posting cadence'],
['content-calendar','Content Calendar','planned posts / campaigns — DRAFT ONLY'],
['competitors','Competitor Radar','who else is in the market + their social/ads'],
['ads','Ad Signals','which platforms competitors advertise on'],
['directories','Listings & Directories','GBP · Yelp · Apple · Bing'],
['suggestions','Growth Moves','impact / effort ranked ideas'],
['media','Generated Media','reels / graphics produced for this client'],
];
const wrap = document.getElementById('wrap');
async function j(u,opt){ const r=await fetch(u,opt); return r.ok?r.json():null; }
for (const [key,title,tag] of PANELS){
const p = document.createElement('div'); p.className='panel';
p.innerHTML = '<h2>'+title+'<span class="tag">'+tag+'</span></h2>'
+ '<textarea id="ta-'+key+'">loading…</textarea>'
+ '<div><button data-k="'+key+'">Save '+key+'</button><span class="saved" id="ok-'+key+'"></span></div>';
wrap.appendChild(p);
j('/api/admin/'+key).then(d=>{ document.getElementById('ta-'+key).value = JSON.stringify(d ?? [], null, 2); });
}
wrap.addEventListener('click', async (e)=>{
const b = e.target.closest('button[data-k]'); if(!b) return;
const k = b.dataset.k; const ta = document.getElementById('ta-'+k); let body;
try { body = JSON.parse(ta.value); } catch { document.getElementById('ok-'+k).textContent='✗ invalid JSON'; return; }
const r = await fetch('/api/admin/'+k,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
document.getElementById('ok-'+k).textContent = r.ok ? '✓ saved '+new Date().toLocaleTimeString() : '✗ error';
setTimeout(()=>{document.getElementById('ok-'+k).textContent='';},4000);
});
</script>
</body>
</html>