I am trying to piece together a Google Apps script for a touchscreen clocking in system, and that involves generating some buttons from an array taken from a spreadsheet, but I'm getting a bit lost working out how to get the script to document which of these automatically generated buttons has been pressed.
Basically, I am using a modified version of this script (https://www.youtube.com/watch?v=KGhGWuTjJwc) - I need it to work with a touch screen.
I have got a version of the script given in the video above working. But because the web app must work on a touch screen I need to be able to generate buttons for the input of staff ID and PIN to replace the text boxes.
To do this I am pulling in an array from a Google Sheet that contains all staff initials needed to log in, as well as adding a numeric keypad to enter a PIN.
I have (sort of) successfully borrowed a keypad from here:https://github.com/ProgrammingHero1/batch5-pin-matcher-solution but I am stuck trying to get use buttons for the staff ID input.
I have managed to generate the buttons from the spreadsheet array, using a modified version of this Create an array of buttons from Javascript array but I can't work out how to set staffid to match whichever of the auto-generated buttons was pressed last. Currently those buttons don't do anything.
If anyone can help guide me the last step of the way so that staffid is set using the buttons and not using the text box that would be very much appreciated.
Below is the code I am using. I am aware that it is a dog's breakfast - that's because I am hacking it together from various sources working at (well, realistically well beyond) the limits of my understanding!
Anyway, here is the HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- Metro 4 -->
<link rel="stylesheet" href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css">
<style>
.main-box {
max-width:500px;
}
.error-message {
background:red;
color:white
padding: 1000px;
border-radius: 1000px;
}
</style>
</head>
<body>
<div class="container">
<div class="container d-flex flex-justify-center pt-9">
<div data-role="panel" class="main-box">
<form id="main-form">
<div class="form-group">
<input type="text" data-role="input" data-prepend="Staff ID" id="staffid">
<div class="form-group">
</div>
<div class="form-group">
<button id="start-work" class="button success" type="submit" data-action="Start work">Start work</button>
<button id="finish-work" class="button success" type="submit" data-action="Finish work">Finish work</button>
<button id="start-break" class="button success" type="submit" data-action="Start break">Start break</button>
<button id="finish-break" class="button success" type="submit" data-action="Finish break">Finish break</button>
<div class="input-section half-width">
<input id="typed-numbers" class="form-control" type="text">
<div class="numbers">
<div id="key-pad" class="calc-body">
<div class="calc-button-row">
<div class="button">7</div>
<div class="button">8</div>
<div class="button">9</div>
</div>
<div class="calc-button-row">
<div class="button">4</div>
<div class="button">5</div>
<div class="button">6</div>
</div>
<div class="calc-button-row">
<div class="button">1</div>
<div class="button">2</div>
<div class="button">3</div>
</div>
<div class="calc-button-row">
<div class="button"><</div>
<div class="button">0</div>
<div class="button">C</div>
</div>
</div>
</div>
</div>
</div>
</form>
<div id="message" class="d-none error-message mt4">
Error!!
</div>
</div>
</div>
</body>
<!-- Metro 4 -->
<script src="https://cdn.metroui.org.ua/v4/js/metro.min.js"></script>
<script>
const TSPwebapp = {}
TSPwebapp.onLoad = function(){
TSPwebapp.form = document.getElementById("main-form")
TSPwebapp.staffidInput = document.getElementById("staffid")
TSPwebapp.pinInput = document.getElementById("typed-numbers")
TSPwebapp.startWorkButton = document.getElementById("start-work")
TSPwebapp.finishWorkButton = document.getElementById("finish-work")
TSPwebapp.startBreakButton = document.getElementById("start-break")
TSPwebapp.finishBreakButton = document.getElementById("finish-break")
TSPwebapp.message = document.getElementById("message")
TSPwebapp.form.addEventListener("submit",TSPwebapp.onSubmit)
TSPwebapp.startWorkButton.addEventListener("click",TSPwebapp.startFinishWork)
TSPwebapp.finishWorkButton.addEventListener("click",TSPwebapp.startFinishWork)
TSPwebapp.startBreakButton.addEventListener("click",TSPwebapp.startFinishBreak)
TSPwebapp.finishBreakButton.addEventListener("click",TSPwebapp.startFinishBreak)
} // TSPwebapp.onLoad function
TSPwebapp.onSubmit= function(e){
e.preventDefault()
} // TSPwebapp.onSubmit function
TSPwebapp.startFinishWork = function(e){
const payload = {
staffid: TSPwebapp.staffidInput.value,
pin: TSPwebapp.pinInput.value,
action: e.target.dataset.action
}
google.script.run.withSuccessHandler(() => {
TSPwebapp.staffidInput.value = ""
TSPwebapp.pinInput.value = ""
} ).withFailureHandler(() => {
TSPwebapp.message.classList.remove("d-none")
setTimeout(() => {TSPwebapp.message.classList.add("d-none")},5000)
}).startFinishWork(payload)
} // TSPwebapp.startFinishWork function
TSPwebapp.startFinishBreak = function(e){
const payload = {
staffid: TSPwebapp.staffidInput.value,
pin: TSPwebapp.pinInput.value,
action: e.target.dataset.action
}
google.script.run.withSuccessHandler(() => {
TSPwebapp.staffidInput.value = ""
TSPwebapp.pinInput.value = ""
} ).withFailureHandler(() => {
TSPwebapp.message.classList.remove("d-none")
setTimeout(() => {TSPwebapp.message.classList.add("d-none")},5000)
}).startFinishBreak(payload)
} // TSPwebapp.startFinishBreak function
</script>
<script>
document.getElementById('key-pad').addEventListener('click', function (event) {
const number = event.target.innerText;
const calcInput = document.getElementById('typed-numbers');
if (isNaN(number)) {
if (number == 'C') {
calcInput.value = '';
}
}
else {
const previousNumber = calcInput.value;
const newNumber = previousNumber + number;
calcInput.value = newNumber;
}
});
</script>
<script>
document.addEventListener("DOMContentLoaded",TSPwebapp.onLoad)
document.addEventListener("DOMContentLoaded",function(){
google.script.run.withSuccessHandler(printBtn).useDataRange();
});
function printBtn(staffData) {
for (var i = 0; i < staffData.length; i++) {
var btn = document.createElement("button");
var t = document.createTextNode(staffData[i]);
btn.appendChild(t);
document.body.appendChild(btn);
}
}
window.onload = printBtn();
</script>
</body>
</html>
Here is the Google Apps Script code:
function doGet(e) {
Logger.log(e);
return HtmlService.createHtmlOutputFromFile("form");
}
function useDataRange () {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const wsStaff = ss.getSheetByName("Staff")
const staffData = wsStaff.getRange(2,2,wsStaff.getLastRow()-1,1).getValues()
Logger.log(staffData)
return staffData;
}
function startFinishBreak(payload){
console.log(payload)
if (!["Start work","Finish work","Start break","Finish break"].includes(payload.action)){
throw new Error("Sign in or sign out failed")
return
}
console.log("Initial check passed")
const ss = SpreadsheetApp.getActiveSpreadsheet()
const wsBreakData = ss.getSheetByName("Break data")
const wsStaff = ss.getSheetByName("Staff")
const staffData = wsStaff.getRange(2,2,wsStaff.getLastRow()-1,3).getValues()
const matchingStaff = staffData.filter(r => r[0].toString() === payload.staffid && r[2].toString() === payload.pin)
if(matchingStaff.length !== 1){
throw new Error("Sign in or sign out failed")
return
}
const idsData = wsBreakData.getRange(2,2,wsBreakData.getLastRow()-1,3).getValues()
console.log(idsData)
const matchingIdsData = idsData.filter(r => r[0].toString() === payload.staffid)
console.log(matchingIdsData)
const latestAction = matchingIdsData.length === 0 ? "Finish break" : matchingIdsData[matchingIdsData.length-1][2]
if (latestAction === payload.action){
throw new Error("Sign in or sign out failed")
return
}
wsBreakData.appendRow([new Date(),payload.staffid,payload.pin,payload.action])
}
function startFinishWork(payload){
console.log(payload)
if (!["Start work","Finish work","Start break","Finish break"].includes(payload.action)){
throw new Error("Sign in or sign out failed")
return
}
console.log("Initial check passed")
const ss = SpreadsheetApp.getActiveSpreadsheet()
const wsWorkData = ss.getSheetByName("Work data")
const wsStaff = ss.getSheetByName("Staff")
const staffData = wsStaff.getRange(2,2,wsStaff.getLastRow()-1,3).getValues()
const matchingStaff = staffData.filter(r => r[0].toString() === payload.staffid && r[2].toString() === payload.pin)
if(matchingStaff.length !== 1){
throw new Error("Sign in or sign out failed")
return
}
const idsData = wsWorkData.getRange(2,2,wsWorkData.getLastRow()-1,3).getValues()
console.log(idsData)
const matchingIdsData = idsData.filter(r => r[0].toString() === payload.staffid)
console.log(matchingIdsData)
const latestAction = matchingIdsData.length === 0 ? "Finish work" : matchingIdsData[matchingIdsData.length-1][2]
if (latestAction === payload.action){
throw new Error("Sign in or sign out failed")
return
}
wsWorkData.appendRow([new Date(),payload.staffid,payload.pin,payload.action])
}
I hope this description all more or less makes sense - I am trying something a way beyond by current capabilities but I do need to get this task done and hopefully I'm learning in the process.