[object Object]

← back to Dw Activation Calendar

Google Calendar tab: fall back to SKU activation rollout when OAuth not connected (no more blank grid)

a3d864f2a6afd5abb260a1c20ef5c6d6547f79e0 · 2026-06-24 14:37:30 -0700 · Steve

Files touched

Diff

commit a3d864f2a6afd5abb260a1c20ef5c6d6547f79e0
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jun 24 14:37:30 2026 -0700

    Google Calendar tab: fall back to SKU activation rollout when OAuth not connected (no more blank grid)
---
 public/index.html | 38 +++++++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/public/index.html b/public/index.html
index fd6ac9b..3e2a305 100644
--- a/public/index.html
+++ b/public/index.html
@@ -210,6 +210,7 @@
 <!-- ====================== GOOGLE CALENDAR VIEW ====================== -->
 <div class="view" id="view-gcal">
   <div class="banner hidden" id="gbanner"></div>
+  <div class="note" id="gfallnote" style="display:none;margin:14px 0 0">Showing the <b>SKU activation rollout</b> below until the Google Calendar is connected — these are scheduled product go-lives, not calendar events. They become editable Google events once Steve authorizes.</div>
   <div class="monthbar">
     <button class="nav" id="gprev" aria-label="Previous month">‹</button>
     <div class="ml" id="gmlabel">—</div>
@@ -292,10 +293,31 @@ async function refreshStatus(){
       '<a href="/api/oauth/start"><button class="btn-primary">Connect</button></a>';
   }
 }
+// Fallback content for the Google tab when OAuth isn't connected: the SKU
+// activation rollout. Kept in its own var (NOT DATA) so the SKU tab still
+// lazy-loads itself via setTab's `!DATA` guard.
+let GSCHED=null;
+async function ensureSched(){
+  if(GSCHED) return GSCHED;
+  try{ GSCHED=await (await fetch('/api/schedule?perDay=500&perVendorDay=500')).json(); }
+  catch(e){ GSCHED={days:[]}; }
+  return GSCHED;
+}
 async function loadGcal(){
   await refreshStatus();
   if(!gMonth){const n=new Date();gMonth=new Date(n.getFullYear(),n.getMonth(),1);}
   document.getElementById('gmlabel').textContent=fmtMonth(gMonth);
+  const fallNote=document.getElementById('gfallnote');
+  if(!GSTATUS.connected){
+    // Never show a blank grid: surface the SKU rollout as read-only fallback
+    // (the "Steve must authorize" banner stays on top). Month nav re-renders it.
+    fallNote.style.display='';
+    document.getElementById('gcal').innerHTML='<div class="loading">Loading rollout…</div>';
+    await ensureSched();
+    renderSchedMonth('gcal', gMonth, GSCHED);
+    return;
+  }
+  fallNote.style.display='none';
   document.getElementById('gcal').innerHTML='<div class="loading">Loading events…</div>';
   const y=gMonth.getFullYear(), m=gMonth.getMonth();
   const timeMin=new Date(y,m,1).toISOString(), timeMax=new Date(y,m+1,0,23,59,59).toISOString();
@@ -464,11 +486,13 @@ function renderLegend(){
   document.getElementById('legend').innerHTML=top.map(([v,n])=>
     `<span class="li"><span class="sw" style="background:${vcolor(v)}"></span>${v} <span style="color:var(--ink)">${n.toLocaleString()}</span></span>`).join('');
 }
-function renderMonth(){
-  const byDate={}; DATA.days.forEach(d=>byDate[d.date]=d);
-  const y=viewMonth.getFullYear(), m=viewMonth.getMonth();
-  document.getElementById('mlabel').textContent=fmtMonth(viewMonth);
-  const cal=document.getElementById('cal'); cal.className='cal'; cal.innerHTML='';
+/* Generic SKU-schedule month grid — shared by the SKU Activation tab AND the
+   Google Calendar tab's not-connected fallback (renders into any container). */
+function renderSchedMonth(containerId, monthDate, data){
+  const cal=document.getElementById(containerId); cal.className='cal'; cal.innerHTML='';
+  if(!data||!data.days){ cal.innerHTML='<div class="loading">No schedule.</div>'; return; }
+  const byDate={}; data.days.forEach(d=>byDate[d.date]=d);
+  const y=monthDate.getFullYear(), m=monthDate.getMonth();
   const dowRow=document.createElement('div'); dowRow.className='dow-row';
   ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'].forEach(d=>{const h=document.createElement('div');h.className='dow';h.textContent=d;dowRow.appendChild(h);});
   cal.appendChild(dowRow);
@@ -502,6 +526,10 @@ function renderMonth(){
   const totalCells=startDow+days; const trail=(7-(totalCells%7))%7;
   for(let dn=1;dn<=trail;dn++){ grid.appendChild(outCell(dn)); }
 }
+function renderMonth(){
+  document.getElementById('mlabel').textContent=fmtMonth(viewMonth);
+  renderSchedMonth('cal', viewMonth, DATA);
+}
 document.getElementById('prev').onclick=()=>{viewMonth=new Date(viewMonth.getFullYear(),viewMonth.getMonth()-1,1);renderMonth();};
 document.getElementById('next').onclick=()=>{viewMonth=new Date(viewMonth.getFullYear(),viewMonth.getMonth()+1,1);renderMonth();};
 document.getElementById('apply').onclick=load;

← b585adf Default calendar to populated SKU Activation tab on first lo  ·  back to Dw Activation Calendar  ·  Fix Connect button: don't navigate to /api/oauth/start when b6aac04 →