'use client'; import { useEffect } from 'react'; const APP_VERSION = '2026-06-14-ux-realtime-v3'; const APP_VERSION_KEY = 'fifa2026-app-version'; function toUint8Array(base64: string): Uint8Array { const padding = '='.repeat((4 - (base64.length % 4)) % 4); const base64Safe = (base64 + padding).replace(/-/g, '+').replace(/_/g, '/'); const raw = atob(base64Safe); const buffer = new ArrayBuffer(raw.length); const out = new Uint8Array(buffer); for (let i = 0; i < raw.length; i += 1) { out[i] = raw.charCodeAt(i); } return out; } export function PwaBootstrap() { useEffect(() => { if (typeof window === 'undefined' || !('serviceWorker' in navigator)) { return; } const setup = async () => { try { const previousVersion = window.localStorage.getItem(APP_VERSION_KEY); const shouldPurgeOldCache = previousVersion !== APP_VERSION; if (shouldPurgeOldCache && 'caches' in window) { const keys = await caches.keys(); await Promise.all(keys.filter((key) => key.startsWith('wc2026-') || key.includes('fifa2026')).map((key) => caches.delete(key))); window.localStorage.setItem(APP_VERSION_KEY, APP_VERSION); } const registration = await navigator.serviceWorker.register(`/sw.js?v=${APP_VERSION}`); await registration.update(); registration.active?.postMessage({ type: 'app-version', version: APP_VERSION }); registration.waiting?.postMessage({ type: 'skip-waiting' }); if (Notification.permission === 'granted') { const vapid = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY; if (vapid) { const existing = await registration.pushManager.getSubscription(); if (!existing) { await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: toUint8Array(vapid), }); } } } navigator.serviceWorker.addEventListener('message', (event) => { const payload = event.data; if (payload?.type === 'push-trigger') { console.log('PWA push message', payload); } }); } catch (error) { console.warn('PWA bootstrap 失敗', error); } }; void setup(); }, []); return null; }