Added scoreboard functionality, seperate update admin frontend

This commit is contained in:
Julian Appel 2024-05-17 21:24:58 +02:00
parent e36a959071
commit 93d06517e4
4 changed files with 331 additions and 22 deletions

View File

@ -0,0 +1,125 @@
const io = require('./socketio');
let enabled = false;
let teamA = {
name: "Team A",
name2: "",
score: 0,
isSpielgemeinschaft: 0,
};
let teamB = {
name: "Team B",
name2: "",
score: 0,
isSpielgemeinschaft: 0,
};
let sideswitch = false;
// Function prototypes
function setEnabled(status) {};
function setName(team, name) {};
function configTeam() {};
function setScore(team, score) {};
function alterScore(team, dir) {};
function clearScore() {};
function toggleSwitch() {};
function getEnabled() {};
function getValues() {};
// Enable or disable the scoreboard
function setEnabled(status) {
enabled = status;
}
function configTeam(team, name, name2, isSpielgemeinschaft) {
if(team == "teamA") {
teamA.name = name;
teamA.name2 = name2;
teamA.isSpielgemeinschaft = isSpielgemeinschaft;
} else if(team == "teamB") {
teamB.name = name;
teamB.name2 = name2;
teamB.isSpielgemeinschaft = isSpielgemeinschaft;
}
}
// Set team name
function setName(team, name) {
if(team == "teamA") {
teamA.name = name;
} else if(team == "teamB") {
teamB.name = name;
}
}
// Set score of team to passed value
function setScore(team, score) {
if(team == "teamA") {
teamA.score = score;
} else if(team == "teamB") {
teamB.score = score;
}
}
// Increment score by one
function alterScore(team, dir) {
if(team == "teamA") {
if(dir == "inc") {
teamA.score++;
console.log("teamA inc");
}
else if(dir == "dec") {
teamA.score--;
console.log("teamA dec");
}
} else if(team == "teamB") {
if(dir == "inc") {
teamB.score++;
console.log("teamB inc");
}
else if(dir == "dec") {
teamB.score--;
console.log("teamB dec");
}
}
io.sockets.emit('score', print());
}
// Clears score of both teams
function clearScore() {
teamA.score = 0;
teamB.score = 0;
io.sockets.emit('score', print());
}
// Toggle sideswitch
function toggleSwitch() {
sideswitch = !sideswitch;
}
// Return enabled value
function getEnabled() {
return enabled
}
function print() {
if(sideswitch) {
return teamB.score + ":" + teamA.score
} else {
return teamA.score + ":" + teamB.score
}
}
function getValues() {
return {
enabled: enabled,
teamA: teamA,
teamB: teamB,
sideswitch: sideswitch,
print: print(),
};
}
module.exports = {
setEnabled, setScore, alterScore, clearScore, getEnabled, getValues
}

View File

