← back to Marketing Command Center
public/panels/compose.js
91 lines
// Compose — merges the engine ("Suggested") and composer ("Manual") panels into
// one tabbed surface WITHOUT duplicating their code. Each tab loads the real
// panel's html into its pane and calls that panel's own MCC_PANELS[id].init(pane),
// so engine.js / composer.js remain the single source of truth. Lazy: Suggested
// inits on open, Manual on first click. The sounds panel's queued songs
// (localStorage 'mccSndSocial') are offered into the Manual caption.
window.MCC_PANELS = window.MCC_PANELS || {};
window.MCC_PANELS['compose'] = {
async init(root) {
const ORIGIN = location.origin;
const paneS = root.querySelector('[data-pane="suggested"]');
const paneM = root.querySelector('[data-pane="manual"]');
let sInited = false, mInited = false;
// Ensure a sibling panel's JS is loaded (it self-registers MCC_PANELS[id]).
async function ensureScript(id) {
if (window.MCC_PANELS[id]) return;
await new Promise(res => {
const s = document.createElement('script');
s.src = ORIGIN + '/panels/' + id + '.js';
s.onload = res; s.onerror = res;
document.body.appendChild(s);
});
}
// Load <id>.html into a pane, then run that panel's own init against the pane.
async function mountInto(id, pane) {
try {
const r = await fetch(ORIGIN + '/panels/' + id + '.html', { credentials: 'same-origin' });
pane.innerHTML = r.ok ? await r.text() : `<div class="muted">Could not load ${id}.</div>`;
} catch { pane.innerHTML = `<div class="muted">Could not load ${id}.</div>`; return; }
await ensureScript(id);
try {
if (window.MCC_PANELS[id] && window.MCC_PANELS[id].init) await window.MCC_PANELS[id].init(pane);
} catch (e) { console.error('[compose] ' + id + ' init failed', e); }
}
async function initSuggested() { if (sInited) return; sInited = true; await mountInto('engine', paneS); }
async function initManual() { if (mInited) return; mInited = true; await mountInto('composer', paneM); wireSoundOffer(paneM); }
// Offer the sounds panel's queued songs into the Manual caption (no silent
// mutation — a dismissible bar the user clicks). sounds.js writes the queue.
function wireSoundOffer(pane) {
let q; try { q = JSON.parse(localStorage.getItem('mccSndSocial') || '[]'); } catch (_) { q = []; }
if (!q.length) return;
const cap = pane.querySelector('#cmp-caption');
if (!cap) return;
const bar = document.createElement('div');
bar.className = 'cmp2-soundoffer';
bar.innerHTML = `🎵 <span><b>${q.length}</b> song${q.length === 1 ? '' : 's'} queued in Sounds.</span>` +
`<button type="button" class="cmp2-addbtn">Add to caption</button>` +
`<button type="button" class="cmp2-dismiss" title="Dismiss">×</button>`;
cap.parentNode.insertBefore(bar, cap);
bar.querySelector('.cmp2-addbtn').onclick = () => {
const lines = q.map(s => `🎵 Sound: ${s.name} — ${s.url}`).join('\n');
cap.value = (cap.value.trim() ? cap.value.trim() + '\n\n' : '') + lines;
cap.dispatchEvent(new Event('input', { bubbles: true })); // composer's countIt listens on input
bar.remove();
};
bar.querySelector('.cmp2-dismiss').onclick = () => bar.remove();
}
// Tabs: toggle panes; lazy-init Manual on first reveal.
root.querySelectorAll('.cmp2-tab').forEach(btn => btn.onclick = () => {
const t = btn.dataset.tab;
root.querySelectorAll('.cmp2-tab').forEach(b => b.classList.toggle('active', b === btn));
paneS.hidden = t !== 'suggested';
paneM.hidden = t !== 'manual';
if (t === 'manual') initManual();
});
// Badge the Manual tab when songs are queued (so the sound offer is discoverable).
try {
const q = JSON.parse(localStorage.getItem('mccSndSocial') || '[]');
const badge = root.querySelector('#cmp2-badge');
if (q.length && badge) { badge.hidden = false; badge.textContent = q.length; }
} catch (_) {}
// If Quick Post handed off a "Publish live" prefill, open the Manual tab
// directly (composer.js reads + applies the prefill on its init).
let hasPrefill = false;
try { hasPrefill = !!sessionStorage.getItem('mccComposePrefill'); } catch (_) {}
if (hasPrefill) {
root.querySelectorAll('.cmp2-tab').forEach(b => b.classList.toggle('active', b.dataset.tab === 'manual'));
paneS.hidden = true; paneM.hidden = false;
initManual();
} else {
initSuggested(); // Suggested is the default tab
}
},
};