diff --git a/server/shell.ts b/server/shell.ts index 896590e..3e12776 100644 --- a/server/shell.ts +++ b/server/shell.ts @@ -361,6 +361,9 @@ export function renderShell(opts: ShellOptions): string { if (!isStandalone) return; // Only show update prompt in installed PWA const b = document.getElementById('pwa-update-banner'); if (!b || b.style.display !== 'none') return; + // Hide install banner first if somehow both would show + const ib = document.getElementById('pwa-install-banner'); + if (ib) ib.style.display = 'none'; b.style.display = ''; document.body.classList.add('rspace-banner-visible'); } @@ -382,31 +385,34 @@ export function renderShell(opts: ShellOptions): string { } // Install banner — browser only (not shown in installed PWA) + // Permanently dismissed once closed or installed (localStorage key persists) if (!isStandalone) { + const installDismissed = () => localStorage.getItem('rspace_install_dismissed') === '1'; + const dismissInstall = () => { + const b = document.getElementById('pwa-install-banner'); + if (b) b.style.display = 'none'; + document.body.classList.remove('rspace-banner-visible'); + localStorage.setItem('rspace_install_dismissed', '1'); + }; + window.addEventListener("beforeinstallprompt", (e) => { e.preventDefault(); window.__rspaceInstallPrompt = () => { e.prompt(); return e.userChoice; }; window.dispatchEvent(new CustomEvent("rspace-install-available")); - if (localStorage.getItem('rspace_install_dismissed') !== '1') { + if (!installDismissed()) { const b = document.getElementById('pwa-install-banner'); if (b) { b.style.display = ''; document.body.classList.add('rspace-banner-visible'); } } }); + // User installed via browser UI (not our button) — still dismiss permanently + window.addEventListener("appinstalled", () => { dismissInstall(); }); document.getElementById('pwa-install-btn')?.addEventListener('click', async () => { if (window.__rspaceInstallPrompt) { const choice = await window.__rspaceInstallPrompt(); - if (choice?.outcome === 'accepted') { - document.getElementById('pwa-install-banner').style.display = 'none'; - document.body.classList.remove('rspace-banner-visible'); - localStorage.setItem('rspace_install_dismissed', '1'); - } + if (choice?.outcome === 'accepted') dismissInstall(); } }); - document.getElementById('pwa-install-close')?.addEventListener('click', () => { - document.getElementById('pwa-install-banner').style.display = 'none'; - document.body.classList.remove('rspace-banner-visible'); - localStorage.setItem('rspace_install_dismissed', '1'); - }); + document.getElementById('pwa-install-close')?.addEventListener('click', () => { dismissInstall(); }); } // Update banner button handlers (always wire, shown conditionally above) @@ -546,9 +552,10 @@ export function renderShell(opts: ShellOptions): string { // ── Invite acceptance on page load ── (function() { var params = new URLSearchParams(window.location.search); - var inviteToken = params.get('invite'); + var inviteToken = params.get('inviteToken') || params.get('invite'); if (!inviteToken) return; // Remove token from URL immediately + params.delete('inviteToken'); params.delete('invite'); var newUrl = window.location.pathname + (params.toString() ? '?' + params.toString() : ''); history.replaceState(null, '', newUrl);