[object Object]

← back to Marketing Command Center

channels: Instagram-account selector — pick 1-to-all IG accounts

f2636e37d40c2e0309842a1ba8f4ee6983237f06 · 2026-07-15 09:40:22 -0700 · Steve Abrams

When only Instagram is ticked, the page picker reframes as 'Instagram accounts':
rows show @handle first, All/None act on the visible (IG-filtered) list so All =
all IG accounts, count reads 'N of M Instagram accounts', search matches @handle.
Verified via Playwright (label/rows/All/None, 0 console errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files touched

Diff

commit f2636e37d40c2e0309842a1ba8f4ee6983237f06
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 15 09:40:22 2026 -0700

    channels: Instagram-account selector — pick 1-to-all IG accounts
    
    When only Instagram is ticked, the page picker reframes as 'Instagram accounts':
    rows show @handle first, All/None act on the visible (IG-filtered) list so All =
    all IG accounts, count reads 'N of M Instagram accounts', search matches @handle.
    Verified via Playwright (label/rows/All/None, 0 console errors).
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 public/panels/channels.html |  2 +-
 public/panels/channels.js   | 48 +++++++++++++++++++++++++++++++++------------
 2 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/public/panels/channels.html b/public/panels/channels.html
index 0fdc8c9..9dce96a 100644
--- a/public/panels/channels.html
+++ b/public/panels/channels.html
@@ -23,7 +23,7 @@
       <!-- Page picker: appears when Facebook/Instagram is selected. Choose WHICH
            of your FB Pages (and their linked IG accounts) the post goes to. -->
       <div id="ch-pages-wrap" style="margin-top:12px;display:none">
-        <label>Pages <span class="muted" id="ch-pages-count" style="font-weight:400"></span></label>
+        <label><span id="ch-pages-label">Pages</span> <span class="muted" id="ch-pages-count" style="font-weight:400"></span></label>
         <div class="row" style="gap:6px;margin:4px 0;align-items:center">
           <input type="text" id="ch-pages-search" placeholder="filter pages…" style="flex:1;min-width:150px">
           <button class="btn ghost xs" id="ch-pages-all" type="button">All</button>
diff --git a/public/panels/channels.js b/public/panels/channels.js
index 0a31d4e..1b2b3d8 100644
--- a/public/panels/channels.js
+++ b/public/panels/channels.js
@@ -32,21 +32,37 @@ window.MCC_PANELS['channels'] = {
       const wrap = $('#ch-pages-wrap'); if (!wrap) return;
       const show = metaSelected();
       wrap.style.display = show ? 'block' : 'none';
-      if (show && !pagesLoaded) loadPages(false);
+      if (show) { if (!pagesLoaded) loadPages(false); else renderPages(); } // re-render to reflect IG-vs-Pages mode
     }
 
+    // IG-only mode = ONLY Instagram is ticked → reframe the picker as "Instagram
+    // accounts" so you select 1-to-all IG accounts directly (each IG account is
+    // reached via its linked Page, so selection is still keyed by page id).
+    const igModeOn = () => metaSelected() && [...root.querySelectorAll('.ch-t:checked')].every(c => c.value === 'instagram');
+    // The rows currently shown — honors the search box AND (in IG mode) the
+    // IG-linked filter. All/None act on THIS list so "All" = all visible.
+    function visiblePages() {
+      const q = ($('#ch-pages-search') && $('#ch-pages-search').value.trim().toLowerCase()) || '';
+      let list = allPages.filter(p => !q || (p.name || '').toLowerCase().includes(q) || ('@' + (p.igUsername || '')).toLowerCase().includes(q));
+      if (igModeOn()) list = list.filter(p => p.hasIG); // IG posts can only go to IG-linked pages
+      return list;
+    }
     function renderPages() {
       const box = $('#ch-pages'); if (!box) return;
-      const q = ($('#ch-pages-search') && $('#ch-pages-search').value.trim().toLowerCase()) || '';
-      const igOnly = metaSelected() && [...root.querySelectorAll('.ch-t:checked')].every(c => c.value === 'instagram');
-      let list = allPages.filter(p => !q || (p.name || '').toLowerCase().includes(q));
-      if (igOnly) list = list.filter(p => p.hasIG); // posting IG-only → only IG-linked pages can receive it
-      box.innerHTML = list.length ? list.map(p =>
-        `<label style="display:flex;align-items:center;gap:7px;padding:3px 4px;font-size:12.5px;border-radius:5px">
-           <input type="checkbox" class="ch-pg" value="${esc(p.id)}" style="width:auto" ${selectedPages.has(p.id) ? 'checked' : ''}>
-           <span style="flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(p.name)}</span>
-           ${p.hasIG ? `<span class="muted" title="IG: @${esc(p.igUsername || '')}" style="font-size:11px">📸 @${esc(p.igUsername || '')}</span>` : ''}
-         </label>`).join('') : '<div class="muted">No pages match.</div>';
+      const igOnly = igModeOn();
+      const lbl = $('#ch-pages-label'); if (lbl) lbl.textContent = igOnly ? 'Instagram accounts' : 'Pages';
+      const list = visiblePages();
+      box.innerHTML = list.length ? list.map(p => igOnly
+        ? `<label style="display:flex;align-items:center;gap:7px;padding:3px 4px;font-size:12.5px;border-radius:5px">
+             <input type="checkbox" class="ch-pg" value="${esc(p.id)}" style="width:auto" ${selectedPages.has(p.id) ? 'checked' : ''}>
+             <span style="font-weight:600;white-space:nowrap">📸 @${esc(p.igUsername || '')}</span>
+             <span class="muted" style="flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:11px" title="via Page: ${esc(p.name)}">${esc(p.name)}</span>
+           </label>`
+        : `<label style="display:flex;align-items:center;gap:7px;padding:3px 4px;font-size:12.5px;border-radius:5px">
+             <input type="checkbox" class="ch-pg" value="${esc(p.id)}" style="width:auto" ${selectedPages.has(p.id) ? 'checked' : ''}>
+             <span style="flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(p.name)}</span>
+             ${p.hasIG ? `<span class="muted" title="IG: @${esc(p.igUsername || '')}" style="font-size:11px">📸 @${esc(p.igUsername || '')}</span>` : ''}
+           </label>`).join('') : `<div class="muted">${igOnly ? 'No Instagram accounts match.' : 'No pages match.'}</div>`;
       box.querySelectorAll('.ch-pg').forEach(c => c.addEventListener('change', () => {
         if (c.checked) selectedPages.add(c.value); else selectedPages.delete(c.value);
         savePageSel(); updatePagesCount();
@@ -55,7 +71,13 @@ window.MCC_PANELS['channels'] = {
     }
     function updatePagesCount() {
       const el = $('#ch-pages-count'); if (!el) return;
-      el.textContent = `· ${selectedPages.size} of ${allPages.length} selected`;
+      if (igModeOn()) {
+        const igIds = new Set(allPages.filter(p => p.hasIG).map(p => p.id));
+        const selIg = [...selectedPages].filter(id => igIds.has(id)).length;
+        el.textContent = `· ${selIg} of ${igIds.size} Instagram accounts`;
+      } else {
+        el.textContent = `· ${selectedPages.size} of ${allPages.length} selected`;
+      }
     }
     async function loadPages(refresh) {
       const box = $('#ch-pages'); if (box) box.innerHTML = '<div class="muted">Loading pages…</div>';
@@ -72,7 +94,7 @@ window.MCC_PANELS['channels'] = {
     }
     // picker controls
     if ($('#ch-pages-search')) $('#ch-pages-search').addEventListener('input', renderPages);
-    if ($('#ch-pages-all')) $('#ch-pages-all').onclick = () => { allPages.forEach(p => selectedPages.add(p.id)); savePageSel(); renderPages(); };
+    if ($('#ch-pages-all')) $('#ch-pages-all').onclick = () => { visiblePages().forEach(p => selectedPages.add(p.id)); savePageSel(); renderPages(); };
     if ($('#ch-pages-none')) $('#ch-pages-none').onclick = () => { selectedPages.clear(); savePageSel(); renderPages(); };
     if ($('#ch-pages-ig')) $('#ch-pages-ig').onclick = () => { selectedPages.clear(); allPages.filter(p => p.hasIG).forEach(p => selectedPages.add(p.id)); savePageSel(); renderPages(); };
     if ($('#ch-pages-refresh')) $('#ch-pages-refresh').onclick = () => loadPages(true);

← df1e623 chore: lint fixes (jget r.ok guard, .env value quoting per u  ·  back to Marketing Command Center  ·  auto-save: 2026-07-15T11:36:14 (1 files) — scripts/fix-conni 0f46bdd →