mirror of
https://github.com/cupcakearmy/obolus.git
synced 2024-12-21 23:56:32 +00:00
service worker
This commit is contained in:
parent
4b566cce32
commit
c299177f2c
@ -1,19 +1,31 @@
|
||||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import Head from 'next/head'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { logout } from '../utils/auth'
|
||||
import { getRandomSlogan } from '../utils/misc'
|
||||
import { editableWhenOnline } from '../utils/hooks'
|
||||
|
||||
|
||||
const Layout = ({ children }) => {
|
||||
const title = getRandomSlogan()
|
||||
|
||||
const online = typeof window !== 'undefined'
|
||||
? editableWhenOnline()
|
||||
: true
|
||||
|
||||
useEffect(() => {
|
||||
if (window && 'navigator' in window && 'serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js')
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <React.Fragment>
|
||||
<Head>
|
||||
<title>{title}</title>
|
||||
|
||||
{/* https://www.flaticon.com/packs/zoo-20 */}
|
||||
<link rel="stylesheet" href="/static/css/spectre.min.css"/>
|
||||
<link rel="stylesheet" href="/static/css/spectre-exp.min.css"/>
|
||||
<link rel="stylesheet" href="/static/css/spectre-icons.min.css"/>
|
||||
@ -70,12 +82,21 @@ const Layout = ({ children }) => {
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{!online && <div id="msg-offline" className="bg-dark text-center p-2">Offline</div>}
|
||||
|
||||
{/* language=CSS */}
|
||||
<style jsx>{`
|
||||
main {
|
||||
padding: 6em 0;
|
||||
}
|
||||
|
||||
#msg-offline {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
#navbar-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -22,7 +22,9 @@ app.prepare().then(() => {
|
||||
const parsedUrl = parse(req.url, true)
|
||||
const { pathname } = parsedUrl
|
||||
|
||||
if (pathname.startsWith('/api/'))
|
||||
if (pathname === '/sw.js')
|
||||
handle(req, res, parse('/static/sw.js', true))
|
||||
else if (pathname.startsWith('/api/'))
|
||||
proxy.web(req, res, { target }, error => console.log('Error!', error))
|
||||
else
|
||||
handle(req, res, parsedUrl)
|
||||
|
74
www/static/sw.js
Normal file
74
www/static/sw.js
Normal file
@ -0,0 +1,74 @@
|
||||
const VERSION = 1
|
||||
const CACHE = `cache:obolus:${VERSION}`
|
||||
|
||||
const getCache = () => self.caches.open(CACHE)
|
||||
|
||||
const getPathFromUrl = url => url.replace(/^https?:\/\/[^\/]+/, '')
|
||||
|
||||
const _default = {
|
||||
ttl: 24 * 60 * 60,
|
||||
methods: ['GET'],
|
||||
}
|
||||
|
||||
const NetworkFirst = () => event => new Promise(async (resolve, reject) => {
|
||||
const cache = await getCache()
|
||||
try {
|
||||
const response = await fetch(event.request)
|
||||
if (_default.methods.includes(event.request.method))
|
||||
cache.put(event.request, response.clone())
|
||||
resolve(response)
|
||||
} catch (e) {
|
||||
const cached = await cache.match(event.request)
|
||||
resolve(cached)
|
||||
}
|
||||
})
|
||||
|
||||
const NetworkOnly = () => event => new Promise(async (resolve, reject) => {
|
||||
const cache = await getCache()
|
||||
const response = await fetch(event.request)
|
||||
cache.put(event.request, response.clone())
|
||||
resolve(response)
|
||||
})
|
||||
|
||||
const CacheFirst = () => event => new Promise(async (resolve, reject) => {
|
||||
const cache = await getCache()
|
||||
const cached = await cache.match(event.request)
|
||||
if (cached) resolve(cached)
|
||||
else {
|
||||
const response = await fetch(event.request)
|
||||
cache.put(event.request, response.clone())
|
||||
resolve(response)
|
||||
}
|
||||
})
|
||||
|
||||
const CacheOnly = () => event => new Promise(async (resolve, reject) => {
|
||||
const cache = await getCache()
|
||||
const cached = await cache.match(event.request)
|
||||
resolve(cached)
|
||||
})
|
||||
|
||||
const Rolling = () => event => {
|
||||
}
|
||||
|
||||
const routes = [
|
||||
{
|
||||
match: /^\/api\//,
|
||||
handler: NetworkFirst(),
|
||||
},
|
||||
{
|
||||
match: /^\/static\/icons\//,
|
||||
handler: CacheFirst(),
|
||||
},
|
||||
{
|
||||
match: /.*/,
|
||||
handler: NetworkFirst(),
|
||||
},
|
||||
]
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
const path = getPathFromUrl(event.request.url)
|
||||
const route = routes.find(route => route.match.test(path))
|
||||
if (route) {
|
||||
event.respondWith(route.handler(event))
|
||||
}
|
||||
})
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
|
||||
export const useLocalStorageWatcher = (fn) => {
|
||||
@ -9,4 +9,28 @@ export const useLocalStorageWatcher = (fn) => {
|
||||
window.removeEventListener('storage', fn)
|
||||
}
|
||||
}, [])
|
||||
}
|
||||
|
||||
export const editableWhenOnline = () => {
|
||||
const [online, setOnline] = useState(window.navigator.onLine)
|
||||
|
||||
useEffect(() => {
|
||||
const onlineHandler = () => setOnline(true)
|
||||
const offlineHandler = () => setOnline(false)
|
||||
window.addEventListener('online', onlineHandler)
|
||||
window.addEventListener('offline', offlineHandler)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('online', onlineHandler)
|
||||
window.removeEventListener('offline', offlineHandler)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const elements = window.document.querySelectorAll('input, button')
|
||||
for (const element of elements)
|
||||
element.disabled = !online
|
||||
}, [online])
|
||||
|
||||
return online
|
||||
}
|
Loading…
Reference in New Issue
Block a user