Merge pull request '#6555 refactor to js' (#28) from 6555-refactorToJs into test
gitea/worker-time-control/pipeline/head There was a failure building this commit
Details
gitea/worker-time-control/pipeline/head There was a failure building this commit
Details
Reviewed-on: #28 Reviewed-by: Juan Ferrer <juan@verdnatura.es>
This commit is contained in:
commit
1db067a65a
|
@ -11,7 +11,6 @@ and open the template in the editor.
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link href="css/style.css" rel="stylesheet" type="text/css"/>
|
<link href="css/style.css" rel="stylesheet" type="text/css"/>
|
||||||
<link rel="icon" type="image/png" href="img/favicon.ico">
|
<link rel="icon" type="image/png" href="img/favicon.ico">
|
||||||
<script src="node_modules/jquery/dist/jquery.min.js" type="text/javascript"></script>
|
|
||||||
<script src="node_modules/fastclick/lib/fastclick.js" type="text/javascript"></script>
|
<script src="node_modules/fastclick/lib/fastclick.js" type="text/javascript"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="pinLogin">
|
<body class="pinLogin">
|
||||||
|
@ -36,12 +35,12 @@ and open the template in the editor.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<footer>
|
||||||
<div class="in">Inicio jornada</div>
|
<div class="in">Inicio jornada</div>
|
||||||
<div class="inMiddle">Inicio descanso</div>
|
<div class="inMiddle">Inicio descanso</div>
|
||||||
<div class="outMiddle">Fin descanso</div>
|
<div class="outMiddle">Fin descanso</div>
|
||||||
<div class="out">Fin jornada</div>
|
<div class="out">Fin jornada</div>
|
||||||
</div>
|
</footer>
|
||||||
|
|
||||||
<div class="confirm">
|
<div class="confirm">
|
||||||
<div class="contConfirm">
|
<div class="contConfirm">
|
||||||
|
|
|
@ -193,17 +193,15 @@ h3 {
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
.footer {
|
footer {
|
||||||
display: none;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100px;
|
height: 115px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
animation: fadeIn 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
.footer {
|
|
||||||
animation: faceIn 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
.in, .inMiddle {
|
.in, .inMiddle {
|
||||||
display: inline;
|
display: inline;
|
||||||
position: static;
|
position: static;
|
||||||
|
@ -342,7 +340,7 @@ header {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
.confirm {
|
.confirm {
|
||||||
display: none;
|
visibility: hidden;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -371,6 +369,14 @@ header {
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.fade-in {
|
||||||
|
visibility: visible;
|
||||||
|
animation: fadeIn 0.2s ease-in-out forwards;
|
||||||
|
}
|
||||||
|
.fade-out {
|
||||||
|
visibility: hidden;
|
||||||
|
animation: fadeOut 0.2s ease-in-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes slideIn {
|
@keyframes slideIn {
|
||||||
0% {
|
0% {
|
||||||
|
@ -382,7 +388,7 @@ header {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes faceIn {
|
@keyframes fadeIn {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
@ -390,6 +396,14 @@ header {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@keyframes fadeOut {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Poppins';
|
font-family: 'Poppins';
|
||||||
|
|
|
@ -11,7 +11,6 @@ and open the template in the editor.
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link href="css/style.css" rel="stylesheet" type="text/css"/>
|
<link href="css/style.css" rel="stylesheet" type="text/css"/>
|
||||||
<link rel="icon" type="image/png" href="img/favicon.ico">
|
<link rel="icon" type="image/png" href="img/favicon.ico">
|
||||||
<script src="node_modules/jquery/dist/jquery.min.js" type="text/javascript"></script>
|
|
||||||
<script src="node_modules/fastclick/lib/fastclick.js" type="text/javascript"></script>
|
<script src="node_modules/fastclick/lib/fastclick.js" type="text/javascript"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="pinLogin">
|
<body class="pinLogin">
|
||||||
|
@ -80,7 +79,7 @@ and open the template in the editor.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1>
|
<h1>
|
||||||
developed by Verdnatura with<span class="heart"></span>
|
powered by Verdnatura with<span class="heart"></span>
|
||||||
</h1>
|
</h1>
|
||||||
<h2 class="device">
|
<h2 class="device">
|
||||||
<p id="deviceLabel"></p>
|
<p id="deviceLabel"></p>
|
||||||
|
|
303
js/clockIn.js
303
js/clockIn.js
|
@ -1,237 +1,142 @@
|
||||||
let userData = "";
|
let userData = "";
|
||||||
|
const footer = document.querySelector("footer");
|
||||||
|
const txtName = document.querySelector("#txtNombre");
|
||||||
|
const inBtn = document.querySelector(".in");
|
||||||
|
const inMiddleBtn = document.querySelector(".inMiddle");
|
||||||
|
const outMiddleBtn = document.querySelector(".outMiddle");
|
||||||
|
const outBtn = document.querySelector(".out");
|
||||||
|
const timetableList = document.querySelector(".listHorario");
|
||||||
|
const weekDays = ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"];
|
||||||
|
|
||||||
$(document).ready(function () {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
userData = JSON.parse(localStorage.getItem("userData"));
|
userData = JSON.parse(localStorage.getItem("userData"));
|
||||||
FastClick.attach(document.body);
|
|
||||||
setView();
|
setView();
|
||||||
setEvents();
|
setEvents();
|
||||||
});
|
});
|
||||||
|
|
||||||
function setEvents() {
|
function setEvents() {
|
||||||
|
document.querySelector(".btnSalir").addEventListener("click", close);
|
||||||
|
|
||||||
$(".btnSalir").on("click", function () {
|
inBtn.addEventListener("click", () => clockIn("in"));
|
||||||
cerrar();
|
inMiddleBtn.addEventListener("click", () => clockIn("middle"));
|
||||||
});
|
outMiddleBtn.addEventListener("click", () => clockIn("middle"));
|
||||||
|
outBtn.addEventListener("click", () => clockIn("out"));
|
||||||
|
|
||||||
$(".in").on("click", function () {
|
setTimeout(close, 5000);
|
||||||
fichar('in');
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".inMiddle").on("click", function () {
|
|
||||||
fichar('middle');
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".outMiddle").on("click", function () {
|
|
||||||
fichar('middle');
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".out").on("click", function () {
|
|
||||||
fichar('out');
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
cerrar();
|
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setView() {
|
async function clockIn(direction) {
|
||||||
$(".footer").hide();
|
let timeout = 1000;
|
||||||
$("#txtNombre").text(userData["name"] + " " + userData["surname"]);
|
const data = await call("WorkerTimeControls/clockIn", {
|
||||||
getInfo();
|
method: "POST",
|
||||||
$("." + userData["button1"]).show();
|
body: {
|
||||||
$("." + userData["button2"]).show();
|
workerFk: userData["userFk"],
|
||||||
}
|
direction,
|
||||||
|
device: localStorage.getItem("device"),
|
||||||
function fichar(direction) {
|
},
|
||||||
const data = {
|
|
||||||
workerFk: userData['userFk'],
|
|
||||||
direction,
|
|
||||||
device: localStorage.getItem("device")
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post({
|
|
||||||
urlPath: 'WorkerTimeControls/clockIn',
|
|
||||||
jsonData: data,
|
|
||||||
processData: false,
|
|
||||||
success: function (msg) {
|
|
||||||
if (msg.error){
|
|
||||||
printErrores(msg);
|
|
||||||
setTimeout(function () {
|
|
||||||
cerrar();
|
|
||||||
}, 2000);
|
|
||||||
}else {
|
|
||||||
$(".confirm").fadeIn(200);
|
|
||||||
$(".txtConfirm").append('Fichada registrada correctamente');
|
|
||||||
setTimeout(function () {
|
|
||||||
cerrar();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function setView() {
|
if (data.error) {
|
||||||
$(".footer").hide();
|
let msg = "";
|
||||||
$(".in").hide();
|
for (const val of data) if (val.error) msg += `${val.error}\n`;
|
||||||
$(".inMiddle").hide();
|
printError(msg);
|
||||||
$(".outMiddle").hide();
|
|
||||||
$(".out").hide();
|
|
||||||
$("#txtNombre").text(userData["name"] + " " + userData["surname"]);
|
|
||||||
getInfo();
|
|
||||||
if(userData["button1"] === null && userData["button2"] === null ) {
|
|
||||||
printError ("Contacta con tu responsable")
|
|
||||||
} else {
|
} else {
|
||||||
$("." + userData["button1"]).show();
|
document.querySelector(".confirm").classList.add("fade-in");
|
||||||
$("." + userData["button2"]).show();
|
txtConfirm.textContent = "Fichada registrada correctamente";
|
||||||
|
timeout = 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTimeout(close, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInfo() {
|
function setView() {
|
||||||
const queryString = $.param({ workerFk: userData['userFk'] });
|
footer.style.hidden = true;
|
||||||
|
inBtn.style.display = "none";
|
||||||
$.get({
|
inMiddleBtn.style.display = "none";
|
||||||
urlPath: `WorkerTimeControls/getClockIn?${queryString}`,
|
outMiddleBtn.style.display = "none";
|
||||||
processData: false,
|
outBtn.style.display = "none";
|
||||||
success: function (data) {
|
|
||||||
$('.footer').show();
|
txtName.textContent = `${userData.name} ${userData.surname}`;
|
||||||
printTimetable(data);
|
getInfo();
|
||||||
}
|
|
||||||
});
|
if (userData.button1 === null && userData.button2 === null) return printError("Contacta con tu responsable");
|
||||||
|
|
||||||
|
document.querySelector(`.${userData.button1}`).style.display = "inline-block";
|
||||||
|
if (userData.button2) document.querySelector(`.${userData.button2}`).style.display = "inline-block";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getInfo() {
|
||||||
|
const data = await call("WorkerTimeControls/getClockIn", { params: { workerFk: userData["userFk"] } });
|
||||||
|
footer.style.hidden = false;
|
||||||
|
printTimetable(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function printTimetable(timetable) {
|
function printTimetable(timetable) {
|
||||||
const listWeekName = [
|
const dated = new Date();
|
||||||
'Domingo',
|
|
||||||
'Lunes',
|
|
||||||
'Martes',
|
|
||||||
'Miércoles',
|
|
||||||
'Jueves',
|
|
||||||
'Viernes',
|
|
||||||
'Sábado'
|
|
||||||
];;
|
|
||||||
let dated = new Date();
|
|
||||||
dated.setDate(dated.getDate() - 6);
|
dated.setDate(dated.getDate() - 6);
|
||||||
|
|
||||||
for (let i = 0; i < 6; i++) {
|
const table = document.createDocumentFragment();
|
||||||
$(".listHorario").append('<label>' + listWeekName[dated.getDay()] +'</label>');
|
const totalEl = document.querySelector(".total");
|
||||||
|
let totalHr = 0;
|
||||||
|
|
||||||
|
for (let day = 0; day < weekDays.length - 1; day++) {
|
||||||
|
const label = createElement("label", { text: weekDays[dated.getDay()] });
|
||||||
|
table.append(label);
|
||||||
dated.setDate(dated.getDate() + 1);
|
dated.setDate(dated.getDate() + 1);
|
||||||
}
|
}
|
||||||
$(".listHorario").append('<label class="hoy">HOY</label>');
|
|
||||||
$(".listHorario").append('<li class="hrTop"></li>');
|
|
||||||
|
|
||||||
for (let i = 0; i < timetable.length; i++) {
|
|
||||||
|
|
||||||
$(".listHorario").append(
|
|
||||||
'<li>' +
|
|
||||||
'<div class="time ' + ifIsEmpty(timetable[i]["6daysAgo"]) + '">' +
|
|
||||||
'<div>' +
|
|
||||||
'<img src="' + ifIsEmptyImage(timetable[i]["6daysAgoDirection"]) + '" />' +
|
|
||||||
'<p>' + ifIsEmptyText(timetable[i]["6daysAgo"]) + '</p>' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="time ' + ifIsEmpty(timetable[i]["5daysAgo"]) + '">' +
|
|
||||||
'<div>' +
|
|
||||||
'<img src="' + ifIsEmptyImage(timetable[i]["5daysAgoDirection"]) + '" />' +
|
|
||||||
'<p>' + ifIsEmptyText(timetable[i]["5daysAgo"]) + '</p>'+
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="time ' + ifIsEmpty(timetable[i]["4daysAgo"]) + '">' +
|
|
||||||
'<div>' +
|
|
||||||
'<img src="' + ifIsEmptyImage(timetable[i]["4daysAgoDirection"]) + '" />' +
|
|
||||||
'<p>' + ifIsEmptyText(timetable[i]["4daysAgo"]) + '</p>'+
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="time ' + ifIsEmpty(timetable[i]["3daysAgo"]) + '">' +
|
|
||||||
'<div>' +
|
|
||||||
'<img src="' + ifIsEmptyImage(timetable[i]["3daysAgoDirection"]) + '" />' +
|
|
||||||
'<p>' + ifIsEmptyText(timetable[i]["3daysAgo"]) + '</p>'+
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="time ' + ifIsEmpty(timetable[i]["2daysAgo"]) + '">' +
|
|
||||||
'<div>' +
|
|
||||||
'<img src="' + ifIsEmptyImage(timetable[i]["2daysAgoDirection"]) + '" />' +
|
|
||||||
'<p>' + ifIsEmptyText(timetable[i]["2daysAgo"]) + '</p>'+
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="time ' + ifIsEmpty(timetable[i]["1daysAgo"]) + '">' +
|
|
||||||
'<div>' +
|
|
||||||
'<img src="' + ifIsEmptyImage(timetable[i]["1daysAgoDirection"]) + '" />' +
|
|
||||||
'<p>' + ifIsEmptyText(timetable[i]["1daysAgo"]) + '</p>'+
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="time ' + ifIsEmpty(timetable[i]["0daysAgo"]) + '">' +
|
|
||||||
'<div>' +
|
|
||||||
'<img src="' + ifIsEmptyImage(timetable[i]["0daysAgoDirection"]) + '" />' +
|
|
||||||
'<p>' + ifIsEmptyText(timetable[i]["0daysAgo"]) + '</p>'+
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'</li>'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
printTotalHours(timetable);
|
|
||||||
}
|
|
||||||
|
|
||||||
function printTotalHours(timetable) {
|
table.append(createElement("label", { text: "HOY", classes: ["hoy"] }), createElement("li", { classes: ["hrTop"] }));
|
||||||
if(timetable.length > 0) {
|
|
||||||
|
|
||||||
$(".listHorario").append('<hr>');
|
const liContent = createElement("li", {});
|
||||||
$(".listHorario").append('<li><div class="time">' + secondsToHm(ifIsEmptyText(timetable[0]["6daysAgoTotal"]))
|
const liTotals = createElement("li", {});
|
||||||
+ ' h</div><div class="time">' + secondsToHm(ifIsEmptyText(timetable[0]["5daysAgoTotal"]))
|
timetable.forEach((row, index) => {
|
||||||
+ ' h</div><div class="time">' + secondsToHm(ifIsEmptyText(timetable[0]["4daysAgoTotal"]))
|
for (let day = weekDays.length - 1; day >= 0; day--) {
|
||||||
+ ' h</div><div class="time">' + secondsToHm(ifIsEmptyText(timetable[0]["3daysAgoTotal"]))
|
const img = createElement("img", { attrs: { src: isEmpty(row[`${day}daysAgoDirection`], "image") } });
|
||||||
+ ' h</div><div class="time">' + secondsToHm(ifIsEmptyText(timetable[0]["2daysAgoTotal"]))
|
const p = createElement("p", { text: isEmpty(row[`${day}daysAgo`], "text") });
|
||||||
+ ' h</div><div class="time">' + secondsToHm(ifIsEmptyText(timetable[0]["1daysAgoTotal"]))
|
|
||||||
+ ' h</div><div class="time">' + secondsToHm(ifIsEmptyText(timetable[0]["0daysAgoTotal"]))
|
|
||||||
+ ' h</div></li>');
|
|
||||||
|
|
||||||
$(".total").text('Total: ' +
|
|
||||||
secondsToHm(
|
|
||||||
Number(timetable[0]["6daysAgoTotal"] == null) +
|
|
||||||
Number(timetable[0]["5daysAgoTotal"]) +
|
|
||||||
Number(timetable[0]["4daysAgoTotal"]) +
|
|
||||||
Number(timetable[0]["3daysAgoTotal"]) +
|
|
||||||
Number(timetable[0]["2daysAgoTotal"]) +
|
|
||||||
Number(timetable[0]["1daysAgoTotal"]) +
|
|
||||||
Number(timetable[0]["0daysAgoTotal"])
|
|
||||||
) + ' h');
|
|
||||||
} else{
|
|
||||||
$(".total").text('Total: 0h');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
const innerDiv = createElement("div", { childs: [img, p] });
|
||||||
|
const outerDiv = createElement("div", { classes: ["time", isEmpty(row[`${day}daysAgo`])], childs: [innerDiv] });
|
||||||
|
liContent.append(outerDiv);
|
||||||
|
|
||||||
function printErrores(errores) {
|
if (index === 0) {
|
||||||
let error = '';
|
const div = createElement("div", { classes: ["time"], text: secondsToHm(timetable[0][`${day}daysAgoTotal`]) });
|
||||||
for (let i = 0; i < errores.length; i++) {
|
liTotals.append(div);
|
||||||
if (errores[i].error) {
|
totalHr += timetable[0][`${day}daysAgoTotal`] || 0;
|
||||||
error += errores[i].error + "<br>";
|
}
|
||||||
}
|
}
|
||||||
}
|
table.append(liContent);
|
||||||
printError(error);
|
if (index === timetable.length - 1) table.append(createElement("hr", {}), liTotals);
|
||||||
|
});
|
||||||
|
|
||||||
|
totalEl.innerText = `Total: ${totalHr ? secondsToHm(totalHr) : 0} h`;
|
||||||
|
timetableList.append(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ifIsEmpty(value) {
|
const isEmpty = (value, type) => {
|
||||||
return value.trim() ? "show" : "hide";
|
const val = value?.toString()?.trim();
|
||||||
}
|
if (!type) return val ? "show" : "hide";
|
||||||
|
if (type === "image") return val ? `img/${val}.svg` : "img/in.svg";
|
||||||
|
if (type === "text") return val ? val : "00:00";
|
||||||
|
};
|
||||||
|
|
||||||
function ifIsEmptyImage(value) {
|
function close() {
|
||||||
return value.trim() ? `img/${value}.svg` :"img/in.svg";
|
|
||||||
}
|
|
||||||
|
|
||||||
function ifIsEmptyText(value) {
|
|
||||||
return value.toString().trim() ? value : "00:00";
|
|
||||||
}
|
|
||||||
|
|
||||||
function cerrar(){
|
|
||||||
localStorage.removeItem("userData");
|
localStorage.removeItem("userData");
|
||||||
setTimeout(function () {
|
setTimeout(() => (window.location = "index.html"), 200);
|
||||||
window.location='index.html';
|
|
||||||
}, 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function secondsToHm(seconds) {
|
function secondsToHm(seconds) {
|
||||||
seconds = Number(seconds);
|
seconds = +seconds;
|
||||||
let hours = Math.floor(seconds / 3600);
|
let hours = Math.floor(seconds / 3600);
|
||||||
let minutes = Math.floor(seconds % 3600 / 60);
|
let minutes = Math.floor((seconds % 3600) / 60);
|
||||||
return hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
|
return hours.toString().padStart(2, "0") + ":" + minutes.toString().padStart(2, "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createElement(tag, { classes = [], text, attrs = {}, childs = [] }) {
|
||||||
|
const el = document.createElement(tag);
|
||||||
|
if (classes) el.classList.add(...classes);
|
||||||
|
if (text) el.textContent = text;
|
||||||
|
for (const [key, value] of Object.entries(attrs)) el.setAttribute(key, value);
|
||||||
|
if (childs) el.append(...childs);
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
130
js/index.js
130
js/index.js
|
@ -1,84 +1,70 @@
|
||||||
let pin = "";
|
let pin = "";
|
||||||
|
if ("addEventListener" in document) {
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
FastClick.attach(document.body);
|
||||||
|
|
||||||
$(document).ready(function () {
|
const heartEl = document.querySelector("body > h1 > span");
|
||||||
FastClick.attach(document.body);
|
const txtPin = document.querySelector("#txtPin");
|
||||||
setEvents();
|
refreshDeviceLabel();
|
||||||
});
|
|
||||||
|
|
||||||
function setEvents() {
|
heartEl.addEventListener("click", () => {
|
||||||
const heartEl = document.querySelector('body > h1 > span');
|
Swal.fire({
|
||||||
refreshDeviceLabel()
|
title: "Iniciar sesión",
|
||||||
|
html: `
|
||||||
heartEl.addEventListener('click', function() {
|
<input id="device" class="swal2-input" type="text" placeholder="Dispositivo" value="${localStorage.getItem("device") ?? ""}">
|
||||||
Swal.fire({
|
<input id="user" class="swal2-input" type="text" placeholder="Usuario" value="${localStorage.getItem("user") ?? ""}">
|
||||||
title: 'Iniciar sesión',
|
<input id="pass" class="swal2-input" type="password" placeholder="Contraseña">`,
|
||||||
html:
|
confirmButtonText: "Login",
|
||||||
`<input id="device" class="swal2-input" type="text" placeholder="Dispositivo" value="${localStorage.getItem('device') ?? ''}">
|
showCloseButton: true,
|
||||||
<input id="user" class="swal2-input" type="text" placeholder="Usuario" value="${localStorage.getItem('user') ?? ''}">
|
showCancelButton: false,
|
||||||
<input id="pass" class="swal2-input" type="password" placeholder="Contraseña">`,
|
}).then(async (result) => {
|
||||||
confirmButtonText: 'Login',
|
if (result.isConfirmed)
|
||||||
showCloseButton: true,
|
signIn(document.querySelector("#user").value, document.querySelector("#pass").value, document.querySelector("#device").value);
|
||||||
showCancelButton: false,
|
});
|
||||||
}).then(async (result) => {
|
|
||||||
if(result.isConfirmed) {
|
|
||||||
const user = $('#user').val();
|
|
||||||
const pass = $('#pass').val();
|
|
||||||
const device = $('#device').val();
|
|
||||||
signIn(user, pass, device);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
$(".btnnum").on("click", function () {
|
document.querySelectorAll(".btnnum").forEach((btn) => {
|
||||||
pin += parseInt($(this).children().html());
|
btn.addEventListener("click", (e) => {
|
||||||
$("#txtPin").text(pin);
|
pin += +e.currentTarget.children[0].innerHTML;
|
||||||
});
|
txtPin.textContent = pin;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$(".btnCancel").on("click", function () {
|
document.querySelector(".btnCancel").addEventListener("click", () => {
|
||||||
pin = "";
|
|
||||||
$("#txtPin").text("ID USUARIO");
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".btnOk").on("click", function () {
|
|
||||||
if (pin) {
|
|
||||||
login();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function login() {
|
|
||||||
$.post({
|
|
||||||
urlPath: 'WorkerTimeControls/login',
|
|
||||||
jsonData: {pin},
|
|
||||||
processData: false,
|
|
||||||
success: function (data) {
|
|
||||||
localStorage.setItem("userData", JSON.stringify(data));
|
|
||||||
window.location = "clockIn.html";
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
$("#txtPin").text("ID USUARIO");
|
|
||||||
pin = "";
|
pin = "";
|
||||||
}
|
txtPin.textContent = "ID USUARIO";
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector(".btnOk").addEventListener("click", () => pin && login());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function signIn(user, password, device) {
|
async function login() {
|
||||||
$.post({
|
try {
|
||||||
urlPath: 'vnUsers/sign-in',
|
const data = await call("WorkerTimeControls/login", {
|
||||||
jsonData: {user, password},
|
method: "POST",
|
||||||
processData: false,
|
body: { pin },
|
||||||
success: function (data) {
|
});
|
||||||
localStorage.setItem("token", data.token);
|
localStorage.setItem("userData", JSON.stringify(data));
|
||||||
localStorage.setItem("ttl", data.ttl);
|
window.location = "clockIn.html";
|
||||||
localStorage.setItem("user", user);
|
} catch (e) {
|
||||||
localStorage.setItem("device", device);
|
document.querySelector("#txtPin").textContent = "ID USUARIO";
|
||||||
localStorage.setItem("created", Date.now());
|
pin = "";
|
||||||
getTokenConfig();
|
}
|
||||||
refreshDeviceLabel();
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshDeviceLabel() {
|
async function signIn(user, password, device) {
|
||||||
$("#deviceLabel").text(localStorage.getItem('device') ?? '')
|
const data = await call("vnUsers/sign-in", {
|
||||||
}
|
method: "POST",
|
||||||
|
body: { user, password },
|
||||||
|
});
|
||||||
|
localStorage.setItem("token", data.token);
|
||||||
|
localStorage.setItem("ttl", data.ttl);
|
||||||
|
localStorage.setItem("user", user);
|
||||||
|
localStorage.setItem("device", device);
|
||||||
|
localStorage.setItem("created", Date.now());
|
||||||
|
getTokenConfig();
|
||||||
|
refreshDeviceLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshDeviceLabel = () => (document.querySelector("#deviceLabel").textContent = localStorage.getItem("device") ?? "");
|
||||||
|
|
226
js/main.js
226
js/main.js
|
@ -1,130 +1,124 @@
|
||||||
const renewPeriod = localStorage.getItem('renewPeriod');
|
const renewPeriod = localStorage.getItem("renewPeriod");
|
||||||
let intervalId, isCheckingToken;
|
let intervalId, isCheckingToken;
|
||||||
|
const txtConfirm = document.querySelector(".txtConfirm");
|
||||||
|
const confirmBtn = document.querySelector(".confirm");
|
||||||
|
|
||||||
function confirmReset() {
|
function confirmReset() {
|
||||||
$(".confirm").removeClass('confirmKO');
|
confirmBtn.classList.remove("confirmKO", "fade-in", "fade-out");
|
||||||
$(".txtConfirm").empty();
|
confirmBtn.style.hidden = true;
|
||||||
|
txtConfirm.textContent = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function printError(msg){
|
function printError(msg) {
|
||||||
confirmReset();
|
confirmReset();
|
||||||
$(".txtConfirm").append(msg);
|
const txtConfirm = document.querySelector(".txtConfirm");
|
||||||
$(".confirm").addClass('confirmKO');
|
txtConfirm.textContent = msg;
|
||||||
$(".confirm").fadeIn(200);
|
confirmBtn.classList.add("confirmKO");
|
||||||
setTimeout(function() {
|
confirmBtn.style.hidden = false;
|
||||||
$(".confirm").fadeOut(200);
|
|
||||||
|
confirmBtn.classList.add("fade-in");
|
||||||
|
setTimeout(() => {
|
||||||
|
confirmBtn.classList.add("fade-out");
|
||||||
setTimeout(confirmReset, 200);
|
setTimeout(confirmReset, 200);
|
||||||
}, 2300);
|
}, 2300);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renewToken() {
|
async function renewToken() {
|
||||||
$.post({
|
const data = await call("vnUsers/renewToken", { method: "POST" });
|
||||||
urlPath: 'vnUsers/renewToken',
|
|
||||||
processData: false,
|
localStorage.setItem("ttl", data.ttl);
|
||||||
success: function (data) {
|
localStorage.setItem("created", Date.now());
|
||||||
localStorage.setItem("token", data.id);
|
|
||||||
localStorage.setItem("ttl", data.ttl);
|
|
||||||
localStorage.setItem("created", Date.now());
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTokenConfig() {
|
async function getTokenConfig() {
|
||||||
const filter = {fields: ['renewInterval', 'renewPeriod']};
|
const data = await call("AccessTokenConfigs/findOne", {
|
||||||
$.get({
|
params: { filter: { fields: ["renewInterval", "renewPeriod"] } },
|
||||||
urlPath: 'AccessTokenConfigs/findOne',
|
|
||||||
jsonData: filter,
|
|
||||||
processData: false,
|
|
||||||
success: function (data) {
|
|
||||||
if (!data) return;
|
|
||||||
localStorage.setItem('renewPeriod', data.renewPeriod);
|
|
||||||
clearInterval(intervalId);
|
|
||||||
intervalId = setInterval(() => checkValidity(), data.renewInterval * 1000);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkValidity() {
|
|
||||||
const created = +localStorage.getItem('created');
|
|
||||||
const ttl = localStorage.getItem('ttl');
|
|
||||||
|
|
||||||
if (isCheckingToken || !created) return;
|
|
||||||
isCheckingToken = true;
|
|
||||||
|
|
||||||
const renewPeriodInSeconds = Math.min(ttl, renewPeriod) * 1000;
|
|
||||||
const maxDate = created + renewPeriodInSeconds;
|
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
if (now.getTime() <= maxDate) return isCheckingToken = false;
|
|
||||||
|
|
||||||
renewToken();
|
|
||||||
isCheckingToken = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajaxPrefilter(function(xhr) {
|
|
||||||
const orgErrorHandler = xhr.error;
|
|
||||||
const token = localStorage.getItem('token')
|
|
||||||
|
|
||||||
Object.assign(xhr, {
|
|
||||||
url: `/api/${xhr.urlPath}`,
|
|
||||||
headers: {
|
|
||||||
Authorization : token
|
|
||||||
},
|
|
||||||
timeout: 2000,
|
|
||||||
contentType: 'application/json; charset=utf-8',
|
|
||||||
dataType: 'json',
|
|
||||||
processData: false,
|
|
||||||
data: JSON.stringify(xhr.jsonData),
|
|
||||||
error: function(xhr, textStatus, err) {
|
|
||||||
if (orgErrorHandler) {
|
|
||||||
try {
|
|
||||||
orgErrorHandler(xhr, textStatus, err);
|
|
||||||
} catch (e) {
|
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(xhr?.responseJSON?.error?.code == 'periodNotExceeded') return;
|
|
||||||
|
|
||||||
switch (textStatus){
|
|
||||||
case 'parsererror':
|
|
||||||
mensaje = 'Requested JSON parse failed';
|
|
||||||
break;
|
|
||||||
case 'timeout':
|
|
||||||
mensaje = 'Time out error';
|
|
||||||
break;
|
|
||||||
case 'abort':
|
|
||||||
mensaje = 'Ajax request aborted';
|
|
||||||
break;
|
|
||||||
case 'error':
|
|
||||||
if (xhr?.responseJSON?.error?.name == 'UserError') {
|
|
||||||
mensaje = xhr.responseJSON.error.message;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (xhr.status){
|
|
||||||
case 0:
|
|
||||||
mensaje = 'Not connect: Verify Network';
|
|
||||||
break;
|
|
||||||
case 504:
|
|
||||||
mensaje = 'No se ha podido conectar con Salix, consulta con informática';
|
|
||||||
break;
|
|
||||||
case 555:
|
|
||||||
mensaje = JSON.parse(xhr.statusText).Message;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (xhr.status >= 400 && xhr.status < 500)
|
|
||||||
mensaje = xhr.statusText;
|
|
||||||
else
|
|
||||||
mensaje = 'Ha ocurrido un error, consulta con informática';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mensaje = 'Ha ocurrido un error, consulta con informática';
|
|
||||||
}
|
|
||||||
printError(mensaje);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if(renewPeriod) getTokenConfig();
|
if (!data) return;
|
||||||
|
|
||||||
|
localStorage.setItem("renewPeriod", data.renewPeriod);
|
||||||
|
clearInterval(intervalId);
|
||||||
|
|
||||||
|
intervalId = setInterval(() => {
|
||||||
|
const created = +localStorage.getItem("created");
|
||||||
|
const ttl = localStorage.getItem("ttl");
|
||||||
|
|
||||||
|
if (isCheckingToken || !created) return;
|
||||||
|
isCheckingToken = true;
|
||||||
|
|
||||||
|
const renewPeriodInSeconds = Math.min(ttl, renewPeriod) * 1000;
|
||||||
|
const maxDate = created + renewPeriodInSeconds;
|
||||||
|
|
||||||
|
if (new Date().getTime() <= maxDate) return (isCheckingToken = false);
|
||||||
|
|
||||||
|
renewToken();
|
||||||
|
isCheckingToken = false;
|
||||||
|
}, data.renewInterval * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function call(url, { method = "GET", body = {}, params = {} }) {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const { signal } = controller;
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), 2000);
|
||||||
|
const opts = {
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
Authorization: localStorage.getItem("token"),
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
signal,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (method === "GET") {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
for (let [key, value] of Object.entries(params)) {
|
||||||
|
searchParams.append(key, typeof value === "object" ? JSON.stringify(value) : value);
|
||||||
|
}
|
||||||
|
url += "?" + searchParams.toString();
|
||||||
|
} else if (method === "POST") opts.body = JSON.stringify(body);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/${url}`, opts);
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (res.ok) return data;
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
throw data.error;
|
||||||
|
} catch (e) {
|
||||||
|
let mensaje = "Ha ocurrido un error, consulta con informática";
|
||||||
|
|
||||||
|
switch (e.name) {
|
||||||
|
case "SyntaxError":
|
||||||
|
mensaje = "Requested JSON parse failed";
|
||||||
|
break;
|
||||||
|
case "TimeoutError":
|
||||||
|
mensaje = "Time out error";
|
||||||
|
break;
|
||||||
|
case "AbortError":
|
||||||
|
mensaje = "Ajax request aborted";
|
||||||
|
break;
|
||||||
|
case "UserError":
|
||||||
|
mensaje = e.message;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
switch (e.statusCode) {
|
||||||
|
case 0:
|
||||||
|
mensaje = "Not connect: Verify Network";
|
||||||
|
break;
|
||||||
|
case 504:
|
||||||
|
mensaje = "No se ha podido conectar con Salix, consulta con informática";
|
||||||
|
break;
|
||||||
|
case 555:
|
||||||
|
mensaje = "Error 555";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (e.statusCode >= 400 && e.statusCode < 500) mensaje = e.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printError(mensaje);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renewPeriod) getTokenConfig();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,11 +18,10 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"fastclick": "^1.0.6",
|
"fastclick": "^1.0.6",
|
||||||
"jquery": "^3.7.0",
|
"sweetalert2": "^11.6.13"
|
||||||
"sweetalert2": "11.10.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"express": "^4.18.2",
|
"express": "^4.19.2",
|
||||||
"http-proxy-middleware": "^2.0.6"
|
"http-proxy-middleware": "^2.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue