ftracker/web/index.html

315 lines
7.8 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>FTracker</title>
<meta name="theme-color" content="#c50e1f">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
background: #ddd;
font-family: sans-serif;
}
h1 {
margin: 0;
padding: 16px;
text-transform: uppercase;
color: #eee;
background: #c50e1f;
text-align: center;
}
form {
padding: 16px;
max-width: 512px;
margin: auto;
}
label {
display: block;
font-size: 16px;
margin-bottom: 16px;
color: #444;
}
label#agreelabel {
height: 32px;
line-height: 32px;
}
label span {
width: calc(100% - 50px);
display: inline-block;
vertical-align: middle;
line-height: normal;
}
input {
border: none;
padding: 16px;
margin: 4px 0;
font-size: 16px;
}
input[type=text] {
color: #000;
width: calc(100% - 32px);
}
input[type=submit], input[type=button] {
background: #c50e1f;
text-transform: uppercase;
font-weight: bold;
color: #fff;
width: 100%;
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
input[type=checkbox] {
transform: translateY(-3px);
float: left;
height: 32px;
width: 32px;
margin-right: 8px;
}
.request {
display: block;
position: fixed;
background: #ddd;
top: 16px;
left: 16px;
width: calc(100% - 32px);
box-shadow: 0 1px 4px 0;
}
input[type=datetime-local] {
width: calc(100% - 24px);
padding: 12px;
font-size: 12px;
background: #fff;
}
</style>
<script>
// 1st script, prepares values needed for writing document
var cbt = {
'arrival': 'I have read and will adhere to the <a href="/guidelines" target="_blank">protection guidelines</a>',
'departure': 'I have cleaned my workspace'
}
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 qp = getParams()
</script>
</head>
<body>
<h1><script>
if (qp)
document.write(qp.action + "<br>Room " + qp.room)
else
document.write('FTracker<br>V1')
</script></h1>
<form id="mainform">
<label>
Full Name:<br>
<input type="text" name="name" id="name" placeholder="John Doe" required>
</label>
<label id="agreelabel">
<input type="checkbox" name="agree" id="agree" required>
<span><script>
document.write(qp ? cbt[qp.action] : '')
</script></span>
</label>
<input type="submit">
</form>
<script>
var mform = document.getElementById('mainform')
if (qp == null) {
mform.innerHTML = 'This is a web app to track which people\
were in the same rooms at which times in order to backtrace\
potential viral infections.<br><br>\
If you\'ve reached this page that either means your\'re\
testing things or something has gone quite wrong with the\
URL.<br>\
In the former case: Yay it works! In the latter you should\
probably contact an admin or a dev nearby :(<br><br>\
Here are a few links for testing:<br>\
<a href="/view">View Data</a>, \
<a href="/QRgen">Door Sign Generator</a>, \
<a href="/?arrival=42">Test Arrival</a>, \
<a href="/?departure=42">Test Departure</a><br><br>\
&copy; 2020 made by <a target="_blank" href="mailto:&#111;&#46;&#119;&#105;&#110;&#107;&#101;&#108;&#115;&#64;&#102;&#97;&#115;&#116;&#116;&#117;&#98;&#101;&#46;&#100;&#101;">Oskar</a> \
for <a target="_blank" href="//fasttube.de">FaSTTUBe</a>.<br> \
For source code & licensing see <a href="//git.fasttube.de/FaSTTUBe/ftracker">git repo</a>'
}
// Prefill the name field if it was successfully entered before
var savedName = localStorage.getItem('name')
if (savedName && qp)
document.getElementById('name').value = savedName
// 2nd script, server API communication
var name, agreed
mform.onsubmit = function(e) {
e.preventDefault()
name = e.srcElement[0].value
agreed = e.srcElement[1].checked
sendMainData()
}
function sendMainData() {
// POST JSON. See docs/API.md
var payload = (qp.action == 'arrival') ?
{
'room': qp.room,
'name': name,
'agreetoguidelines': agreed
} :
{
'name': name,
'cleanedworkspace': agreed
}
post("/" + qp.action, payload)
}
function post(url, payload) {
console.log("Sending payload:", payload)
return fetch(url, {
method: "POST",
body: JSON.stringify(payload)
}).then(res => {
handleResponse(res)
})
}
function handleResponse(res) {
console.log("Request complete! response:", res)
if (Math.floor(res.status / 100) == 2) {
// Success
mform = document.getElementById('mainform')
mform.innerHTML = "<h2>Done. Thanks!</h2>"
localStorage.setItem('name', name)
} else if (res.status == 409) {
// Conflict, more data requested
handleRequest(res)
} else {
// Any other generic error
res.text().then(function (text) {
alert(text)
})
}
}
function handleRequestSubmit(e, json) {
e.preventDefault()
var input = e.srcElement[0].value
var iso = new Date(input).toISOString()
// POST JSON. See docs/API.md
var payload = (json.request == 'arrival') ?
{
'room': qp.room,
'name': name,
'arrival': iso,
'agreetoguidelines': agreed
} :
{
'name': name,
'departure': iso,
'cleanedworkspace': agreed
}
return post("/" + json.request, payload)
}
function localISOTimeMinutes(date) {
var tzoffset = date.getTimezoneOffset() * 60000; //offset in milliseconds
var localISOTime = (new Date(date - tzoffset)).toISOString().slice(0, -1);
return localISOTime.split(':').slice(0,2).join(':')
}
function handleRequest(res) {
var reqt = {
'arrival': 'You probably forgot to sign in when you arrived. Please enter your arrival time now:',
'departure': 'You probably forgot to sign out when you left. Please enter your departure time now:'
}
mform.innerHTML = "<h2>Processing Request...</h2>"
res.json().then(function (json) {
var aInfo = ''
var minD = ''
var doubleT = ''
if (json.request == 'departure') {
var d = new Date(json.arrival.time)
var dInfo = d.toString('en-GB').split(' ').slice(0,5).join(' ')
aInfo = `Your last arrival was on <b>${dInfo}</b> in room <b>${json.arrival.room}</b>.`
minD = `min="${localISOTimeMinutes(d)}"`
if (new Date() - d < 3 * 60 * 1000) {
doubleT = '<b style="color:red">Your last sign in was less than 3 minutes ago. You might be accidentally trying to sign in twice. If you don\'t intend to log 2 arrivals within the last 3 minutes, please abort below.</b>'
}
}
var now = localISOTimeMinutes(new Date())
document.body.innerHTML +=
`<div class="request">
<h1>${json.request} missing!</h1>
<form id="reqform">
<label>
${reqt[json.request]}
<input type="datetime-local" id="datetime" ${minD} max="${now}" required>
${aInfo}
</label>
${doubleT}
<input type="submit">
<input type="button" value="Abort" onclick="document.body.innerHTML='<h1>Aborted</h1><form>Nothing was logged.<br>You can close this tab/window now.</form>'">
</form>
</div>`
rform = document.getElementById('reqform')
rform.onsubmit = async function(e) {
await handleRequestSubmit(e, json)
document.querySelector('.request').remove()
setTimeout(sendMainData, 200)
}
})
}
</script>
</body>
</html>