import type { Component } from 'solid-js' import type { DivProps } from '../ui/utils-ui' import { Logger } from 'besonders-logger' import { createEffect, createSignal, Match, Show, Switch } from 'solid-js' import { useRegisterSW } from 'virtual:pwa-register/solid' import { createAsyncButtonHandler } from '../ui/utils-ui' import { Iconify } from './mini-components' const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO, { prefix: '[SW]' }) const [pwaReloadFuncSignal, setPwaReloadFunc] = createSignal<(reload: boolean) => Promise>(null) const [pwaUpdateFuncSignal, setPwaUpdateFunc] = createSignal<() => Promise>(null) const [pwaUnregisterFuncSignal, setPwaUnregisterFunc] = createSignal<() => Promise>(null) export { pwaReloadFuncSignal, pwaUnregisterFuncSignal, pwaUpdateFuncSignal } async function registerPeriodicWovinSync(swReg: ServiceWorkerRegistration & { periodicSync?: any }) { if (!swReg.periodicSync) return WARN('//TODO firefox friendly way') // @ ts-expect-error periodicSync is still experimental *and chromium only const registeredSyncTags = await swReg.periodicSync.getTags() try { await swReg.periodicSync.register('wovin-do-sync', { minInterval: 24 * 60 * 60 * 1000, }) } catch (e) { console.log('Periodic Sync could not be registered!', e) } } export const PwaReloadPrompt: Component = (restProps) => { // const offlineReady = () => false // (i) for UI testing // const needRefresh = () => true const [reloadStartTime, setReloadStartTime] = createSignal(null) const { offlineReady: [offlineReady, setOfflineReady], needRefresh: [needRefresh, setNeedRefresh], updateServiceWorker, } = useRegisterSW({ onRegisteredSW(swUrl, swReg) { LOG('ServiceWorker registered:', swReg) // @ts-expect-error window.sw = swReg // TODO consider https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/updatefound_event if (swReg) { registerPeriodicWovinSync(swReg) setPwaUnregisterFunc(() => () => swReg.unregister()) setPwaReloadFunc(() => () => swReg.update()) // FROM: https://vite-pwa-org.netlify.app/guide/periodic-sw-updates.html#handling-edge-cases setInterval(async () => { VERBOSE('ServiceWorker update check:', { swReg, installing: swReg.installing, onLine: navigator.onLine }) if (!(!swReg.installing && navigator)) { return } if (('connection' in navigator) && !navigator.onLine) { return } const resp = await fetch(swUrl, { cache: 'no-store', headers: { 'cache': 'no-store', 'cache-control': 'no-cache', }, }) DEBUG('ServiceWorker update check response:', resp) if (resp?.status === 200) { LOG('ServiceWorker 200 response:', resp) await swReg.update() } }, (import.meta.env.DEV ? 1 : 5) * 60 * 1000 /* HACK: 5 minute SW update interval during development */) } }, onRegisterError(error) { ERROR('ServiceWorker registration error', error) }, }) createEffect(() => { setPwaReloadFunc(() => flag => updateServiceWorker(flag)) }) const close = () => { setOfflineReady(false) setNeedRefresh(false) } const reloadButtonProps = createAsyncButtonHandler(async () => { setReloadStartTime(new Date()) // @ts-expect-error const swReg = window.sw LOG('Reloading ServiceWorker:', swReg, updateServiceWorker) await updateServiceWorker(true) LOG('Reloaded ServiceWorker:', swReg) }) DEBUG('ReloadButtonProps:', { reloadButtonProps }) return (
App ready to work offline
New app version available
Reload close()}> Close
{ /*
New content available, click on reload button to update.} when={offlineReady()} > App ready to work offline
*/ } ) }