← 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
    }
  },
};