[object Object]

← back to Carmelwallpapers

stage2: wire carmelwallpapers onto shared catalog (hand-tailored)

ccc83e1c476162e63c81ab0fcc51c83eb4e6cffa · 2026-05-19 11:07:18 -0700 · Steve Abrams

Files touched

Diff

commit ccc83e1c476162e63c81ab0fcc51c83eb4e6cffa
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue May 19 11:07:18 2026 -0700

    stage2: wire carmelwallpapers onto shared catalog (hand-tailored)
---
 server.js | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 58 insertions(+), 14 deletions(-)

diff --git a/server.js b/server.js
index b04006d..cd30afc 100644
--- a/server.js
+++ b/server.js
@@ -6,6 +6,27 @@ const path = require('path');
 const PORT = process.env.PORT || 9832;
 const DATA_PATH = path.join(__dirname, 'data', 'products.json');
 
+// ── Shared catalog: products live in dw_unified.microsite_products ───────────
+const catalog = require('../_shared/admin-catalog');
+const siteCfg = JSON.parse(fs.readFileSync(path.join(__dirname, 'site.config.json'), 'utf8'));
+const SITE_SLUG  = siteCfg.slug || path.basename(__dirname);
+const SITE_RAILS = Array.isArray(siteCfg.rails) ? siteCfg.rails : [];
+
+// The PG read-path returns the canonical microsite_products columns. The Carmel
+// templates also expect `sample_url` + `images` (legacy products.json fields),
+// so derive them: sample = product page anchored to #sample; images = [image_url].
+function shapeForSite(p) {
+  const productUrl = p.product_url
+    || (p.handle ? `https://designerwallcoverings.com/products/${p.handle}` : '#');
+  return {
+    ...p,
+    product_url: productUrl,
+    sample_url: p.sample_url || `${productUrl}#sample`,
+    images: Array.isArray(p.images) && p.images.length ? p.images
+            : (p.image_url ? [p.image_url] : []),
+  };
+}
+
 // ── Junk filter ──────────────────────────────────────────────────────────────
 const JUNK_TITLE = /(lamp|rug|pillow|throw|tripod|frame|mirror|vase|candle|sculpture|figurine|stool|table|chair|sofa|curtain|bedding|towel|plate|bowl|mug)/i;
 function isJunk(p) {
@@ -99,23 +120,39 @@ let PRODUCTS = [];
 let DROPPED  = 0;
 let AESTHETICS = {};
 
-function loadData() {
+function applyProducts(raw) {
+  const clean = raw.map(shapeForSite).filter(p => !isJunk(p));
+  DROPPED = raw.length - clean.length;
+  PRODUCTS = clean;
+  AESTHETICS = {};
+  for (const p of PRODUCTS) {
+    AESTHETICS[p.aesthetic] = (AESTHETICS[p.aesthetic] || 0) + 1;
+  }
+}
+
+function loadFromJson() {
+  const raw = JSON.parse(fs.readFileSync(DATA_PATH, 'utf8'));
+  applyProducts(Array.isArray(raw) ? raw : []);
+}
+
+// PG-first load: read the curated catalog from dw_unified.microsite_products.
+// On any PG failure, fall back to the static data/products.json snapshot.
+async function loadData() {
   try {
-    const raw = JSON.parse(fs.readFileSync(DATA_PATH, 'utf8'));
-    const clean = raw.filter(p => !isJunk(p));
-    DROPPED = raw.length - clean.length;
-    PRODUCTS = clean;
-    AESTHETICS = {};
-    for (const p of PRODUCTS) {
-      AESTHETICS[p.aesthetic] = (AESTHETICS[p.aesthetic] || 0) + 1;
+    const rows = await catalog.getProducts(SITE_SLUG);
+    applyProducts(rows);
+    console.log(`Loaded ${PRODUCTS.length} products from dw_unified (dropped ${DROPPED} junk)`);
+  } catch (e) {
+    console.error(`PG catalog load failed (${e.message}) — falling back to data/products.json`);
+    try {
+      loadFromJson();
+      console.log(`Loaded ${PRODUCTS.length} products from JSON fallback (dropped ${DROPPED} junk)`);
+    } catch (e2) {
+      console.error('Failed to load products.json:', e2.message);
+      PRODUCTS = [];
     }
-    console.log(`Loaded ${PRODUCTS.length} products (dropped ${DROPPED} junk)`);
-  } catch(e) {
-    console.error('Failed to load products.json:', e.message);
-    PRODUCTS = [];
   }
 }
-loadData();
 
 const app = express();
 app.set('trust proxy', 1);
@@ -530,4 +567,11 @@ ${THEME_TOGGLE_SCRIPT}
 </body></html>`);
 });
 
-app.listen(PORT, () => console.log(`carmelwallpapers listening on :${PORT}`));
+// ── Admin catalog CRUD — /admin/catalog (basic-auth) + /api/admin/* REST ─────
+catalog.mount(app, { siteSlug: SITE_SLUG, rails: SITE_RAILS });
+
+// ── Startup: load catalog from PG, then listen ───────────────────────────────
+(async () => {
+  await loadData();
+  app.listen(PORT, () => console.log(`carmelwallpapers listening on :${PORT}`));
+})();

← 5958e2e fix: wire vendor sort handler, add SKU option, drop dead Pri  ·  back to Carmelwallpapers  ·  Phase 2: mobile-ready + tap-to-reveal 76119fc →