mirror of
https://github.com/DerTyp7/time-tracking.git
synced 2025-10-29 12:32:11 +01:00
table and entries
This commit is contained in:
@@ -1 +1,25 @@
|
|||||||
// ExpressJS server
|
// Dependencies
|
||||||
|
const express = require("express");
|
||||||
|
const configFile = require("./config");
|
||||||
|
const logger = require("./logger");
|
||||||
|
const cors = require("cors");
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
const app = express();
|
||||||
|
const config = configFile.config;
|
||||||
|
const port = config.port;
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
const apiEntry = require("./routes/api/entry");
|
||||||
|
|
||||||
|
// Set up the express server
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
|
app.use(express.json()); // Parse JSON data from requests
|
||||||
|
app.use(express.urlencoded({ extended: true })); // Parse URL encoded data from requests
|
||||||
|
|
||||||
|
// routes
|
||||||
|
app.use("/api/entry", apiEntry);
|
||||||
|
|
||||||
|
// Start the express server
|
||||||
|
app.listen(port, () => logger.info("Server started", `Port: ${port}`));
|
||||||
|
|||||||
11
backend/config.js
Normal file
11
backend/config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const config = {
|
||||||
|
db: {
|
||||||
|
host: "127.0.0.1",
|
||||||
|
user: "root",
|
||||||
|
password: "", // In production: "InfraTag!" SORRY FOR CLEAR TEXT PASSWORD
|
||||||
|
database: "rme-time-tracking",
|
||||||
|
},
|
||||||
|
port: 8080, // Port for the server
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = { config };
|
||||||
34
backend/handlers/mysql_handler.js
Normal file
34
backend/handlers/mysql_handler.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Handles the connection to the MySQL database
|
||||||
|
* - Connects to the database
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Dependencies
|
||||||
|
const mysql = require("mysql");
|
||||||
|
const configFile = require("../config");
|
||||||
|
const logger = require("../logger");
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
const config = configFile.config;
|
||||||
|
|
||||||
|
// Connection to the database
|
||||||
|
const con = mysql.createConnection({
|
||||||
|
host: config.db.host,
|
||||||
|
user: config.db.user,
|
||||||
|
password: config.db.password,
|
||||||
|
database: config.db.database,
|
||||||
|
});
|
||||||
|
|
||||||
|
con.connect(function (err) {
|
||||||
|
if (err) throw err;
|
||||||
|
logger.info(
|
||||||
|
`Connected to MySQL`,
|
||||||
|
`${config.db.user}@${config.db.host}/${config.db.database}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
con.on("error", () => {
|
||||||
|
logger.error("MySQL Error");
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { con };
|
||||||
25
backend/handlers/request_handler.js
Normal file
25
backend/handlers/request_handler.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Handlers which can be included into the request handler chain.
|
||||||
|
|
||||||
|
// Dependencies
|
||||||
|
const logger = require("../logger");
|
||||||
|
|
||||||
|
// better logging of requests
|
||||||
|
function LoggerHandler(req, res, next) {
|
||||||
|
const ip = (req.headers["x-forwarded-for"] || req.socket.remoteAddress || "")
|
||||||
|
.split(",")[0]
|
||||||
|
.trim()
|
||||||
|
.split(":")[3]; // get the ip of the client
|
||||||
|
|
||||||
|
if (req.method == "GET") {
|
||||||
|
// If the request is a GET request
|
||||||
|
logger.get(req.originalUrl, ip); // Log the request
|
||||||
|
} else if (req.method == "POST") {
|
||||||
|
// If the request is a POST request
|
||||||
|
logger.post(req.originalUrl, ip); // Log the request
|
||||||
|
}
|
||||||
|
next(); // Continue to the next handler
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
LoggerHandler,
|
||||||
|
};
|
||||||
103
backend/logger.js
Normal file
103
backend/logger.js
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
const SHOW_TIME = true;
|
||||||
|
|
||||||
|
function getTimestamp() {
|
||||||
|
let date_ob = new Date();
|
||||||
|
|
||||||
|
// current date
|
||||||
|
// adjust 0 before single digit date
|
||||||
|
let date = ("0" + date_ob.getDate()).slice(-2);
|
||||||
|
|
||||||
|
// current month
|
||||||
|
let month = ("0" + (date_ob.getMonth() + 1)).slice(-2);
|
||||||
|
|
||||||
|
// current year
|
||||||
|
let year = date_ob.getFullYear();
|
||||||
|
|
||||||
|
// current hours
|
||||||
|
let hours = ("0" + date_ob.getHours()).slice(-2);
|
||||||
|
|
||||||
|
// current minutes
|
||||||
|
let minutes = ("0" + date_ob.getMinutes()).slice(-2);
|
||||||
|
|
||||||
|
// current seconds
|
||||||
|
let seconds = ("0" + date_ob.getSeconds()).slice(-2);
|
||||||
|
|
||||||
|
if (SHOW_TIME) {
|
||||||
|
return hours + ":" + minutes + ":" + seconds;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmd(msg, info = null) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[36m%s\x1b[0m",
|
||||||
|
`${
|
||||||
|
getTimestamp() != null ? "[" + getTimestamp() + "]" : ""
|
||||||
|
}[COMMAND] ${msg} ${info != null ? "- " + info : ""}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function info(msg, info = null) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[37m%s\x1b[0m",
|
||||||
|
`${getTimestamp() != null ? "[" + getTimestamp() + "]" : ""}[INFO] ${msg} ${
|
||||||
|
info != null ? "- " + info : ""
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(msg, info = null) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[31m%s\x1b[0m",
|
||||||
|
`${
|
||||||
|
getTimestamp() != null ? "[" + getTimestamp() + "]" : ""
|
||||||
|
}[ERROR] ${msg} ${info != null ? "- " + info : ""}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(msg, info = null) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[37m\x1b[2m%s\x1b[0m",
|
||||||
|
`${getTimestamp() != null ? "[" + getTimestamp() + "]" : ""}[GET] ${msg} ${
|
||||||
|
info != null ? "- " + info : ""
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function post(msg, info = null) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[37m\x1b[2m%s\x1b[0m",
|
||||||
|
`${getTimestamp() != null ? "[" + getTimestamp() + "]" : ""}[POST] ${msg} ${
|
||||||
|
info != null ? "- " + info : ""
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function socket(msg, type) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[35m\x1b[1m%s\x1b[0m",
|
||||||
|
`${
|
||||||
|
getTimestamp() != null ? "[" + getTimestamp() + "]" : ""
|
||||||
|
}[SOCKET.IO][${type}] ${msg}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function event(msg, type) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[35m\x1b[1m%s\x1b[0m",
|
||||||
|
`${
|
||||||
|
getTimestamp() != null ? "[" + getTimestamp() + "]" : ""
|
||||||
|
}[EVENT][${type}] ${msg}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
cmd,
|
||||||
|
info,
|
||||||
|
error,
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
socket,
|
||||||
|
event,
|
||||||
|
};
|
||||||
209
backend/package-lock.json
generated
209
backend/package-lock.json
generated
@@ -9,7 +9,9 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.1"
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.18.1",
|
||||||
|
"mysql": "^2.18.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
@@ -29,6 +31,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||||
},
|
},
|
||||||
|
"node_modules/bignumber.js": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.20.0",
|
"version": "1.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
||||||
@@ -104,6 +114,23 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||||
},
|
},
|
||||||
|
"node_modules/core-util-is": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
|
},
|
||||||
|
"node_modules/cors": {
|
||||||
|
"version": "2.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||||
|
"dependencies": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
@@ -308,6 +335,11 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
|
},
|
||||||
"node_modules/media-typer": {
|
"node_modules/media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
@@ -364,6 +396,25 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
|
"node_modules/mysql": {
|
||||||
|
"version": "2.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
|
||||||
|
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
|
||||||
|
"dependencies": {
|
||||||
|
"bignumber.js": "9.0.0",
|
||||||
|
"readable-stream": "2.3.7",
|
||||||
|
"safe-buffer": "5.1.2",
|
||||||
|
"sqlstring": "2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mysql/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
"node_modules/negotiator": {
|
"node_modules/negotiator": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||||
@@ -372,6 +423,14 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-inspect": {
|
"node_modules/object-inspect": {
|
||||||
"version": "1.12.0",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
|
||||||
@@ -404,6 +463,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||||
},
|
},
|
||||||
|
"node_modules/process-nextick-args": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
|
},
|
||||||
"node_modules/proxy-addr": {
|
"node_modules/proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
@@ -452,6 +516,25 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readable-stream/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
"node_modules/safe-buffer": {
|
"node_modules/safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
@@ -536,6 +619,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sqlstring": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
|
||||||
|
"integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
@@ -544,6 +635,19 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/string_decoder/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
"node_modules/toidentifier": {
|
"node_modules/toidentifier": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
@@ -572,6 +676,11 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
|
},
|
||||||
"node_modules/utils-merge": {
|
"node_modules/utils-merge": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
@@ -604,6 +713,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||||
},
|
},
|
||||||
|
"bignumber.js": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
|
||||||
|
},
|
||||||
"body-parser": {
|
"body-parser": {
|
||||||
"version": "1.20.0",
|
"version": "1.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
||||||
@@ -660,6 +774,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||||
},
|
},
|
||||||
|
"core-util-is": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
|
},
|
||||||
|
"cors": {
|
||||||
|
"version": "2.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||||
|
"requires": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
@@ -818,6 +946,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
||||||
},
|
},
|
||||||
|
"isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
|
},
|
||||||
"media-typer": {
|
"media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
@@ -856,11 +989,34 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
|
"mysql": {
|
||||||
|
"version": "2.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
|
||||||
|
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
|
||||||
|
"requires": {
|
||||||
|
"bignumber.js": "9.0.0",
|
||||||
|
"readable-stream": "2.3.7",
|
||||||
|
"safe-buffer": "5.1.2",
|
||||||
|
"sqlstring": "2.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"negotiator": {
|
"negotiator": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
|
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
|
||||||
},
|
},
|
||||||
|
"object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
|
},
|
||||||
"object-inspect": {
|
"object-inspect": {
|
||||||
"version": "1.12.0",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
|
||||||
@@ -884,6 +1040,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||||
},
|
},
|
||||||
|
"process-nextick-args": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
|
},
|
||||||
"proxy-addr": {
|
"proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
@@ -917,6 +1078,27 @@
|
|||||||
"unpipe": "1.0.0"
|
"unpipe": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
@@ -980,11 +1162,31 @@
|
|||||||
"object-inspect": "^1.9.0"
|
"object-inspect": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sqlstring": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
|
||||||
|
"integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A="
|
||||||
|
},
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
||||||
},
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"toidentifier": {
|
"toidentifier": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
@@ -1004,6 +1206,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||||
},
|
},
|
||||||
|
"util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
|
},
|
||||||
"utils-merge": {
|
"utils-merge": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.1"
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.18.1",
|
||||||
|
"mysql": "^2.18.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
118
backend/routes/api/entry.js
Normal file
118
backend/routes/api/entry.js
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// Dependencies
|
||||||
|
const express = require("express");
|
||||||
|
const mysql = require("../../handlers/mysql_handler");
|
||||||
|
const logger = require("../../logger");
|
||||||
|
const request_handler = require("../../handlers/request_handler");
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
const con = mysql.con;
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
function formatDate(date) {
|
||||||
|
let result = date.split("T")[0].split("-");
|
||||||
|
result = result[2] + "." + result[1] + "." + result[0];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate time difference
|
||||||
|
function calcInd(date, checkedIn, checkedOut) {
|
||||||
|
date = date.split("T")[0];
|
||||||
|
let ind =
|
||||||
|
(new Date(date + "T" + checkedOut) - new Date(date + "T" + checkedIn)) /
|
||||||
|
1000 /
|
||||||
|
60 /
|
||||||
|
60;
|
||||||
|
|
||||||
|
// round ind to 2 decimal places
|
||||||
|
ind = Math.round(ind * 100) / 100;
|
||||||
|
|
||||||
|
if (ind > 6) {
|
||||||
|
ind -= 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ind;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Bei dieser Funktion habe 112312 Gehirnzellen verloren. Bitte nicht drauf ansprechen.
|
||||||
|
function calcNorm(date, checkedIn, checkedOut) {
|
||||||
|
let ind = calcInd(date, checkedIn, checkedOut).toString().split(".");
|
||||||
|
|
||||||
|
let hours = parseInt(ind[0]);
|
||||||
|
let minutes = 0;
|
||||||
|
|
||||||
|
if (ind.length > 1) {
|
||||||
|
minutes = parseInt(ind[1] * 6) / 10;
|
||||||
|
minutes = Math.round(minutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hours < 10) {
|
||||||
|
hours = "0" + hours;
|
||||||
|
}
|
||||||
|
if (minutes < 10) {
|
||||||
|
minutes = "0" + minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hours + ":" + minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(time) {
|
||||||
|
let result = time.split(":");
|
||||||
|
result = result[0] + ":" + result[1];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInMonth(date, monthYear) {
|
||||||
|
if (monthYear == undefined) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
date = date.split("-");
|
||||||
|
let month = parseInt(date[1]);
|
||||||
|
let year = parseInt(date[0]);
|
||||||
|
monthYear = monthYear.split("-");
|
||||||
|
if (month == monthYear[0] && year == monthYear[1]) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// monthYear = month number-year number (04-2019)
|
||||||
|
router.get("/all/:monthYear?", request_handler.LoggerHandler, (req, res) => {
|
||||||
|
const monthYear = req.params.monthYear;
|
||||||
|
|
||||||
|
con.query(`SELECT * FROM entries ORDER BY date ASC`, (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
logger.error(err, "routes/api/entries.js");
|
||||||
|
res.send(JSON.parse(JSON.stringify({ error: err }))); // Send error message
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
let entries = [];
|
||||||
|
result = JSON.parse(JSON.stringify(result));
|
||||||
|
|
||||||
|
for (let i = 0; i < result.length; i++) {
|
||||||
|
if (isInMonth(result[i].date, monthYear)) {
|
||||||
|
entries.push({
|
||||||
|
date: formatDate(result[i].date),
|
||||||
|
checkedIn: formatTime(result[i].checked_in),
|
||||||
|
checkedOut: formatTime(result[i].checked_out),
|
||||||
|
ind: calcInd(
|
||||||
|
result[i].date,
|
||||||
|
result[i].checked_in,
|
||||||
|
result[i].checked_out
|
||||||
|
),
|
||||||
|
norm: calcNorm(
|
||||||
|
result[i].date,
|
||||||
|
result[i].checked_in,
|
||||||
|
result[i].checked_out
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send(entries); // Send result
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
58
frontend/package-lock.json
generated
58
frontend/package-lock.json
generated
@@ -13,6 +13,7 @@
|
|||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"sass": "^1.51.0",
|
"sass": "^1.51.0",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
@@ -7991,6 +7992,14 @@
|
|||||||
"he": "bin/he"
|
"he": "bin/he"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/history": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hoopy": {
|
"node_modules/hoopy": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||||
@@ -13425,6 +13434,30 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"history": "^5.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-router-dom": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
|
||||||
|
"dependencies": {
|
||||||
|
"history": "^5.2.0",
|
||||||
|
"react-router": "6.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-scripts": {
|
"node_modules/react-scripts": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||||
@@ -21933,6 +21966,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||||
},
|
},
|
||||||
|
"history": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hoopy": {
|
"hoopy": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||||
@@ -25729,6 +25770,23 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||||
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
|
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
|
||||||
},
|
},
|
||||||
|
"react-router": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
|
||||||
|
"requires": {
|
||||||
|
"history": "^5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-router-dom": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
|
||||||
|
"requires": {
|
||||||
|
"history": "^5.2.0",
|
||||||
|
"react-router": "6.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-scripts": {
|
"react-scripts": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"sass": "^1.51.0",
|
"sass": "^1.51.0",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
|||||||
@@ -1,15 +1,24 @@
|
|||||||
import "./css/App.scss";
|
import "./css/app.scss";
|
||||||
|
import ServerProvider from "./contexts/ServerContext";
|
||||||
|
import Table from "./components/table/Table";
|
||||||
|
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div id="app">
|
<ServerProvider>
|
||||||
<div id="content" className="app-container">
|
<div id="app">
|
||||||
<h1>Hello World</h1>
|
<div id="content" className="app-container">
|
||||||
|
<Router>
|
||||||
|
<Routes>
|
||||||
|
<Route exact path="/table/:monthYear" element={<Table />} />
|
||||||
|
</Routes>
|
||||||
|
</Router>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar" className="app-container">
|
||||||
|
<h1>Sidebar</h1>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="sidebar" className="app-container">
|
</ServerProvider>
|
||||||
<h1>Sidebar</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
frontend/src/components/table/Header.jsx
Normal file
25
frontend/src/components/table/Header.jsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import "../../css/components/table.scss";
|
||||||
|
|
||||||
|
function Header({ date, checkedIn, checkedOut, ind, norm }) {
|
||||||
|
return (
|
||||||
|
<div className="table-header">
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{date}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{checkedIn}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{checkedOut}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{ind}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{norm}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header;
|
||||||
25
frontend/src/components/table/Row.jsx
Normal file
25
frontend/src/components/table/Row.jsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import "../../css/components/table.scss";
|
||||||
|
|
||||||
|
function Row({ date, checkedIn, checkedOut, ind, norm }) {
|
||||||
|
return (
|
||||||
|
<div className="table-row">
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{date ? date : "-"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{checkedIn ? checkedIn : "-"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{checkedOut ? checkedOut : "-"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{ind ? ind : "-"}</span>
|
||||||
|
</div>
|
||||||
|
<div className="table-cell">
|
||||||
|
<span>{norm ? norm : "-"}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Row;
|
||||||
81
frontend/src/components/table/Table.jsx
Normal file
81
frontend/src/components/table/Table.jsx
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import React, { useState, useContext, useEffect } from "react";
|
||||||
|
import { ServerContext } from "../../contexts/ServerContext";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
|
import "../../css/components/table.scss";
|
||||||
|
|
||||||
|
import Row from "./Row";
|
||||||
|
import Header from "./Header";
|
||||||
|
|
||||||
|
function Table() {
|
||||||
|
const params = useParams();
|
||||||
|
const { URL } = useContext(ServerContext);
|
||||||
|
const [entries, setEntries] = useState([]);
|
||||||
|
const [monthYear, setMonthYear] = useState(params.monthYear);
|
||||||
|
|
||||||
|
async function fetchEntries() {
|
||||||
|
let response = await fetch(URL + `/api/entry/all/` + monthYear);
|
||||||
|
let data = await response.json();
|
||||||
|
setEntries(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchEntries();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function nextMonth() {
|
||||||
|
let month = parseInt(monthYear.split("-")[0]);
|
||||||
|
|
||||||
|
if (month === 12) {
|
||||||
|
window.location.href = `/table/${1}-${
|
||||||
|
parseInt(monthYear.split("-")[1]) + 1
|
||||||
|
}`;
|
||||||
|
} else {
|
||||||
|
window.location.href = `/table/${month + 1}-${monthYear.split("-")[1]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function previousMonth() {
|
||||||
|
let month = parseInt(monthYear.split("-")[0]);
|
||||||
|
|
||||||
|
if (month === 1) {
|
||||||
|
window.location.href = `/table/${12}-${
|
||||||
|
parseInt(monthYear.split("-")[1]) - 1
|
||||||
|
}`;
|
||||||
|
} else {
|
||||||
|
window.location.href = `/table/${month - 1}-${monthYear.split("-")[1]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="table">
|
||||||
|
<div className="table-nav">
|
||||||
|
<div onClick={previousMonth}> </div>
|
||||||
|
<h2>{monthYear}</h2>
|
||||||
|
<div onClick={nextMonth}> </div>
|
||||||
|
</div>
|
||||||
|
<div className="table-container">
|
||||||
|
<Header
|
||||||
|
date="Date"
|
||||||
|
checkedIn="Checked In"
|
||||||
|
checkedOut="Checked Out"
|
||||||
|
ind="Ind."
|
||||||
|
norm="Norm."
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ROWS */}
|
||||||
|
{entries.map((entry, index) => (
|
||||||
|
<Row
|
||||||
|
date={entry.date}
|
||||||
|
checkedIn={entry.checkedIn}
|
||||||
|
checkedOut={entry.checkedOut}
|
||||||
|
ind={entry.ind}
|
||||||
|
norm={entry.norm}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Table;
|
||||||
14
frontend/src/contexts/ServerContext.jsx
Normal file
14
frontend/src/contexts/ServerContext.jsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import React, { createContext } from "react";
|
||||||
|
|
||||||
|
export const ServerContext = createContext();
|
||||||
|
|
||||||
|
const ServerProvider = (props) => {
|
||||||
|
const URL = "http://127.0.0.1:8080";
|
||||||
|
return (
|
||||||
|
<ServerContext.Provider value={{ URL }}>
|
||||||
|
{props.children}
|
||||||
|
</ServerContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServerProvider;
|
||||||
59
frontend/src/css/components/table.scss
Normal file
59
frontend/src/css/components/table.scss
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#table {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.table-nav {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
background-color: red;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
.table-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(28, 28, 28);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom: 2px solid rgb(157, 157, 157);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(61, 61, 61);
|
||||||
|
border-top: 1px solid rgb(85, 85, 85);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cell {
|
||||||
|
grid-area: auto;
|
||||||
|
padding: 10px;
|
||||||
|
border-right: 1px solid rgb(85, 85, 85);
|
||||||
|
border-left: 1px solid rgb(85, 85, 85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user