Update frontend to allow requesting and receiving notifications

Includes requesting permissions and adding a basic service worker
as well as re-working and restructuring a bunch of the existing logic
for parsing URL parameters, sending data and adding another form field
This commit is contained in:
Oskar Winkels 2021-06-08 00:49:42 +02:00
parent e521edd62b
commit b8e704c300
Signed by: o.winkels
GPG Key ID: E7484A06E99DAEF1
3 changed files with 145 additions and 19 deletions

View File

@ -13,25 +13,27 @@
'departure': 'I have cleaned my workspace' 'departure': 'I have cleaned my workspace'
} }
var testCheckBox = '<label class="checkbox"><input type="checkbox" name="tested" id="tested"><span>I have been tested negative for COVID in the last 24 hours</span></label>' var testCheckBox = '<label class="checkbox"><input type="checkbox" name="tested" id="tested"><span>I have been tested negative for COVID in the last 24 hours</span></label>'
var editTimeBox = '<label>Departure Date/Time:<input type="datetime-local" name="datetime" id="datetime" required></label>'
function getParams() { function getParams() {
var h = document.location.href var qparams = document.location.search.substr(1)
var qparam = h.split('?')[1] || null if (qparams == "") return {}
if (qparam == null) qparams = qparams.split('&')
return null var qps = {}
var vals = qparam.split('=') for (var qparam of qparams) {
if (vals.length < 2 || !cbt.hasOwnProperty(vals[0])) var vals = qparam.split('=')
return null qps[vals[0]] = vals[1] || null
return {
action: vals[0],
room: vals[1]
} }
// Backwards compat
if (qps.arrival) {qps.action = 'arrival'; qps.room = qps.arrival}
if (qps.departure) {qps.action = 'departure'; qps.room = qps.departure}
return qps
} }
var qp = getParams() var qp = getParams()
</script> </script>
</head> </head>
<body> <body>
<h1><script> <h1><script>
document.write(qp ? (qp.action + "<br>Room " + qp.room) : 'FTracker<br>V1') document.write(qp.action ? (qp.action + "<br>Room " + qp.room) : 'FTracker<br>V1')
</script></h1> </script></h1>
<div id="startpage"> <div id="startpage">
This is a web app to track which people This is a web app to track which people
@ -56,6 +58,10 @@
Full Name:<br> Full Name:<br>
<input type="text" name="name" id="name" placeholder="John Doe" required> <input type="text" name="name" id="name" placeholder="John Doe" required>
</label> </label>
<script>
if (qp.edittime && qp.edittime == 1)
document.write(editTimeBox)
</script>
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" name="agree" id="agree" required> <input type="checkbox" name="agree" id="agree" required>
<span><script> <span><script>
@ -63,7 +69,7 @@
</script></span> </script></span>
</label> </label>
<script> <script>
if (qp && qp.action == 'arrival') if (qp.action && qp.action == 'arrival')
document.write(testCheckBox) document.write(testCheckBox)
</script> </script>
<input type="submit"> <input type="submit">

View File

@ -1,7 +1,9 @@
var pushServerPublicKey = 'BBwBPYxhogHLU3B1FpxfQNzO3q7qZpmD1n1KaaL8WJbcVmJSHhi1uB-VmvsVjjUHWYCeqKyLT7w-1LBfpIcbbcg'
var spage = document.getElementById('startpage') var spage = document.getElementById('startpage')
var mform = document.getElementById('mainform') var mform = document.getElementById('mainform')
if (qp) { if (qp.action) {
spage.style.display = 'none' spage.style.display = 'none'
mform.style.display = 'block' mform.style.display = 'block'
} }
@ -12,18 +14,26 @@ if (savedName && qp)
document.getElementById('name').value = savedName document.getElementById('name').value = savedName
// 2nd script, server API communication // 2nd script, server API communication
var name, agreed, tested var name, datetime, agreed, tested
mform.onsubmit = function(e) { mform.onsubmit = function(e) {
e.preventDefault() e.preventDefault()
name = e.srcElement[0].value var i = 0;
agreed = e.srcElement[1].checked name = e.srcElement[i++].value
if (e.srcElement.length > 2) if (qp.edittime && qp.edittime == 1) {
tested = e.srcElement[2].checked var value = e.srcElement[i++].value
datetime = new Date(value).toISOString()
}
agreed = e.srcElement[i++].checked
if (qp.action && qp.action == 'arrival')
tested = e.srcElement[i++].checked
sendMainData() sendMainData()
initPush(name)
} }
function sendMainData() { function sendMainData() {
@ -33,11 +43,13 @@ function sendMainData() {
{ {
'room': qp.room, 'room': qp.room,
'name': name, 'name': name,
'arrival': datetime,
'agreetoguidelines': agreed, 'agreetoguidelines': agreed,
'tested': tested 'tested': tested
} : } :
{ {
'name': name, 'name': name,
'departure': datetime,
'cleanedworkspace': agreed 'cleanedworkspace': agreed
} }
@ -159,7 +171,7 @@ function handleRequest(res) {
<form id="reqform"> <form id="reqform">
<label> <label>
${reqt[json.request]} ${reqt[json.request]}
<input type="datetime-local" id="datetime" ${minD} max="${now}" required> <input type="datetime-local" ${minD} max="${now}" required>
${aInfo} ${aInfo}
</label> </label>
${doubleT} ${doubleT}
@ -179,3 +191,76 @@ function handleRequest(res) {
}) })
} }
if (qp.edittime && qp.edittime == 1) {
var now = localISOTimeMinutes(new Date())
document.getElementById('datetime').value = now;
document.getElementById('datetime').max = now;
}
/* Push Notifications */
function sendNotification() {
navigator.serviceWorker.ready.then(function(serviceWorker) {
serviceWorker.showNotification("Forgot to sign out?", {
body: "You didn't sign out of ftracker yet",
icon: "/favicon.ico",
actions: [{
action: "depart",
title: "Sign Out"
}]
})
})
}
function initPush(name) {
// Check availability
var supported = "serviceWorker" in navigator && "PushManager" in window
if (!supported) {
console.warn("Push Notifications not supported!")
return
}
// Register service worker
navigator.serviceWorker.register("/sw.js").then(function(swRegistration) {
console.log("ServiceWorker registered:", swRegistration)
})
// Request permission
// TODO: Only do this AFTER the first? SUCCESSFUL sign-in
Notification.requestPermission(function(result) {
return (result === 'granted')
}).then(function(consent) {
console.log('Notifications', consent ? 'enabled' : 'denied');
})
// Check if already initialized
if (localStorage.getItem('pushsub'))
return
// Register push service
navigator.serviceWorker.ready.then(function(serviceWorker) {
serviceWorker.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: pushServerPublicKey
}).then(function(subscription) {
console.log("User is subscribed:", subscription);
localStorage.setItem('pushsub', subscription);
fetch('/pushsubscribe', {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
name: name,
sub: subscription
})
});
});
});
}

35
web/sw.js Normal file
View File

@ -0,0 +1,35 @@
function receivePushNotification(event) {
var data = event.data.json();
console.log("[Service Worker] Push Received:", data)
var room = data.arr ? data.arr.room : 'test'
var options = {
data: `/?departure=${room}&edittime=1`,
body: data.body,
icon: "/favicon.ico",
actions: [{
action: "depart",
title: "Sign Out"
}]
};
event.waitUntil(self.registration.showNotification(data.title, options))
}
self.addEventListener("push", receivePushNotification)
function openPushNotification(event) {
console.log("[Service Worker] Notification click Received.", event.notification.data)
event.notification.close()
event.waitUntil(clients.openWindow(event.notification.data))
}
self.addEventListener("notificationclick", openPushNotification)