Add push notifications for forgotten departures #26
@ -13,25 +13,27 @@
 | 
			
		||||
				'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 editTimeBox = '<label>Departure Date/Time:<input type="datetime-local" name="datetime" id="datetime" required></label>'
 | 
			
		||||
			function getParams() {
 | 
			
		||||
				var h = document.location.href
 | 
			
		||||
				var qparam = h.split('?')[1] || null
 | 
			
		||||
				if (qparam == null)
 | 
			
		||||
					return null
 | 
			
		||||
				var vals = qparam.split('=')
 | 
			
		||||
				if (vals.length < 2 || !cbt.hasOwnProperty(vals[0]))
 | 
			
		||||
					return null
 | 
			
		||||
				return {
 | 
			
		||||
					action: vals[0],
 | 
			
		||||
					room: vals[1]
 | 
			
		||||
				var qparams = document.location.search.substr(1)
 | 
			
		||||
				if (qparams == "") return {}
 | 
			
		||||
				qparams = qparams.split('&')
 | 
			
		||||
				var qps = {}
 | 
			
		||||
				for (var qparam of qparams) {
 | 
			
		||||
					var vals = qparam.split('=')
 | 
			
		||||
					qps[vals[0]] = vals[1] || null
 | 
			
		||||
				}
 | 
			
		||||
				// 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()
 | 
			
		||||
		</script>
 | 
			
		||||
	</head>
 | 
			
		||||
	<body>
 | 
			
		||||
		<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>
 | 
			
		||||
		<div id="startpage">
 | 
			
		||||
			This is a web app to track which people
 | 
			
		||||
@ -56,6 +58,10 @@
 | 
			
		||||
				Full Name:<br>
 | 
			
		||||
				<input type="text" name="name" id="name" placeholder="John Doe" required>
 | 
			
		||||
			</label>
 | 
			
		||||
			<script>
 | 
			
		||||
				if (qp.edittime && qp.edittime == 1)
 | 
			
		||||
					document.write(editTimeBox)
 | 
			
		||||
			</script>
 | 
			
		||||
			<label class="checkbox">
 | 
			
		||||
				<input type="checkbox" name="agree" id="agree" required>
 | 
			
		||||
				<span><script>
 | 
			
		||||
@ -63,7 +69,7 @@
 | 
			
		||||
				</script></span>
 | 
			
		||||
			</label>
 | 
			
		||||
			<script>
 | 
			
		||||
				if (qp && qp.action == 'arrival')
 | 
			
		||||
				if (qp.action && qp.action == 'arrival')
 | 
			
		||||
					document.write(testCheckBox)
 | 
			
		||||
			</script>
 | 
			
		||||
			<input type="submit">
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										99
									
								
								web/main.js
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								web/main.js
									
									
									
									
									
								
							@ -1,7 +1,9 @@
 | 
			
		||||
var pushServerPublicKey = 'BBwBPYxhogHLU3B1FpxfQNzO3q7qZpmD1n1KaaL8WJbcVmJSHhi1uB-VmvsVjjUHWYCeqKyLT7w-1LBfpIcbbcg'
 | 
			
		||||
 | 
			
		||||
var spage = document.getElementById('startpage')
 | 
			
		||||
var mform = document.getElementById('mainform')
 | 
			
		||||
 | 
			
		||||
if (qp) {
 | 
			
		||||
if (qp.action) {
 | 
			
		||||
	spage.style.display = 'none'
 | 
			
		||||
	mform.style.display = 'block'
 | 
			
		||||
}
 | 
			
		||||
@ -12,18 +14,26 @@ if (savedName && qp)
 | 
			
		||||
	document.getElementById('name').value = savedName
 | 
			
		||||
 | 
			
		||||
// 2nd script, server API communication
 | 
			
		||||
var name, agreed, tested
 | 
			
		||||
var name, datetime, agreed, tested
 | 
			
		||||
mform.onsubmit = function(e) {
 | 
			
		||||
 | 
			
		||||
	e.preventDefault()
 | 
			
		||||
 | 
			
		||||
	name = e.srcElement[0].value
 | 
			
		||||
	agreed = e.srcElement[1].checked
 | 
			
		||||
	if (e.srcElement.length > 2)
 | 
			
		||||
		tested = e.srcElement[2].checked
 | 
			
		||||
	var i = 0;
 | 
			
		||||
	name = e.srcElement[i++].value
 | 
			
		||||
	if (qp.edittime && qp.edittime == 1) {
 | 
			
		||||
		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()
 | 
			
		||||
 | 
			
		||||
	initPush(name)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sendMainData() {
 | 
			
		||||
@ -33,11 +43,13 @@ function sendMainData() {
 | 
			
		||||
		{
 | 
			
		||||
			'room': qp.room,
 | 
			
		||||
			'name': name,
 | 
			
		||||
			'arrival': datetime,
 | 
			
		||||
			'agreetoguidelines': agreed,
 | 
			
		||||
			'tested': tested
 | 
			
		||||
		} :
 | 
			
		||||
		{
 | 
			
		||||
			'name': name,
 | 
			
		||||
			'departure': datetime,
 | 
			
		||||
			'cleanedworkspace': agreed
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -159,7 +171,7 @@ function handleRequest(res) {
 | 
			
		||||
				<form id="reqform">
 | 
			
		||||
					<label>
 | 
			
		||||
						${reqt[json.request]}
 | 
			
		||||
						<input type="datetime-local" id="datetime" ${minD} max="${now}" required>
 | 
			
		||||
						<input type="datetime-local" ${minD} max="${now}" required>
 | 
			
		||||
						${aInfo}
 | 
			
		||||
					</label>
 | 
			
		||||
					${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
									
								
							
							
						
						
									
										35
									
								
								web/sw.js
									
									
									
									
									
										Normal 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)
 | 
			
		||||
		Reference in New Issue
	
	Block a user