[object Object]

← back to Dw Pairs Well

preview.html: accept handle (auto-detect vs dw_sku), deep-link via ?handle=/?sku=/?key=, surface real .catch errors, add Izara repro buttons — dev surface to diagnose the 2026-05-13 Shopify-side render failure without touching the live theme

c54aef983831091eca0c8e0800fecda141a5b695 · 2026-05-13 11:14:51 -0700 · Steve

Files touched

Diff

commit c54aef983831091eca0c8e0800fecda141a5b695
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed May 13 11:14:51 2026 -0700

    preview.html: accept handle (auto-detect vs dw_sku), deep-link via ?handle=/?sku=/?key=, surface real .catch errors, add Izara repro buttons — dev surface to diagnose the 2026-05-13 Shopify-side render failure without touching the live theme
---
 public/preview.html | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/public/preview.html b/public/preview.html
index 071085d..4a53c85 100644
--- a/public/preview.html
+++ b/public/preview.html
@@ -144,10 +144,12 @@
 
 <main>
   <div class="source-picker">
-    <label for="sku">Source SKU</label>
-    <input id="sku" type="text" value="DWRW-74991" autocomplete="off">
+    <label for="sku">SKU or handle</label>
+    <input id="sku" type="text" value="DWRW-74991" autocomplete="off" placeholder="DWA-91351 or izara-beige-..." style="min-width:340px">
     <button id="load">Load</button>
     <div class="quick">
+      <button data-sku="izara-beige-residential-wallpaper-jeffrey-stevens">Izara Beige (repro 2026-05-13)</button>
+      <button data-sku="izara-light-green-residential-wallpaper-jeffrey-stevens">Izara Light Green</button>
       <button data-sku="DWRW-74991">DWRW-74991 (Rebel Walls mural)</button>
       <button data-sku="DWPT-200315">DWPT-200315 (1838 Floribunda Midnight)</button>
       <button data-sku="DWPT-200312">DWPT-200312 (1838 Lavender Dream)</button>
@@ -370,9 +372,16 @@
   }
 
   // ---- load source product + catalog pairs (deferred until CTA click) + AI ----
-  async function loadSource(sku) {
-    picker.value = sku;
-    section.setAttribute('data-product-sku', sku);
+  // `key` can be a dw_sku (e.g. DWA-91351) OR a Shopify handle (e.g. izara-beige-...).
+  // We auto-detect: if it contains a hyphen + non-uppercase letters, treat as handle.
+  function buildQuery(key) {
+    var isHandle = /[a-z]/.test(key) && key.indexOf('-') !== -1 && !/^DW[A-Z]?-/.test(key);
+    return (isHandle ? 'handle=' : 'dw_sku=') + encodeURIComponent(key);
+  }
+
+  async function loadSource(key) {
+    picker.value = key;
+    section.setAttribute('data-product-sku', key);
     cta.setAttribute('aria-expanded', 'false');
     catalogHeader.hidden = true;
     catalogGrid.hidden = true;
@@ -381,9 +390,12 @@
     aiSection.hidden = true;
     aiGrid.innerHTML = '';
 
+    var qs = buildQuery(key);
     try {
-      var r = await fetch(endpointPairs + '?dw_sku=' + encodeURIComponent(sku) + '&limit=24');
+      var r = await fetch(endpointPairs + '?' + qs + '&limit=24');
+      if (!r.ok) throw new Error('http ' + r.status);
       var d = await r.json();
+      if (d && d.ok === false) throw new Error(d.error || 'bad payload');
       if (d && d.source) {
         photoEl.src = d.source.image_url || '';
         photoEl.alt = d.source.title || '';
@@ -393,24 +405,29 @@
         section._catalogPairs = d.pairs || [];
         catalogCount.textContent = '(' + (d.pairs || []).length + ')';
       } else {
-        titleEl.textContent = 'Not found: ' + sku;
+        titleEl.textContent = 'Not found: ' + key;
         vendorEl.textContent = '';
         photoEl.removeAttribute('src');
       }
     } catch (e) {
-      titleEl.textContent = 'Service unreachable on :9813';
+      console.error('[preview] catalog fetch failed:', e, 'url=', endpointPairs + '?' + qs);
+      titleEl.textContent = 'Catalog fetch failed: ' + (e && e.message ? e.message : 'unknown');
+      vendorEl.textContent = '';
     }
 
     // Kick off AI generation in parallel — show its section as soon as it loads
     showSkeletons(aiGrid, 24);
     aiSection.hidden = false;
     try {
-      var ar = await fetch(endpointAi + '?dw_sku=' + encodeURIComponent(sku) + '&limit=24');
+      var ar = await fetch(endpointAi + '?' + qs + '&limit=24');
+      if (!ar.ok) throw new Error('http ' + ar.status);
       var ad = await ar.json();
+      if (ad && ad.ok === false) throw new Error(ad.error || 'bad payload');
       if (ad && ad.items) renderGrid(aiGrid, ad.items, { aiBadge: 'AI-Generated' });
       else aiGrid.innerHTML = '<div class="pairs-well__empty">AI generator not ready yet.</div>';
     } catch (e) {
-      aiGrid.innerHTML = '<div class="pairs-well__empty">AI service unreachable.</div>';
+      console.error('[preview] ai fetch failed:', e, 'url=', endpointAi + '?' + qs);
+      aiGrid.innerHTML = '<div class="pairs-well__empty">AI fetch failed: ' + (e && e.message ? e.message : 'unknown') + '</div>';
     }
   }
 
@@ -418,6 +435,13 @@
   picker.addEventListener('keydown', function (e) { if (e.key === 'Enter') loadSource(picker.value.trim()); });
   quickBtns.forEach(function (b) { b.addEventListener('click', function () { loadSource(b.getAttribute('data-sku')); }); });
 
+  // Deep-link: ?handle=... or ?sku=... or ?key=... auto-loads on page open.
+  (function () {
+    var params = new URLSearchParams(window.location.search);
+    var k = params.get('handle') || params.get('sku') || params.get('key');
+    if (k) loadSource(k.trim());
+  })();
+
   cta.addEventListener('click', function () {
     var open = cta.getAttribute('aria-expanded') === 'true';
     if (open) {

← a19993c design-coordinate: surface real error in .catch (was 'Could  ·  back to Dw Pairs Well  ·  pairs/coordinate: accept ?palette=#hex,#hex,... for external d7926be →