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