tickets/templates/party.html

310 lines
11 KiB
HTML
Raw Normal View History

2022-06-11 23:44:44 +02:00
{% extends "base.html" %}
{% block content %}
<div class="columns">
<div class="column col-md-12 col-mx-auto col-6">
<h1>{{name}}</h1>
<h2>Modus</h2>
<div class="form-group">
<label class="form-radio form-inline">
2022-12-15 18:27:42 +01:00
<input type="radio" name="mode" value="false" checked="" onclick="reselect()"><i class="form-icon"></i>
Toevoegen
2022-06-11 23:44:44 +02:00
</label>
<label class="form-radio form-inline">
2022-12-15 18:27:42 +01:00
<input type="radio" name="mode" value="true" onclick="reselect()"><i class="form-icon"></i> Controleren
2022-06-11 23:44:44 +02:00
</label>
</div>
2022-06-28 20:09:24 +02:00
<h2>Informatie</h2>
2022-06-11 23:44:44 +02:00
<div>
2022-12-15 18:27:42 +01:00
<p><select id="videoSource"></select><button class="btn btn-primary" id="start_scan_btn"
onclick="reselect()">Start
2022-06-11 23:44:44 +02:00
Scannen</button> </p>
<div class="columns">
2022-12-23 20:22:38 +01:00
<video autoplay playsinline controls="false" class="column col-12" id="webcam_holder" hidden></video>
</div>
2022-06-28 20:09:24 +02:00
<h4><span id="last-scanned">Nog geen gescand</span></h4>
<h3><span id="scan-status">Nog geen gescand</span></h3>
<h3>Binnen/Betaald: <span id="stats">Laden...</span></h3>
2022-11-12 22:19:27 +01:00
<h3>
<label class="form-checkbox form-inline">
<input type="checkbox" id="muntjes" onclick="reselect()"><i class="form-icon"></i> Muntjes kopen
2022-11-12 22:19:27 +01:00
</label>
</h3>
2022-06-11 23:44:44 +02:00
</div>
<div class="columns">
<div class="column col-md-12 col-6">
<h2>Handmatig Toevoegen</h2>
<form id="student_number_wrapper">
<p><label for="student_number">Leerlingnummer:</label></p>
<input type="text" id="student_number" name="student_number" placeholder="Leerlingnummer">
<button class="btn btn-primary" id="add_student">"Scan"</button>
</form>
2022-06-11 23:44:44 +02:00
</div>
<div class="column col-md-12 col-6">
<h2>Extra opties</h2>
<p><a href="/party/{{id}}/lijst">Bekijk een tabel in je browser</a></p>
<p><a href="/party/{{id}}/export">Exporteer als CSV</a></p>
<p><label for="file-selector">Importeer CSV:</label><input type="file" id="file-selector"
accept=".csv" /></p>
<p><button id="file-selector-button">Importeer</button> <span id="import-result"></span></p>
2022-06-11 23:44:44 +02:00
</div>
</div>
</div>
</div>
<input type="hidden" id="party_id" value="{{id}}">
<script src="//unpkg.com/javascript-barcode-reader"></script>
<script>
function set_colour(state) {
if (state == "OK") {
document.body.classList.add("bg-success");
setTimeout(function () {
document.body.classList.remove("bg-success");
}, 1000);
2022-11-12 22:19:27 +01:00
} else if (state == "COINS") {
document.body.classList.add("bg-primary");
setTimeout(function () {
document.body.classList.remove("bg-primary");
}, 1000);
2022-06-11 23:44:44 +02:00
} else if (state == "WARN") {
document.body.classList.add("bg-warning");
setTimeout(function () {
document.body.classList.remove("bg-warning");
}, 1000);
} else if ("ERR") {
document.body.classList.add("bg-error");
setTimeout(function () {
document.body.classList.remove("bg-error");
}, 1000);
}
}
function reselect() {
let elem = document.getElementById("student_number");
elem.focus();
elem.select();
}
2022-06-11 23:44:44 +02:00
function set_scan_status(status) {
document.getElementById("scan-status").innerHTML = status;
}
function set_state(data) {
let code = data.code;
let state = data.state;
let check = document.querySelector('input[name="mode"]:checked').value === "true";
document.getElementById("last-scanned").innerText = code;
if (state === "NotFound") {
// leerlingnummer niet gevonden op de gastenlijst
// alert("Leerlingnummer niet gevonden");
set_scan_status("Heeft (waarschijnlijk) niet betaald");
set_colour("ERR");
} else if (state === "Found") {
// leerlingnummer is gevonden en mag naar binnen
// alert("Leerlingnummer gevonden");
set_scan_status("Mag naar binnen");
set_colour("OK");
2022-11-12 22:19:27 +01:00
} else if (state === "Coins") {
// leerlingnummer is gevonden en mag naar binnen
// alert("Leerlingnummer gevonden");
set_scan_status("Mag naar binnen, heeft muntjes gekocht!");
set_colour("COINS");
2022-06-11 23:44:44 +02:00
} else if (state === "Added") {
// leerlingummer is toegevoegd aan de gastenlijst
// alert("Leerlingnummer toegevoegd");
set_scan_status("Toegevoegd");
set_colour("OK");
} else if (state === "AlreadyScanned") {
// leerlingnummer is al gescand, bij check==false is er al betaald, bij check==true is de leerling al binnen
if (check) {
// alert("Leerlingnummer is al binnen");
set_scan_status("Al binnen");
set_colour("ERR");
} else {
// alert("Leerlingnummer is al betaald");
set_scan_status("Al betaald");
set_colour("WARN");
}
} else {
alert("Error");
}
2022-06-28 20:09:24 +02:00
fetch_stats()
2022-06-11 23:44:44 +02:00
}
2022-06-28 20:09:24 +02:00
function fetch_stats() {
let party_id = +document.getElementById("party_id").value;
fetch(`/api/party/${party_id}/stats`)
.then(response => response.json())
.then(data => {
document.getElementById("stats").innerText = `${data.inside}/${data.total}`;
});
}
2022-11-12 22:36:08 +01:00
function scan_ticket(code, coins) {
2022-11-12 22:19:27 +01:00
if (code === "COINS" || code === "000000") {
document.getElementById("muntjes").checked = true;
return;
}
2022-06-11 23:44:44 +02:00
let check = document.querySelector('input[name="mode"]:checked').value === "true";
let party_id = +document.getElementById("party_id").value;
2022-11-12 22:19:27 +01:00
2022-06-11 23:44:44 +02:00
fetch("/api/ticket", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
party: party_id,
code: code,
check: check,
2022-11-12 22:36:08 +01:00
coins: coins || document.getElementById("muntjes").checked,
2022-06-11 23:44:44 +02:00
})
}).then(function (response) {
return response.json();
}).then(function (data) {
console.log(data)
2022-11-12 22:19:27 +01:00
document.getElementById("muntjes").checked = false;
2022-06-11 23:44:44 +02:00
return data;
}).then(set_state);
}
2022-06-28 19:52:11 +02:00
function return_handler(e) {
e.preventDefault();
let code = document.getElementById("student_number").value;
console.log(code);
scan_ticket(code);
2022-06-28 19:32:12 +02:00
document.getElementById("student_number").value = "";
}
document.getElementById("student_number_wrapper").addEventListener("submit", return_handler);
2022-06-11 23:44:44 +02:00
document.getElementById("start_scan_btn").addEventListener('click', start_scanning);
const videoElement = document.querySelector("video");
const videoSelect = document.querySelector("select#videoSource");
function start_scanning() {
2022-12-23 20:22:38 +01:00
document.getElementById("webcam_holder").hidden = false;
2022-06-11 23:44:44 +02:00
navigator.mediaDevices
.enumerateDevices()
.then(gotDevices)
.then(getStream)
.catch(handleError);
}
videoSelect.onchange = getStream;
function gotDevices(deviceInfos) {
for (let i = 0; i !== deviceInfos.length; ++i) {
const deviceInfo = deviceInfos[i];
const option = document.createElement("option");
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === "videoinput") {
option.text = deviceInfo.label || "camera " + (videoSelect.length + 1);
videoSelect.appendChild(option);
} else {
console.log("Found another kind of device: ", deviceInfo);
}
}
}
function getStream() {
if (window.stream) {
window.stream.getTracks().forEach(function (track) {
track.stop();
});
}
const constraints = {
video: {
deviceId: { exact: videoSelect.value },
},
};
navigator.mediaDevices
.getUserMedia(constraints)
.then(gotStream)
.catch(handleError);
}
function gotStream(stream) {
window.stream = stream; // make stream available to console
videoElement.srcObject = stream;
setInterval(() => {
console.log("scanning now?")
2022-06-12 09:28:46 +02:00
const canvas = document.createElement("canvas");
2022-06-11 23:44:44 +02:00
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
canvas.getContext("2d").drawImage(videoElement, 0, 0);
do_scan(canvas);
}, 500);
}
function handleError(error) {
console.error("Error: ", error);
}
let last_scan = "";
function do_scan(imageData) {
javascriptBarcodeReader({
image: imageData,
barcode: 'codabar',
options: {
useAdaptiveThreshold: true,
}
})
.then(code => {
if (code.length == 6) {
if (last_scan === code) {
return;
}
last_scan = code;
scan_ticket(code);
}
})
.catch(err => {
console.log(err)
})
}
function upload_csv() {
let file = document.getElementById("file-selector").files[0];
if (file) {
2022-12-23 20:22:38 +01:00
set_scan_status("CSV uploaden...");
// upload file contents to server
let reader = new FileReader();
reader.onload = function (e) {
let contents = e.target.result;
let party_id = +document.getElementById("party_id").value;
fetch("/api/csv", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
party: party_id,
csv: contents,
})
}).then(function (response) {
return response.json();
}).then(function (data) {
console.log(data)
set_scan_status(`CSV geupload: ${data.total} regels, waarvan ${data.scanned} leerlingen, ${data.with_coins} met muntjes`);
});
};
reader.readAsText(file);
}
}
document.getElementById("file-selector-button").addEventListener("click", upload_csv);
2022-06-28 19:52:11 +02:00
2022-06-28 20:09:24 +02:00
fetch_stats();
reselect();
2022-06-28 19:52:11 +02:00
2022-06-11 23:44:44 +02:00
</script>
{% endblock %}