← back to Wallco Ai
Hot-or-not + room setting generalized to ALL wallco.ai lines
ed7d4f3de10bae83f4580288c08dd316aa100867 · 2026-05-27 14:06:24 -0700 · Steve Abrams
- /api/admin/drunk/list takes ?category=<line> (was hardwired to drunk samples);
excludes heal derivatives; returns room_mockups.
- drunk-curator.html: line picker (45 lines from /api/admin/curator/collections),
?category= + ?admin= forwarding, title reflects line. Already had hot-or-not
(HOT publishes + auto-renders living-room mockup; NOT → reject+defect registry)
AND a live room setting (flat tile left, wallpaper-on-wall room right).
Verified: designer-zoo-calm 5,626 queue, tile+room both render.
Files touched
M public/admin/drunk-curator.htmlM server.js
Diff
commit ed7d4f3de10bae83f4580288c08dd316aa100867
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed May 27 14:06:24 2026 -0700
Hot-or-not + room setting generalized to ALL wallco.ai lines
- /api/admin/drunk/list takes ?category=<line> (was hardwired to drunk samples);
excludes heal derivatives; returns room_mockups.
- drunk-curator.html: line picker (45 lines from /api/admin/curator/collections),
?category= + ?admin= forwarding, title reflects line. Already had hot-or-not
(HOT publishes + auto-renders living-room mockup; NOT → reject+defect registry)
AND a live room setting (flat tile left, wallpaper-on-wall room right).
Verified: designer-zoo-calm 5,626 queue, tile+room both render.
---
public/admin/drunk-curator.html | 30 +++++++++++++++++++++++++++---
server.js | 15 +++++++++------
2 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/public/admin/drunk-curator.html b/public/admin/drunk-curator.html
index b7a6a70..44d2675 100644
--- a/public/admin/drunk-curator.html
+++ b/public/admin/drunk-curator.html
@@ -40,7 +40,10 @@
</head>
<body>
<header>
- <h1>🔥 Drunk-Animals <small>· Hot or Not · tile + room</small></h1>
+ <h1>🔥 <span id="lineName">Hot or Not</span> <small>· tile + room</small></h1>
+ <select id="coll" title="pick a line" style="background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:4px 9px;font-size:13px;max-width:300px;">
+ <option value="">drunk samples (default)</option>
+ </select>
<div class="stats">
<span>seen <b id="seen">0</b></span><span>🔥 hot <b id="hot">0</b></span>
<span>👎 not <b id="not">0</b></span><span class="streak" id="streak"></span>
@@ -63,6 +66,9 @@
<script>
const $=s=>document.querySelector(s);
+const ADMIN=new URLSearchParams(location.search).get('admin');
+const CATEGORY=new URLSearchParams(location.search).get('category')||'';
+const q=s=>ADMIN?(s+(s.includes('?')?'&':'?')+'admin='+encodeURIComponent(ADMIN)):s;
let QUEUE=[], i=0, hot=0, not=0, streak=0;
function fmtDate(iso){ if(!iso)return''; try{return new Date(iso).toLocaleString(undefined,{month:'short',day:'numeric',hour:'numeric',minute:'2-digit'});}catch{return iso;} }
function flash(e){ const f=$('#flash'); f.textContent=e; f.classList.add('show'); setTimeout(()=>f.classList.remove('show'),250); }
@@ -92,11 +98,29 @@ async function decide(v){
if(i>=QUEUE.length) return; const d=QUEUE[i];
if(v==='hot'){hot++;streak++;flash('🔥');}else{not++;streak=0;flash('👎');}
i++; render();
- try{ await fetch('/api/admin/drunk/decide',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:d.id,verdict:v})}); }catch{}
+ try{ await fetch(q('/api/admin/drunk/decide'),{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:d.id,verdict:v})}); }catch{}
}
document.addEventListener('keydown',e=>{ const k=e.key.toLowerCase();
+ if(e.target.tagName==='SELECT')return;
if(e.key==='ArrowRight'||k==='h')decide('hot'); else if(e.key==='ArrowLeft'||k==='n')decide('not'); });
-(async function(){ const r=await fetch('/api/admin/drunk/list'); QUEUE=(await r.json()).items||[]; render(); })();
+
+// collection picker — switch the hot-or-not queue to any wallco.ai line
+async function loadCollections(){
+ try{
+ const r=await fetch(q('/api/admin/curator/collections')); const cols=(await r.json()).collections||[];
+ const sel=$('#coll');
+ for(const c of cols){
+ const o=document.createElement('option');
+ o.value=c.line; o.textContent=`${c.line} (${c.total})`;
+ if(c.line===CATEGORY) o.selected=true;
+ sel.appendChild(o);
+ }
+ sel.addEventListener('change',()=>{ location.href=q('/admin/drunk-curator?category='+encodeURIComponent(sel.value)); });
+ }catch{}
+}
+if(CATEGORY) $('#lineName').textContent=CATEGORY;
+loadCollections();
+(async function(){ const r=await fetch(q('/api/admin/drunk/list'+(CATEGORY?'?category='+encodeURIComponent(CATEGORY):''))); QUEUE=(await r.json()).items||[]; render(); })();
</script>
</body>
</html>
diff --git a/server.js b/server.js
index 182872c..155bfb1 100644
--- a/server.js
+++ b/server.js
@@ -1143,15 +1143,18 @@ app.get('/admin/drunk-curator', (req, res) => {
app.get('/api/admin/drunk/list', (req, res) => {
if (!isAdmin(req)) return res.status(404).json({ error: 'not found' });
+ // ?category=<line> generalizes hot-or-not to ANY wallco.ai line (default =
+ // the original drunk-sample queue). Sanitized to a safe ILIKE fragment.
+ const cat = String(req.query.category || '').replace(/[^a-zA-Z0-9 ._·-]/g, '').slice(0, 40);
try {
+ const where = cat
+ ? `category ILIKE '%${cat}%' AND is_published=FALSE AND (user_removed IS NULL OR user_removed=FALSE) AND local_path IS NOT NULL`
+ : `(category LIKE 'drunk-animals-sample%' OR category='drunk-animals-replfast' OR ((category LIKE 'drunk%' OR category LIKE 'stoned%') AND notes LIKE '%AUTO_HOT_CANDIDATE%')) AND is_published=FALSE AND (user_removed IS NULL OR user_removed=FALSE) AND local_path IS NOT NULL`;
const rawJson = psqlQuery(
"SELECT COALESCE(json_agg(t ORDER BY t.id), '[]'::json) FROM (" +
- "SELECT id, category, generator, left(prompt,260) AS prompt, created_at " +
- "FROM all_designs " +
- "WHERE (category LIKE 'drunk-animals-sample%' OR category='drunk-animals-replfast' " +
- "OR ((category LIKE 'drunk%' OR category LIKE 'stoned%') AND notes LIKE '%AUTO_HOT_CANDIDATE%')) " +
- "AND is_published=FALSE AND (user_removed IS NULL OR user_removed=FALSE) " +
- "AND local_path IS NOT NULL " +
+ "SELECT id, category, generator, left(prompt,260) AS prompt, created_at, room_mockups " +
+ "FROM all_designs WHERE " + where +
+ " AND local_path NOT LIKE '%midheal_%' AND local_path NOT LIKE '%edgeheal_%' AND local_path NOT LIKE '%smartfix_%'" +
") t;"
);
res.json({ ok: true, items: JSON.parse(rawJson || '[]') });
← 10cd2cf auto-decider TRIAGE mode: flag AUTO_HOT_CANDIDATE (no auto-p
·
back to Wallco Ai
·
drunk-curator (Hot or Not): fix votes silently dropped + sam 7462d55 →