view mrjunejune/src/public/pwa-register.js @ 264:04fee26ecce0

add authenticated JRPG conversation platform Add reusable auth/session storage, owned conversation recovery, guest quotas, admin workflows, URL-routed conversation UI, mobile frame support, and parallel browser acceptance. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 07:34:12 -0700
parents 60a876c4587a
children e02e2036ef84
line wrap: on
line source

// PWA Service Worker Registration
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/sw.js', { scope: '/' })
      .then((registration) => {
        // console.log('[PWA] Service Worker registered:', registration.scope);

        // Check for updates periodically
        setInterval(() => {
          registration.update();
        }, 60000); // Check every minute

        // Handle updates
        registration.addEventListener('updatefound', () => {
          const newWorker = registration.installing;
          newWorker.addEventListener('statechange', () => {
            if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
              // New content available, show update notification
              if (confirm('New version available! Reload to update?')) {
                newWorker.postMessage({ type: 'SKIP_WAITING' });
                window.location.reload();
              }
            }
          });
        });
      })
      .catch((error) => {
        console.error('[PWA] Service Worker registration failed:', error);
      });

    // Handle service worker updates
    let refreshing = false;
    navigator.serviceWorker.addEventListener('controllerchange', () => {
      if (!refreshing) {
        refreshing = true;
        window.location.reload();
      }
    });
  });
}

// Add install prompt handler
let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  deferredPrompt = e;

  showInstallPromotion();
});

function showInstallPromotion() {
  // Create an install button if it doesn't exist
  if (document.getElementById('pwa-install-btn')) return;

  const installBtn = document.createElement('button');
  installBtn.classList.add('with-icon');
  installBtn.id = 'pwa-install-btn';
  const installIcon = document.createElement('zen-icon');
  installIcon.setAttribute('name', 'download');
  const installLabel = document.createElement('span');
  installLabel.textContent = 'Install as App';
  installBtn.append(installIcon, installLabel);

  installBtn.addEventListener('click', async () => {
    if (!deferredPrompt) return;

    deferredPrompt.prompt();
    const { outcome } = await deferredPrompt.userChoice;
    console.log(`[PWA] User response: ${outcome}`);

    deferredPrompt = null;
    installBtn.remove();
  });

  const wrapper = document.createElement('zen-button');
  wrapper.setAttribute('appearance', 'plain');
  wrapper.setAttribute('size', 'md');
  wrapper.append(installBtn);
  document.body.appendChild(wrapper);

  setTimeout(() => {
    installBtn.style.opacity = '0';
    installBtn.style.transition = 'opacity 0.3s';
    setTimeout(() => wrapper.remove(), 300);
  }, 5000);
}

window.addEventListener('appinstalled', () => {
  console.log('[PWA] App installed successfully!');
  deferredPrompt = null;

  const installBtn = document.getElementById('pwa-install-btn');
  if (installBtn) installBtn.closest('zen-button')?.remove();
});