The banquet menu (18 dishes) and extras/supplies/delivery items (16) in the training catalog were seeded with photo:'', which the catalog tiles render as a plain red placeholder square. Sourced a real photo for each item (mostly Pexels, free license, picked and visually reviewed one by one to avoid mismatches -- several first search hits were wrong: a live chicken for "chicken caesar salad", a person in frame, branded bottles/cups) and two AI-generated (banquet-caprese, banquet-roastbeef). Converted to square 1024x1024 WebP with sharp. Wires the paths through the actual source of truth: ops/demo/trial- banquet-data.mjs and trial-extras-data.mjs now set photo to the real path, then ops/demo/build-trial-*.mjs regenerated public/demo/*.json and the matching Supabase seed-function migrations, so the client's static JSON fetch and the server-side company-provisioning function stay in sync. Bumped the demo-catalog fetch's own cache-busting query string in training-catalog.js (and its script-tag/precache version), since it's fetched by the client with a separate version from the outer script tags -- the same stale-cache class of bug fixed earlier this session. Verified: all 34 referenced files resolve (200) and decode as real 1024x1024 images; confirmed via the actual rendered catalog tiles (#tiles img[src]) that the extras category -- where the user's red-square screenshot was taken -- now serves the real photo paths. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
68 lines
5.5 KiB
JavaScript
68 lines
5.5 KiB
JavaScript
const CACHE='sun-catering-pwa-v110-20260918-ui-stability-20260919-client-menu-support-bot-training-catalog-banquet-onepage-employee-session-mfa-recovery-promo-entry-support-mail-correct-recipient';
|
|
const VERSION='20260918-ui-stability';
|
|
const CORE=[
|
|
'./core/support-form.js?v=20260921-support-recipient',
|
|
'./core/trial-promo-developer-v181.js?v=20260921-promo-entry',
|
|
'./core/banquet-client-menu.js?v=20260920-onepage',
|
|
'./core/training-catalog.js?v=20260922-training-photos',
|
|
'./core/catalog-pricing.js?v=20260919-client-menu','./core/client-menu.css?v=20260919-client-menu',
|
|
'./vendor/supabase-2.112.4.min.js',
|
|
`./core/help-center.js?v=${VERSION}`,`./core/help-center.css?v=${VERSION}`,`./help/knowledge-v1.json?v=${VERSION}`,
|
|
'./','./index.html',`./core/mobile-order.js?v=${VERSION}`,`./core/proposal-layout.js?v=${VERSION}`,'./fonts/Manrope.ttf','./fonts/PlayfairDisplay.ttf','./fonts/PlayfairDisplay-Italic.ttf',`./core/trial-demo.js?v=${VERSION}`,`./core/cloud-transport.js?v=${VERSION}`,`./core/banquet-menu.js?v=${VERSION}`,`./core/access-policy.js?v=${VERSION}`,`./core/import-archive.js?v=${VERSION}`,`./core/company-branding.js?v=${VERSION}`,`./core/signature-offer-pdf-v18.js?v=${VERSION}`,`./core/brand-theme.js?v=${VERSION}`,
|
|
`./core/sun-safe.js?v=${VERSION}`,`./core/performance.js?v=${VERSION}`,`./core/account-center-v1780.js?v=${VERSION}`,`./core/login-signature-v1776.js?v=${VERSION}`,`./core/login-signature-v1776.css?v=${VERSION}`,`./core/data-layer-v1773.js?v=${VERSION}`,`./core/server-automation-v1770.js?v=${VERSION}`,`./core/hotfix-v1763.js?v=${VERSION}`,`./core/ops-ux-v1762.js?v=${VERSION}`,`./core/ux-fixes-v1764.js?v=${VERSION}`,`./core/pdf-engine.js?v=${VERSION}`,`./core/classic-offer-pdf-v1767.js?v=${VERSION}`,`./core/developer-console-v1768.js?v=${VERSION}`,`./core/offer-workspace-v1769.js?v=${VERSION}`,`./core/auth-security-v1774.js?v=${VERSION}`,`./core/order-enhancements-v1775.js?v=${VERSION}`,`./legacy/bootstrap.js?v=${VERSION}`,`./app-runtime.js?v=${VERSION}`,
|
|
'./offer-gallery/001.jpg','./offer-gallery/002.jpg',
|
|
'./catalog/001.jpg','./catalog/002.jpg','./catalog/003.jpg',
|
|
'./sun-logo.png','./caterium-login-logo.png','./caterium-mark-light.svg','./pwa-icon-192.png','./pwa-icon-512.png','./manifest.webmanifest',
|
|
'./offer-templates/thumb-light.jpg','./offer-templates/thumb-editorial-grid.jpg','./offer-templates/thumb-midnight-glass.jpg','./offer-templates/thumb-emerald-gold.jpg'
|
|
];
|
|
const CRITICAL_FRESH=new Set([
|
|
'/core/support-form.js',
|
|
'/core/trial-promo-developer-v181.js','/core/hotfix-v1763.js',
|
|
'/core/banquet-client-menu.js',
|
|
'/core/training-catalog.js',
|
|
'/core/catalog-pricing.js','/core/client-menu.css',
|
|
'/core/help-center.js','/core/help-center.css','/help/knowledge-v1.json',
|
|
'/core/mobile-order.js','/core/cloud-transport.js','/core/trial-demo.js','/core/proposal-layout.js',
|
|
'/core/banquet-menu.js','/core/access-policy.js','/core/import-archive.js','/core/company-branding.js','/core/brand-theme.js','/core/sun-safe.js','/core/performance.js','/core/account-center-v1780.js','/core/login-signature-v1776.js','/core/login-signature-v1776.css','/core/auth-security-v1774.js','/legacy/bootstrap.js','/app-runtime.js'
|
|
]);
|
|
self.addEventListener('install',event=>{
|
|
event.waitUntil(caches.open(CACHE).then(cache=>cache.addAll(CORE)).then(()=>self.skipWaiting()));
|
|
});
|
|
self.addEventListener('activate',event=>{
|
|
event.waitUntil(caches.keys().then(keys=>Promise.all(keys.filter(k=>k.startsWith('sun-catering-pwa-')&&k!==CACHE).map(k=>caches.delete(k)))).then(()=>self.clients.claim()));
|
|
});
|
|
function cachePut(req,res){
|
|
if(res&&res.ok){const clone=res.clone();caches.open(CACHE).then(c=>c.put(req,clone)).catch(()=>{});}return res;
|
|
}
|
|
function networkFirst(req,fallback){
|
|
return fetch(req,{cache:'no-store'}).then(res=>cachePut(req,res)).catch(()=>caches.match(req).then(hit=>hit||caches.match(fallback||req)));
|
|
}
|
|
function forceFresh(req){
|
|
const url=new URL(req.url);url.searchParams.set('__caterium_release',VERSION);
|
|
return fetch(url.toString(),{cache:'no-store',credentials:'same-origin'}).then(res=>cachePut(req,res)).catch(()=>caches.match(req));
|
|
}
|
|
self.addEventListener('fetch',event=>{
|
|
const req=event.request;if(req.method!=='GET')return;
|
|
const url=new URL(req.url);if(url.origin!==self.location.origin||url.pathname.startsWith('/api/'))return;
|
|
// Static PNGs can bypass Apache rewrites on the production host. Resolve old
|
|
// catalog/editor/document URLs here too, before checking the original cache.
|
|
if(/^\/demo\/images\/(?:berry-dessert|bruschetta-tomato|caprese|cheese-fruit|chicken-sandwich|meat-assortment|mushroom-tartlet|salmon-cream|turkey-wrap|vegetables-hummus)\.png$/.test(url.pathname)){
|
|
url.pathname=url.pathname.replace(/\.png$/,'.webp');
|
|
const optimized=new Request(url.toString(),{credentials:'same-origin'});
|
|
event.respondWith(caches.match(optimized).then(hit=>hit||fetch(optimized).then(res=>res.ok?cachePut(optimized,res):fetch(req))));
|
|
return;
|
|
}
|
|
if(req.mode==='navigate'){
|
|
event.respondWith(
|
|
fetch(req,{cache:'no-store'})
|
|
.then(res=>{const clone=res.clone();caches.open(CACHE).then(c=>c.put('./index.html',clone)).catch(()=>{});return res;})
|
|
.catch(()=>caches.match('./index.html'))
|
|
);
|
|
return;
|
|
}
|
|
if(CRITICAL_FRESH.has(url.pathname)){event.respondWith(forceFresh(req));return;}
|
|
const freshAsset=/\.(?:js|css|webmanifest)$/i.test(url.pathname);
|
|
if(freshAsset){event.respondWith(networkFirst(req));return;}
|
|
event.respondWith(caches.match(req).then(cached=>cached||fetch(req,{cache:'no-store'}).then(res=>cachePut(req,res))));
|
|
});
|