[object Object]

← back to Marketing Command Center

chore: harden calendars module (pool error log, load() try/catch, fieldvis merge), v1.1.0 (session close)

f2866e6a03f1c2a4f48e4704819e0adead21a4a7 · 2026-07-16 08:54:09 -0700 · Steve Abrams

Report-only lint+refactor review at close — all syntax valid, SQL parameterization safe,
no critical issues. Applied 3 safe non-behavioral robustness fixes:
- lib.js: pool 'error' handler now logs instead of silently swallowing
- calendars.js: load() wrapped in try/catch with Retry banner (was: spinner-forever on fetch fail)
- calendars.js: fieldvis prefs now MERGE over defaults (was: JSON.parse('') threw every fresh load)
Deferred cosmetic items (pad dedup, named SLOT_MIN constant client-side) — noted, not applied.
NOTE: local now 1 commit ahead of live; ships on the next (gated) MCC deploy.

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

Files touched

Diff

commit f2866e6a03f1c2a4f48e4704819e0adead21a4a7
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 16 08:54:09 2026 -0700

    chore: harden calendars module (pool error log, load() try/catch, fieldvis merge), v1.1.0 (session close)
    
    Report-only lint+refactor review at close — all syntax valid, SQL parameterization safe,
    no critical issues. Applied 3 safe non-behavioral robustness fixes:
    - lib.js: pool 'error' handler now logs instead of silently swallowing
    - calendars.js: load() wrapped in try/catch with Retry banner (was: spinner-forever on fetch fail)
    - calendars.js: fieldvis prefs now MERGE over defaults (was: JSON.parse('') threw every fresh load)
    Deferred cosmetic items (pad dedup, named SLOT_MIN constant client-side) — noted, not applied.
    NOTE: local now 1 commit ahead of live; ships on the next (gated) MCC deploy.
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 modules/calendars/lib.js   |  2 +-
 package-lock.json          |  4 ++--
 package.json               |  2 +-
 public/panels/calendars.js | 13 ++++++++++---
 4 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/modules/calendars/lib.js b/modules/calendars/lib.js
index 44aa545..61a299e 100644
--- a/modules/calendars/lib.js
+++ b/modules/calendars/lib.js
@@ -35,7 +35,7 @@ function pool() {
     ? new Pool({ connectionString: process.env.DATABASE_URL, max: 4 })
     : new Pool({ host: process.env.PGHOST || '/tmp', database: process.env.PGDATABASE || 'dw_unified',
         user: process.env.PGUSER || process.env.USER || 'stevestudio2', max: 4 });
-  _pool.on('error', () => {});   // never let an idle-client error crash the MCC
+  _pool.on('error', (e) => console.error('[calendars pool]', e.message));   // log, but never crash the MCC
   return _pool;
 }
 
diff --git a/package-lock.json b/package-lock.json
index 4ec4447..cb34005 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "marketing-command-center",
-  "version": "1.0.2",
+  "version": "1.1.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "marketing-command-center",
-      "version": "1.0.2",
+      "version": "1.1.0",
       "dependencies": {
         "express": "^4.22.2",
         "pg": "^8.22.0"
diff --git a/package.json b/package.json
index 47868bf..9c14a53 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "marketing-command-center",
-  "version": "1.0.2",
+  "version": "1.1.0",
   "description": "DW Marketing Command Center — Constant Contact, marketing calendar, suggested copy, on-demand layouts",
   "main": "server.js",
   "scripts": {
diff --git a/public/panels/calendars.js b/public/panels/calendars.js
index 82fbb28..86b632d 100644
--- a/public/panels/calendars.js
+++ b/public/panels/calendars.js
@@ -245,8 +245,15 @@ window.MCC_PANELS = window.MCC_PANELS || {};
   // ── load + wire ──
   async function load(fresh) {
     $('#cwCal').innerHTML = '<div class="cw-loading">' + (fresh ? 'Refreshing from live dw_unified…' : 'Loading calendars…') + '</div>';
-    const r = await fetch(ORIGIN + '/api/calendars/events' + (fresh ? '?fresh=1' : ''), { credentials: 'same-origin' });
-    const d = await r.json();
+    let d;
+    try {
+      const r = await fetch(ORIGIN + '/api/calendars/events' + (fresh ? '?fresh=1' : ''), { credentials: 'same-origin' });
+      if (!r.ok) throw new Error('HTTP ' + r.status);
+      d = await r.json();
+    } catch (e) {
+      $('#cwCal').innerHTML = `<div class="cw-note" style="padding:20px">Couldn't load calendars (${esc(e.message)}). <button class="cw-btn" onclick="location.reload()">Retry</button></div>`;
+      return;
+    }
     ALL = (d.items || []).map(it => ({ ...it, month: (it.date || '').slice(0, 7) }));
     META = d;
     if (d.mock || d.error) $('#cwCal').insertAdjacentHTML('afterbegin', `<div class="cw-note" style="padding:10px 14px">Live catalog unavailable (${esc(d.error || 'db')}). Showing ${ALL.length} cached/overlay items.</div>`);
@@ -261,7 +268,7 @@ window.MCC_PANELS = window.MCC_PANELS || {};
   window.MCC_PANELS['calendars'] = {
     async init() {
       // restore prefs
-      try { FVIS = JSON.parse(localStorage.getItem('cw.fieldvis') || '') || FVIS; } catch {}
+      try { const s = localStorage.getItem('cw.fieldvis'); if (s) FVIS = { ...FVIS, ...JSON.parse(s) }; } catch {}
       const dens = localStorage.getItem('cw.density') || '5';
       $('#cwDensity').value = dens; setDensity(dens);
       applyFieldVis();

← a83ad8f Place All Calendars in the Planning nav group (next to Marke  ·  back to Marketing Command Center  ·  PR naturals mailer: point SISAL tile at sisal search (page 5 b3300df →