[object Object]

← back to Reidwitlin Landing

reidwitlin-landing: add Memo/Stock/Price chip actions (shared vendor-requests module)

685f7c88b6187a6ed68b06ac3f4c9ab5c73af3da · 2026-07-15 15:02:35 -0700 · Steve Abrams

Files touched

Diff

commit 685f7c88b6187a6ed68b06ac3f4c9ab5c73af3da
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 15 15:02:35 2026 -0700

    reidwitlin-landing: add Memo/Stock/Price chip actions (shared vendor-requests module)
---
 public/index.html | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/public/index.html b/public/index.html
index c2a62a3..e610990 100644
--- a/public/index.html
+++ b/public/index.html
@@ -94,6 +94,13 @@ body.imgonly .grid:not(.list) .card .b{display:none}
 .acts{display:flex;flex-wrap:wrap;gap:6px;margin-top:3px}
 .act{font-size:11px;font-weight:600;border:1px solid var(--line);background:var(--panel);color:var(--ink);border-radius:7px;padding:4px 10px;cursor:pointer}
 .act:hover{border-color:var(--acc)}
+.act:disabled{opacity:.5;cursor:default}
+body.imgonly .grid:not(.list) .card .acts{display:none}
+#toast{position:fixed;left:50%;bottom:18px;transform:translateX(-50%) translateY(20px);max-width:min(560px,92vw);
+  background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:10px 16px;font-size:13px;
+  box-shadow:0 8px 30px #0008;opacity:0;pointer-events:none;transition:.25s;z-index:120}
+#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
+#toast.ok{border-color:#2a6a4a} #toast.err{border-color:#7a2a2a}
 #more{display:block;margin:8px auto 60px;background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:9px 18px;cursor:pointer}
 #empty{padding:60px;text-align:center;color:var(--mut)}
 /* ── List view ── aligned CSS-grid rows (.b uses display:contents so its
@@ -267,7 +274,7 @@ function card(p){
     :`<div class="imgwrap noimg"></div>`;
   const kv=(k,v)=>v?`<div class="kv"><span class="k">${k}</span><span class="v">${esc(v)}</span></div>`:'';
   const dot=BUCKET_HEX[p.color_bucket]||'#666';
-  return `<div class="card" data-href="/product/${encodeURIComponent(p.handle)}" data-handle="${esc(p.handle)}">
+  return `<div class="card" data-href="/product/${encodeURIComponent(p.handle)}" data-handle="${esc(p.handle)}" data-sku="${esc(p.dw_sku||'')}" data-mfr="${esc(p.sku||'')}" data-title="${esc((p.series||p.display_name||'')+(p.color?(' — '+p.color):''))}">
     ${img}<div class="b">
     <span class="vend">${esc(p.book||'Reid Witlin')}${p.series&&p.series!==p.display_name?(' · '+esc(p.series)):''}</span>
     <div class="ttl">${title}</div>
@@ -287,9 +294,11 @@ function card(p){
       ${kv('DW SKU',p.dw_sku)}${kv('Vendor SKU',p.sku)}${kv('Pattern',p.series)}${kv('Book',p.book)}
       ${kv('Style',p.style)}${kv('Colorway',p.color)}${kv('Width',p.width)}${kv('Repeat',p.repeat)}
       <div class="acts">
+        <button class="act" data-act="memo"  title="Log a memo-sample request">Memo</button>
+        <button class="act" data-act="stock" title="Email the vendor a stock check">Stock</button>
+        <button class="act" data-act="price" title="Email the vendor for current price">Price</button>
         ${p.sku?`<button class="act" data-copy="${esc(p.sku)}" onclick="copyTxt(this)" title="copy vendor SKU">📋 SKU</button>`:''}
         ${p.dw_sku?`<button class="act" data-copy="${esc(p.dw_sku)}" onclick="copyTxt(this)" title="copy DW SKU">📋 DW</button>`:''}
-        <button class="act" onclick="__openInquiry('${esc(p.inquiry_sku||p.dw_sku||p.sku)}','${esc((p.series||'')+(p.color?(' — '+p.color):''))}')" title="request a memo sample">✉ Memo</button>
         <a class="lnk" href="/product/${encodeURIComponent(p.handle)}">open ↗</a>
       </div>
     </div>
@@ -314,6 +323,26 @@ function copyTxt(btn){
   });
 }
 window.copyTxt=copyTxt;
+// ── Purchasing actions on each card: Memo / Stock / Price → /api/request ──
+grid.addEventListener('click', async (e)=>{
+  const btn=e.target.closest('.act[data-act]'); if(!btn) return;
+  e.stopPropagation();
+  const c=btn.closest('.card'); const type=btn.dataset.act;
+  const payload={ type, dw_sku:c.dataset.sku, mfr_sku:c.dataset.mfr, title:c.dataset.title };
+  const old=btn.textContent; btn.disabled=true; btn.textContent='…';
+  try{
+    const r=await fetch(location.origin+'/api/request',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(r=>r.json());
+    toast(r.ok ? (r.message||('Logged '+(r.req_no||''))) : (r.error||'request failed'), !!r.ok);
+  }catch(err){ toast('request failed: '+err.message, false); }
+  btn.disabled=false; btn.textContent=old;
+});
+let toastT=null;
+function toast(msg, ok){
+  let t=document.getElementById('toast');
+  if(!t){ t=document.createElement('div'); t.id='toast'; document.body.appendChild(t); }
+  t.textContent=msg; t.className='show '+(ok?'ok':'err');
+  clearTimeout(toastT); toastT=setTimeout(()=>t.className='',6000);
+}
 // color sort key — white/grey/black first (by value), then chromatic by hue
 function colorKey(p){
   const b=p.color_bucket, hue=p.hue??999;

← d7714e5 chore: lint, refactor, v0.2.3 (session close)  ·  back to Reidwitlin Landing  ·  (newest)