[object Object]

โ† back to Rentv

feat(deals-admin): show record created date+time on each deal card (Steve admin-card rule) โ€” join registry first_seen as created_at in /api/deals-manage + '๐Ÿ•“ Added <date, time>' chip via toLocaleString

97b029c8152568531c81308f110176b3a4f6e482 ยท 2026-08-06 08:19:55 -0700 ยท Steve

Files touched

Diff

commit 97b029c8152568531c81308f110176b3a4f6e482
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Aug 6 08:19:55 2026 -0700

    feat(deals-admin): show record created date+time on each deal card (Steve admin-card rule) โ€” join registry first_seen as created_at in /api/deals-manage + '๐Ÿ•“ Added <date, time>' chip via toLocaleString
---
 public/deals.html |  4 ++++
 server.js         | 12 ++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/public/deals.html b/public/deals.html
index a20c65a3..fc824ced 100644
--- a/public/deals.html
+++ b/public/deals.html
@@ -61,6 +61,7 @@
   .card h3{font-size:13px;color:var(--sub);font-weight:600;line-height:1.35}
   .card .meta{font-size:12px;color:var(--sub);font-weight:600;display:flex;flex-wrap:wrap;gap:4px 10px}
   .card .meta b{color:var(--ink)}
+  .card .when{font-size:11px;color:var(--sub);font-weight:600;letter-spacing:.02em}
   .card .meta.parties{font-size:11px;gap:3px 8px}
   .card .meta.parties span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}
   .drill{cursor:pointer}.badge.drill:hover{filter:brightness(1.25)}.card .meta .drill:hover{text-decoration:underline;color:var(--red)}
@@ -213,6 +214,8 @@ function dateOf(d){
   const m=String(d.image||'').match(/([A-Z][a-z]+?)(\d{1,2})(\d{4})\.(?:jpg|jpeg|png|webp)/);if(!m)return null;const mo=MONTHS[m[1].slice(0,3)];if(mo==null)return null;return new Date(Date.UTC(+m[3],mo,+m[2]));
 }
 const fmtDate=dt=>dt?dt.toLocaleDateString(undefined,{month:'short',day:'numeric',year:'numeric'}):'';