@ -15,7 +15,13 @@ socket.on('timerEnded', (message) => {
initialUpdate(); // Update admin frontend to set correct buttonstatus initialUpdate(); // Update admin frontend to set correct buttonstatus
}); });
function updateFrontend(values) { socket.on('score', (message) => {
console.log(message) // Log score in client console
document.getElementById("score").innerHTML = message; // Display score in corresponding html Element
});
// Update DOM timer elements from passed values
function updateTimerFrontend(values) {
values.duration = moment.duration(values.duration) // Create moment object from ISO 8601 string values.duration = moment.duration(values.duration) // Create moment object from ISO 8601 string
values.durationLeft = moment.duration(values.durationLeft) // Create moment object from ISO 8601 string values.durationLeft = moment.duration(values.durationLeft) // Create moment object from ISO 8601 string
document.getElementById("durationLeft").innerHTML = values.print // Display durationLeft as prettyfied string document.getElementById("durationLeft").innerHTML = values.print // Display durationLeft as prettyfied string
@ -29,7 +35,18 @@ function updateFrontend(values) {
} }
} }
// Update DOM score elements from passed values
function updateScoreFrontend(values) {
document.getElementById("scoreSwitchEnable").checked = values.enabled; // Set switch status to received score enabled value
document.getElementById("score").innerHTML = values.print // Set score on admin interface
}
// Initial update gets called whenever page has been loaded
async function initialUpdate() { async function initialUpdate() {
timerGetValues(); // Request new values for timer
scoreGetValues(); // Request new values for score
}
// Request monitor refresh for index frontend // Request monitor refresh for index frontend
async function refreshMonitor() { async function refreshMonitor() {
const response = await fetch("/admin/refreshMonitor"); // Call API Endpoint /admin/timerStart const response = await fetch("/admin/refreshMonitor"); // Call API Endpoint /admin/timerStart
@ -38,12 +55,21 @@ async function refreshMonitor() {
} }
// Timerfunctions // Timerfunctions
// Request important timer values
async function timerGetValues() {
const response = await fetch("/admin/timerGetValues"); // Call API Endpoint /admin/timerGetValues
const data = await response.json(); // Wait for asynchronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data
updateTimerFrontend(data); // Update admin frontend with received values for timerboard
}
// Request to start the timer
async function timerStart() { async function timerStart() {
const response = await fetch("/admin/timerStart"); // Call API Endpoint /admin/timerStart const response = await fetch("/admin/timerStart"); // Call API Endpoint /admin/timerStart
if(response.status == 200) { if(response.status == 200) { // If request successfull
const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend) const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data console.log(data); // Print received data
updateFrontend(data); // Update admin frontend with received values updateTimerFrontend(data); // Update admin frontend with received values
} else { } else {
//console.log("Error, Timer bereits abgelaufen: ", response.status); //console.log("Error, Timer bereits abgelaufen: ", response.status);
const timerStartErrorToast = bootstrap.Toast.getOrCreateInstance(document.getElementById("timerStartErrorToast")); // Create toast instance byId timerStartErrorToast const timerStartErrorToast = bootstrap.Toast.getOrCreateInstance(document.getElementById("timerStartErrorToast")); // Create toast instance byId timerStartErrorToast
@ -57,7 +83,7 @@ async function timerPause() {
if(response.status == 200) { if(response.status == 200) {
const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend) const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data console.log(data); // Print received data
updateFrontend(data); // Update admin frontend with received values updateTimerFrontend(data); // Update admin frontend with received values
} else { } else {
//console.log("Error, Timer bereits pausiert: ", response.status); //console.log("Error, Timer bereits pausiert: ", response.status);
const timerPauseErrorToast = bootstrap.Toast.getOrCreateInstance(document.getElementById("timerPauseErrorToast")); // Create toast instance byId timerStartErrorToast const timerPauseErrorToast = bootstrap.Toast.getOrCreateInstance(document.getElementById("timerPauseErrorToast")); // Create toast instance byId timerStartErrorToast
@ -91,8 +117,49 @@ async function timerIncDec(value) {
} }
// Scoreboardfunctions // Scoreboardfunctions
// Request important values for score
async function scoreGetValues() {
const response = await fetch("/admin/scoreGetValues"); // Call API Endpoint /admin/scoreGetValues
const data = await response.json(); // Wait for asynchronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data
updateScoreFrontend(data); // Update admin frontend with received values for scoreboard
}
// Toggle index page to also show scoreboard
async function scoreToggle() {
console.log(document.getElementById("scoreSwitchEnable").checked)
const response = await fetch("/admin/scoreToggle"); // Call API Endpoint /admin/scoreEnable
const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data
updateScoreFrontend(data); // Update admin frontend with received values for scoreboard
refreshMonitor(); // Send request to refresh monitor
}
// Alter the score of passed team in the specified direction
async function scoreAlterScore(team, dir) {
const response = await fetch("/admin/scoreAlterScore", {// Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({team: team, dir: dir})
});
const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data
updateScoreFrontend(data); // Update admin frontend with received values
}
// Switch sides
async function scoreSwitch() { async function scoreSwitch() {
const response = await fetch("/admin/scoreSwitch"); // Call API Endpoint /admin/timerStart const response = await fetch("/admin/scoreSwitch"); // Call API Endpoint /admin/timerStart
const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend) const data = await response.json(); // Wait for asyncronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data console.log(data); // Print received data
updateScoreFrontend(data); // Update admin frontend with received values for scoreboard
} }
// Clear score
async function scoreClearScore() {
const response = await fetch("/admin/scoreClearScore"); // Call API Endpoint /admin/scoreResetScore
const data = await response.json(); // Wait for asynchronous transfer to complete and parse json (which got received by backend)
console.log(data); // Print received data
updateScoreFrontend(data); // Update admin frontend with received values for scoreboard
}

View File

@ -1,6 +1,10 @@
var express = require('express'); var express = require('express');
var router = express.Router(); var router = express.Router();
const io = require('../controllers/socketio'); const io = require('../controllers/socketio');
const timer = require('../controllers/timer');
const score = require('../controllers/score');
// Express router endpoint to trigger a frontend refresh on all connected sockets // Express router endpoint to trigger a frontend refresh on all connected sockets
router.get('/refreshMonitor', function(req, res, next) { router.get('/refreshMonitor', function(req, res, next) {
console.log("Monitor neu geladen"); console.log("Monitor neu geladen");
@ -47,9 +51,48 @@ router.get('/timerGetValues', function(req, res, next) {
res.json(timer.getValues()); // Respond with important values for frontend res.json(timer.getValues()); // Respond with important values for frontend
}); });
// Express router endpoint to toggle the scoreboard
router.get('/scoreToggle', function(req, res, next) {
if(score.getEnabled()) { // If scoreboard enabled
console.log("Scoreboard disabled");
score.setEnabled(false) // Disable the scoreboard
res.status(200); // Set http status code to 200 (success)
res.json(score.getValues()) // Respond with all important values to update the frontend
} else {
console.log("Scoreboard enabled");
score.setEnabled(true) // Enable the scoreboard
res.status(200); // Set http status code to 200 (success)
res.json(score.getValues()); // Respond with all important values to update the frontend
}
});
// Express router endpoint to set score of a team
router.post('/scoreSetScore', function(req, res, next) {
score.setScore(req.body.team, req.body.score);
res.status(200);
res.json(score.getValues());
});
// Express router endpoint to alter passed teams score by one in the passed direction
router.post('/scoreAlterScore', function(req, res, next) {
score.alterScore(req.body.team, req.body.dir);
res.status(200);
res.json(score.getValues());
});
// Express router endpoint to switch the score after halftime // Express router endpoint to switch the score after halftime
router.get('/scoreSwitch', function(req, res, next) { router.post('/scoreSwitch', function(req, res, next) {
res.render('admin'); });
// Express router endpoint to get important score values
router.get('/scoreGetValues', function(req, res, next) {
res.json(score.getValues()); // Respond with important values for frontend
});
// Express router endpoint to clear score
router.get('/scoreClearScore', function(req, res, next) {
score.clearScore(); // Clear score
res.json(score.getValues()); // Respond with important values for frontend
}); });
/* GET home page. */ /* GET home page. */

View File

@ -27,28 +27,27 @@
<div class="h-100 card text-center"> <div class="h-100 card text-center">
<div class="card-body"> <div class="card-body">
<button class="m-2 p-3 btn btn-lg btn-success" onclick="timerStart()" id="timerStartBtn"><i class="fa-solid fa-play"></i> Start</button> <button class="m-2 p-3 btn btn-lg btn-success" onclick="timerStart()" id="timerStartBtn"><i class="fa-solid fa-play"></i> Start</button>
<br>
<button class="m-2 p-3 btn btn-lg btn-warning" onclick="timerPause()" id="timerPauseBtn"><i class="fa-solid fa-pause"></i> Pause</button> <button class="m-2 p-3 btn btn-lg btn-warning" onclick="timerPause()" id="timerPauseBtn"><i class="fa-solid fa-pause"></i> Pause</button>
</div> </div>
</div> </div>
</div> </div>
<div class="col-sm-12 col-md-12 col-lg-4"> <div class="col-sm-12 col-md-12 col-lg-4">
<div class="h-100 card text-center "> <div class="h-100 card text-center">
<div class="card-body "> <div class="card-body ">
<div class="btn-group align-middle" role="group" aria-label="Basic example"> <div class="btn-group align-middle" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary">-1m</button> <button type="button" class="btn btn-secondary" onclick="timerIncDec(-10)">-10s</button>
<button type="button" class="btn btn-secondary">-10s</button> <button type="button" class="btn btn-secondary" onclick="timerIncDec(-5)">-5s</button>
<button type="button" class="btn btn-secondary">-1s</button> <button type="button" class="btn btn-secondary" onclick="timerIncDec(-1)">-1s</button>
<button type="button" class="btn btn-secondary">+1s</button> <button type="button" class="btn btn-secondary" onclick="timerIncDec(+1)">+1s</button>
<button type="button" class="btn btn-secondary">+10s</button> <button type="button" class="btn btn-secondary" onclick="timerIncDec(+5)">+5s</button>
<button type="button" class="btn btn-secondary">+1m</button> <button type="button" class="btn btn-secondary" onclick="timerIncDec(+10)">+10s</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="py-auto col-sm-12 col-md-12 col-lg-4"> <div class="col-sm-12 col-md-12 col-lg-4">
<div class="h-100 card text-center"> <div class="h-100 card text-center">
<div class="card-body"> <div class="card-body">
<button class="btn btn-lg btn-danger" data-bs-toggle="modal" data-bs-target="#timerResetModal"> <button class="btn btn-lg btn-danger" data-bs-toggle="modal" data-bs-target="#timerResetModal">
@ -59,12 +58,64 @@
</div> </div>
</div> </div>
<div class="row text-center"> <div class="row mb-4 justify-content-center">
<div class="col-sm-12 col-md-12 col-lg-12"> <div class="col-sm-12 col-md-12 col-lg-4">
<button class="btn btn-lg btn-danger" onclick="scoreSwitch()"><i class="fa-solid fa-rotate"></i> Seitenwechsel</button> <div class="card text-center">
<div class="card-body">
<h1 id="score"></h1>
</div>
</div>
</div> </div>
</div> </div>
<div class="row mb-4">
<div class="col-sm-12 col-md-12 col-lg-4">
<div class="h-100 card text-center">
<div class="card-body">
<div class="row">
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="btn-group-vertical" role="group" aria-label="Vertical button group">
<button type="mb-2 button" class="btn btn-outline-success" onclick="scoreAlterScore('teamA', 'inc')">Team A +1</button>
<button type="mb-2 button" class="btn btn-outline-danger" onclick="scoreAlterScore('teamA', 'dec')">Team A -1</button>
</div>
</div>
<div class="col-sm-6 col-md-6 col-lg-6">
<div class="btn-group-vertical" role="group" aria-label="Vertical button group">
<button type="mb-2 button" class="btn btn-outline-success" onclick="scoreAlterScore('teamB', 'inc')">Team B +1</button>
<button type="mb-2 button" class="btn btn-outline-danger" onclick="scoreAlterScore('teamB', 'dec')">Team B -1</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-4">
<div class="h-100 card text-center">
<div class="card-body">
<button class="mb-2 btn btn-lg btn-danger" onclick="scoreSwitch()"><i class="fa-solid fa-rotate"></i> Seitenwechsel</button>
<button class="mb-2 btn btn-lg btn-danger" onclick="scoreClearScore()"><i class="fa-solid fa-rotate"></i> Score löschen</button>
<button class="mb-2 btn btn-lg btn-danger" data-bs-toggle="modal" data-bs-target="#scoreConfigTeamAModal">Team A konfigurieren</button>
</div>
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-4">
<div class="h-100 card text-center">
<div class="card-body">
<div class="form-check form-switch">
<input class="form-check-input" onclick="scoreToggle()" type="checkbox" role="switch" id="scoreSwitchEnable">
<label class="form-check-label" for="scoreSwitchEnable">Zeige Scoreboard</label>
</div>
<button class="mb-2 btn btn-lg btn-warning" onclick="scoreToggle()"><i class="fa-solid fa-rotate"></i> Scoreboard togglen</button>
<button class="mb-2 btn btn-lg btn-warning" onclick="refreshMonitor()"><i class="fa-solid fa-rotate"></i> Monitor neu laden</button>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</body> </body>
<script src='/javascripts/bootstrap/bootstrap.bundle.min.js'></script> <script src='/javascripts/bootstrap/bootstrap.bundle.min.js'></script>
@ -137,6 +188,29 @@
</div> </div>
<!-- Modal --> <!-- Modal -->
<!-- Config Team Modal -->
<div class="modal fade" id="scoreConfigTeamAModal" tabindex="-1" aria-labelledby="scoreConfigTeamAModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="timerResetModalLabel">Timer zurücksetzen?</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Konfiguration von Team A bearbeiten:</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-bs-dismiss="modal" onclick="">Absenden</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<!-- Config Team Modal -->
<!-- Timer start error toast --> <!-- Timer start error toast -->
<div class="toast-container position-fixed bottom-0 end-0 p-3"> <div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="timerStartErrorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true"> <div id="timerStartErrorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">