← 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 →