+// Admin-card rule: show the RECORD's created date AND time (when RENTV first captured it) in local tz.
+const fmtDateTime=iso=>{if(!iso)return'';const dt=new Date(iso);return isNaN(dt)?'':dt.toLocaleString(undefined,{month:'short',day:'numeric',year:'numeric',hour:'numeric',minute:'2-digit'});};
 const isManual=d=>d._manual||String(d.id||'').startsWith('md');
 
 function pillRow(hostId,list,cur,pick){
@@ -268,6 +271,7 @@ function render(){
         ${loc?`<div class="meta"><span class="drill" data-filt="q" data-val="${esc(loc)}" title="Filter by ${esc(loc)}">๐Ÿ“ <b>${esc(loc)}</b></span>${d.size_label?`<span>๐Ÿ“ ${esc(d.size_label)}</span>`:''}${d.year_built?`<span>๐Ÿ— ${esc(d.year_built)}</span>`:''}</div>`:''}
         ${(d.buyer||d.seller||d.broker)?`<div class="meta parties">${d.buyer?`<span class="drill" data-filt="q" data-val="${esc(d.buyer)}" title="Buyer โ€” filter by ${esc(d.buyer)}">๐ŸŸข <b>${esc(d.buyer)}</b></span>`:''}${d.seller?`<span class="drill" data-filt="q" data-val="${esc(d.seller)}" title="Seller โ€” filter by ${esc(d.seller)}">๐Ÿ”ด ${esc(d.seller)}</span>`:''}${d.broker?`<span class="drill" data-filt="q" data-val="${esc(d.broker)}" title="Broker โ€” filter by ${esc(d.broker)}">๐Ÿค ${esc(d.broker)}</span>`:''}</div>`:''}
         ${(d.address&&d.title)?`<h3>${esc(d.title)}</h3>`:''}
+        ${d.created_at?`<div class="when" title="${esc(d.created_at)}">๐Ÿ•“ Added ${esc(fmtDateTime(d.created_at))}</div>`:''}
         <div class="cardfoot">
           ${story}
           <div class="acts">
diff --git a/server.js b/server.js
index 45b63249..0baf851a 100644
--- a/server.js
+++ b/server.js
@@ -136,6 +136,7 @@ function adminOnly(req, res, next) {
 // </body>. Used by every explicit page route AND the static HTML injector below, so the
 // toggle is present site-wide from a single include (the widget self-hides for user-tier).
 const TOGGLE_TAG = '<script src="/toggle.js" defer></script>';
+const NAV_TAG = '<script src="/rentv-nav.js" defer></script>'; // rentv.com region+category tab panel (TK-10278), public pages only
 // User-facing day/night toggle (sun/moon icon, bottom-right), shown site-wide to EVERY
 // visitor. DAYNIGHT_TAG mounts the button; DAYNIGHT_PREAPPLY runs inline in <head> to set
 // the dark CSS vars before first paint so night mode never flashes white (FOUC guard).
@@ -177,6 +178,12 @@ function sendPage(res, absFile) {
   if (html.indexOf('/toggle.js') === -1) {
     html = closeBody() ? html.replace('</body>', TOGGLE_TAG + '</body>') : html + TOGGLE_TAG;
   }
+  // rentv.com region+category tab panel (TK-10278) โ€” inject on PUBLIC pages only (skip admin/internal
+  // tools via INTERNAL_PAGE, same gate the public footer uses). The script self-mounts to whatever
+  // header/nav the page has and bails on chrome-less pages, so this is safe site-wide.
+  if (!INTERNAL_PAGE.test(absFile) && html.indexOf('/rentv-nav.js') === -1) {
+    html = closeBody() ? html.replace('</body>', NAV_TAG + '</body>') : html + NAV_TAG;
+  }
   // Day/night toggle for all visitors: FOUC pre-apply in <head>, button before </body>.
   if (html.indexOf('/daynight.js') === -1) {
     html = html.indexOf('</head>') !== -1 ? html.replace('</head>', DAYNIGHT_PREAPPLY + '</head>') : DAYNIGHT_PREAPPLY + html;
@@ -546,6 +553,9 @@ app.get('/api/deals-manage', adminOnly, (req, r) => {
   const corpusById = new Map(allCorpus.map((a) => [String(a.id), a]));
   const corpusExtra = allCorpus.filter((a) => !feedIds.has(String(a.id)));
   const base = [...feedDeals, ...corpusExtra];
+  // Registry first_seen = when RENTV first captured this deal โ†’ surfaced as created_at so the admin
+  // grid can show the record's created date+time (Steve's admin-card rule; a curate-by-recency aid).
+  const regDeals = readJSON('deals-registry.json', { deals: {} }).deals || {};
   // GAP-FILL each feed row from its matching corpus article (never overwrite a field the feed already
   // has) so buyer/seller/broker/summary surface here too โ€” mirrors /api/closings (TK-10254). The
   // deals-pull feed carries image/price but NOT the LLM-extracted party/summary fields (corpus-only).
@@ -558,6 +568,8 @@ app.get('/api/deals-manage', adminOnly, (req, r) => {
     const row = e ? { ...d2, ...e, _edited: true } : { ...d2 };
     row._hidden = hides.has(String(d.id));
     row._corpus = feedIds.has(String(d.id)) ? undefined : true;
+    const reg = regDeals[String(d.id)];
+    row.created_at = row.created_at || (reg && reg.first_seen) || null; // when RENTV first captured it
     return row;
   }).filter((d) => includeHidden || !d._hidden);
   const adds = (ov.adds || []).map((a) => ({ ...a, _manual: true }));

โ† ba45532d Add rentv.com region+category tab panel + /region/:slug land  ยท  back to Rentv  ยท  auto-save: 2026-08-06T08:19:59 (6 files) โ€” data/deals-regist 0ece69ca โ†’