mirror of
https://github.com/cupcakearmy/obolus.git
synced 2024-12-22 16:16:27 +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 Head from 'next/head'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
import { logout } from '../utils/auth'
|
import { logout } from '../utils/auth'
|
||||||
import { getRandomSlogan } from '../utils/misc'
|
import { getRandomSlogan } from '../utils/misc'
|
||||||
|
import { editableWhenOnline } from '../utils/hooks'
|
||||||
|
|
||||||
|
|
||||||
const Layout = ({ children }) => {
|
const Layout = ({ children }) => {
|
||||||
const title = getRandomSlogan()
|
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>
|
return <React.Fragment>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{title}</title>
|
<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.min.css"/>
|
||||||
<link rel="stylesheet" href="/static/css/spectre-exp.min.css"/>
|
<link rel="stylesheet" href="/static/css/spectre-exp.min.css"/>
|
||||||
<link rel="stylesheet" href="/static/css/spectre-icons.min.css"/>
|
<link rel="stylesheet" href="/static/css/spectre-icons.min.css"/>
|
||||||
@ -70,12 +82,21 @@ const Layout = ({ children }) => {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
{!online && <div id="msg-offline" className="bg-dark text-center p-2">Offline</div>}
|
||||||
|
|
||||||
{/* language=CSS */}
|
{/* language=CSS */}
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
main {
|
main {
|
||||||
padding: 6em 0;
|
padding: 6em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#msg-offline {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
#navbar-container {
|
#navbar-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -22,7 +22,9 @@ app.prepare().then(() => {
|
|||||||
const parsedUrl = parse(req.url, true)
|
const parsedUrl = parse(req.url, true)
|
||||||
const { pathname } = parsedUrl
|
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))
|
proxy.web(req, res, { target }, error => console.log('Error!', error))
|
||||||
else
|
else
|
||||||
handle(req, res, parsedUrl)
|
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) => {
|
export const useLocalStorageWatcher = (fn) => {
|
||||||
@ -10,3 +10,27 @@ export const useLocalStorageWatcher = (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