← 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
M public/panels/channels.htmlM public/panels/channels.js
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 →