[object Object]

← back to Wallco Ai

PDP: '✓ smart-fix → #child' pill linking a design to its published smart-fixed child (parent_design_id). Server-side, works on monolith + theme PDPs + unpublished parents; /api/design exposes smartfix_child.

0bbf5baccc807bd72ea40403279b97e3160e7a07 · 2026-06-02 08:34:31 -0700 · Steve Abrams

Files touched

Diff

commit 0bbf5baccc807bd72ea40403279b97e3160e7a07
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 2 08:34:31 2026 -0700

    PDP: '✓ smart-fix → #child' pill linking a design to its published smart-fixed child (parent_design_id). Server-side, works on monolith + theme PDPs + unpublished parents; /api/design exposes smartfix_child.
---
 server.js | 37 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/server.js b/server.js
index 2c5a8ea..68e71d9 100644
--- a/server.js
+++ b/server.js
@@ -494,6 +494,13 @@ app.get('/api/design/:id', (req, res) => {
   // the name can never disagree with the color shown (a #FFCFD8 blush design
   // must not read "Midnight Navy"). See lib/hex-colorname.js. (Steve 2026-06-01)
   applyHexConsistentNaming(merged);
+  // Surface a published smart-fix child (parent_design_id=id) so the PDP can link
+  // parent → its fixed/published version (Steve 2026-06-02: "✓ smart-fix → #child").
+  try {
+    const c = psqlQuery(`SELECT id FROM spoon_all_designs WHERE parent_design_id=${id} AND is_published=TRUE AND user_removed IS NOT TRUE ORDER BY created_at DESC, id DESC LIMIT 1`);
+    const cid = parseInt(c, 10);
+    if (Number.isFinite(cid) && cid > 0 && cid !== id) merged.smartfix_child = cid;
+  } catch { /* PG hiccup — omit the link */ }
   res.json({ ok: true, design: merged });
 });
 
@@ -536,6 +543,33 @@ app.get('/design/:id/tabs', (req, res) => {
 // Theme variants are standalone HTML. Inject the standard site chrome — login
 // header + nav + footer — so every theme has the login and the same info as the
 // rest of the site (Steve 2026-06-01). One injection point covers all variants.
+// Inject a "✓ smart-fix → #child" link into a theme PDP, server-side with the
+// concrete child id baked in (works even when the parent is unpublished and its
+// /api/design 404s). Child = newest published design with parent_design_id=id.
+// Steve 2026-06-02. Raw theme file cached; only the per-id link is appended.
+// Returns the "✓ smart-fix → #child" pill <a> for a design that has a published
+// smart-fix child (parent_design_id=id), else ''. Server-side so it works even
+// for unpublished parents. Used by both the theme PDP and the monolith PDP.
+function smartFixLinkFor(id) {
+  let childId = null;
+  try {
+    const c = psqlQuery(`SELECT id FROM spoon_all_designs WHERE parent_design_id=${parseInt(id, 10)} AND is_published=TRUE AND user_removed IS NOT TRUE ORDER BY created_at DESC, id DESC LIMIT 1`);
+    const cid = parseInt(c, 10);
+    if (Number.isFinite(cid) && cid > 0 && cid !== id) childId = cid;
+  } catch { /* PG hiccup — no link */ }
+  if (!childId) return '';
+  return `<a href="/design/${childId}" title="View the published smart-fixed version" style="position:fixed;top:88px;right:16px;z-index:99999;background:#c79a3a;color:#3a2a00;padding:8px 14px;border-radius:999px;font:600 12px system-ui,-apple-system,sans-serif;text-decoration:none;box-shadow:0 2px 10px rgba(0,0,0,.28)">&#10003; smart-fix &#8594; #${childId}</a>`;
+}
+const _pdpThemeRawCache = {};
+function injectSmartFixLink(file, id) {
+  const full = path.join(__dirname, 'public', 'theme-variants', file);
+  let html = _pdpThemeRawCache[file];
+  if (html === undefined) { try { html = fs.readFileSync(full, 'utf8'); } catch { return '<h1>404</h1>'; } _pdpThemeRawCache[file] = html; }
+  const link = smartFixLinkFor(id);
+  if (!link) return html;
+  return /<\/body>/i.test(html) ? html.replace(/<\/body>/i, link + '\n</body>') : html + link;
+}
+
 const _themeVariantCache = {};
 function themeVariantSend(req, res, file) {
   const id = parseInt(req.params.id, 10);
@@ -12756,7 +12790,7 @@ app.get('/design/:id', (req, res) => {
       ? req.query.theme : null;
     const liveSlug = req.query.classic === '1' ? null : (previewSlug || getActivePdpTheme());
     if (liveSlug && THEME_FILE_MAP[liveSlug]) {
-      return res.sendFile(path.join(__dirname, 'public', 'theme-variants', THEME_FILE_MAP[liveSlug]));
+      return res.type('html').send(injectSmartFixLink(THEME_FILE_MAP[liveSlug], id));
     }
   }
 
@@ -13027,6 +13061,7 @@ app.get('/design/:id', (req, res) => {
   })}
 <body>
 ${htmlHeader('/designs')}
+${smartFixLinkFor(id)}
 <main class="detail-main" id="detail-main"${_isAdmin ? ' data-page-theme="theme2"' : ''}>
 ${_isAdmin ? `
 <!-- Theme toggle (theme1 / theme2) — ADMIN-ONLY preview surface

← c198fff generator: every new design self-archives TIF+SVG via build-  ·  back to Wallco Ai  ·  color-dots: Save targets the last-recolored image, not the t 3535426 →