diff --git a/backend/db.js b/backend/db.js
index efd3300..87c045a 100644
--- a/backend/db.js
+++ b/backend/db.js
@@ -1,59 +1,10 @@
-import { fileURLToPath } from "url";
-import { connection } from "./index.js";
-// Create the connection to database
+import mysql from "mysql2/promise";
-// get data for users between 2 dates
-async function getTopTen() {
- let filteredResults;
- let startDate = "2021-01-01";
- let endDate = "2029-01-01";
- if (req.query.to) startDate = req.query.to;
- if (req.query.from) startDate = req.query.from;
- try {
- const [results, fields] = await connection.query(
- "SELECT t.user,t.time,t.date,t.project \
- FROM Timelog t\
- WHERE t.date BETWEEN ? AND ? ;",
- [startDate, endDate],
- );
- filteredResults = results;
- console.log(filteredResults);
- } catch (err) {
- console.log(err);
- }
+const connection = await mysql.createConnection({
+ host: "localhost",
+ user: "monty",
+ password: "some_pass",
+ database: "timelog",
+});
- if (req.query.filterBy) filterBy = req.query.filterBy;
- // how much time each user has logged during that time period
- if (filterBy === "user") {
- let users = {};
- for (let i = 0; i < filteredResults.length; i++) {
- if (filteredResults[i].user in users) {
- users[filteredResults[i].user] += filteredResults[i].time;
- } else {
- users[filteredResults[i].user] = filteredResults[i].time;
- }
- }
- // Create items array
- let items = Object.keys(users).map(function (key) {
- return [key, users[key]];
- });
-
- // Sort the array based on the second element
- items.sort(function (first, second) {
- return second[1] - first[1];
- });
-
- // Create a new array with only the first 10 items
- return items.slice(0, 10);
- }
-}
-
-export { getTopTen };
-
-// SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date
-// FROM Timelog t
-// INNER JOIN Project p ON p.id=t.project
-// INNER JOIN User u ON u.id=t.user
-// WHERE User = "100";
-// ORDER BY time
-// LIMIT 10 OFFSET 10
+export default connection;
diff --git a/backend/index.js b/backend/index.js
index 1b7f7c7..eff2223 100644
--- a/backend/index.js
+++ b/backend/index.js
@@ -1,179 +1,19 @@
import express from "express";
-import mysql from "mysql2/promise";
-import { getTopTen } from "./db.js";
-import { resourceUsage } from "process";
-
-export const connection = await mysql.createConnection({
- host: "localhost",
- user: "monty",
- password: "some_pass",
- database: "timelog",
-});
-connection.config.namedPlaceholders = true;
+import getAll from "./routers/getAll.js";
+import getUser from "./routers/getUser.js";
+import getTopTen from "./routers/getTopTen.js";
+import reset from "./routers/reset.js";
const router = express.Router();
-router.get("/getall", async (req, res) => {
- let sql =
- "SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date,t.user \
- FROM Timelog t \
- INNER JOIN Project p ON p.id=t.project \
- INNER JOIN User u ON u.id=t.user ";
- let where = "WHERE t.date BETWEEN ? AND ? ";
- let order = "ORDER BY ?? ";
- let offsetSql = "LIMIT 10 OFFSET ?;";
- let flag = 0;
- if (req.query.from || req.query.to) {
- sql = sql + where;
- flag += 1;
- }
- if (req.query.sortby) {
- sql = sql + order;
- flag += 2;
- }
- sql = sql + offsetSql;
- let results;
- let fields;
- if (flag == 0) {
- [results, fields] = await connection.query(sql, [
- parseInt(req.query.offset),
- ]);
- } else if (flag === 1) {
- [results, fields] = await connection.query(sql, [
- req.query.from,
- req.query.to,
- parseInt(req.query.offset),
- ]);
- } else if (flag === 2) {
- [results, fields] = await connection.query(sql, [
- req.query.sortby,
- parseInt(req.query.offset),
- ]);
- } else if (flag === 3) {
- [results, fields] = await connection.query(sql, [
- req.query.from,
- req.query.to,
- req.query.sortby,
- parseInt(req.query.offset),
- ]);
- }
- res.json(results);
-});
-router.get("/gettopten", async (req, res) => {
- let filteredResults;
- let results2;
- let from = "2021-01-01";
- let to = "2029-01-01";
- let filterBy = "user";
- if (req.query.from) from = req.query.from;
- if (req.query.to) to = req.query.to;
-
- try {
- const [results, fields] = await connection.query(
- "SELECT t.user,t.time,t.date,t.project \
- FROM Timelog t\
- WHERE t.date BETWEEN ? AND ? ;",
- [from, to],
- );
- filteredResults = results;
- } catch (err) {
- console.log(err);
- }
-
- if (req.query.filterBy) filterBy = req.query.filterBy;
- // how much time each user has logged during that time period
- if (filterBy === "user") {
- let users = {};
- for (let i = 0; i < filteredResults.length; i++) {
- if (filteredResults[i].user in users) {
- users[filteredResults[i].user] += filteredResults[i].time;
- } else {
- users[filteredResults[i].user] = filteredResults[i].time;
- }
- }
- // Create items array
- let items = Object.keys(users).map(function (key) {
- return [key, users[key]];
- });
-
- // Sort the array based on the second element
- items.sort(function (first, second) {
- return second[1] - first[1];
- });
-
- // Create a new array with only the first 10 items
- results2 = items.slice(0, 10);
- } else if (filterBy === "project") {
- let projects = {};
- for (let i = 0; i < filteredResults.length; i++) {
- if (filteredResults[i].project in projects) {
- projects[filteredResults[i].project] += filteredResults[i].time;
- } else {
- projects[filteredResults[i].project] = filteredResults[i].time;
- }
- }
- // Create items array
- let items = Object.keys(projects).map(function (key) {
- return [key, projects[key]];
- });
-
- // Sort the array based on the second element
- items.sort(function (first, second) {
- return second[1] - first[1];
- });
-
- // Create a new array with only the first 10 items
- results2 = items.slice(0, 10);
- }
-
- res.json(results2);
-});
-router.get("/reset", async (req, res) => {
- try {
- const [results, fields] = await connection.query("CALL InitDb;", []);
- } catch (err) {
- console.log(err);
- }
- res.status(200).json({ message: "Success" });
-});
-router.get("/getUser", async (req, res) => {
- const userId = req.query.userid;
- let results, fields;
- console.log(userId);
- try {
- [results, fields] = await connection.query(
- "SELECT p.name,t.time,t.project \
- FROM Timelog t \
- INNER JOIN Project p ON p.id=t.project \
- INNER JOIN User u ON u.id=t.user \
- WHERE USER = ? ;",
- [userId],
- );
- } catch (err) {
- console.log(err);
- }
- let projects = {};
- let projectIdtoName = {};
- for (let i = 0; i < results.length; i++) {
- if (results[i].project in projects) {
- projects[results[i].project] += results[i].time;
- } else {
- projects[results[i].project] = results[i].time;
- projectIdtoName[results[i].project] = results[i].name;
- }
- }
- // map projectIds to project names before sending the data
- let respData = {};
- for (let key in projects) {
- if (projects.hasOwnProperty(key)) {
- respData[projectIdtoName[key]] = projects[key];
- }
- }
- res.json(respData);
-});
-
const app = express();
app.use(express.json());
+
+app.use("/api", getAll);
+app.use("/api", getTopTen);
+app.use("/api", getUser);
+app.use("/api", reset);
+
app.use("/api", router);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
diff --git a/backend/temp.js b/backend/populateDB.js
similarity index 100%
rename from backend/temp.js
rename to backend/populateDB.js
diff --git a/backend/routers/getAll.js b/backend/routers/getAll.js
new file mode 100644
index 0000000..561a22a
--- /dev/null
+++ b/backend/routers/getAll.js
@@ -0,0 +1,60 @@
+import express from "express";
+import connection from "../db.js";
+
+const router = express.Router();
+
+router.get("/getall", async (req, res) => {
+ let sql =
+ "SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date,t.user \
+ FROM Timelog t \
+ INNER JOIN Project p ON p.id=t.project \
+ INNER JOIN User u ON u.id=t.user ";
+ const where = "WHERE t.date BETWEEN ? AND ? ";
+ const order = "ORDER BY ?? ";
+ const offsetSql = "LIMIT 10 OFFSET ?;";
+ let flag = 0;
+ // construct the sql statement based on incoming request
+ if (req.query.from || req.query.to) {
+ sql = sql + where;
+ flag += 1;
+ }
+ if (req.query.sortby) {
+ sql = sql + order;
+ flag += 2;
+ }
+ sql = sql + offsetSql;
+
+ let results;
+ let fields;
+ switch (flag) {
+ case 0:
+ [results, fields] = await connection.query(sql, [
+ parseInt(req.query.offset),
+ ]);
+ break;
+ case 1:
+ [results, fields] = await connection.query(sql, [
+ req.query.from,
+ req.query.to,
+ parseInt(req.query.offset),
+ ]);
+ break;
+ case 2:
+ [results, fields] = await connection.query(sql, [
+ req.query.sortby,
+ parseInt(req.query.offset),
+ ]);
+ break;
+ case 3:
+ [results, fields] = await connection.query(sql, [
+ req.query.from,
+ req.query.to,
+ req.query.sortby,
+ parseInt(req.query.offset),
+ ]);
+ break;
+ }
+ res.json(results);
+});
+
+export default router;
diff --git a/backend/routers/getTopTen.js b/backend/routers/getTopTen.js
new file mode 100644
index 0000000..d6115e6
--- /dev/null
+++ b/backend/routers/getTopTen.js
@@ -0,0 +1,69 @@
+import express from "express";
+import connection from "../db.js";
+
+const router = express.Router();
+
+router.get("/gettopten", async (req, res) => {
+ let from = "2020-01-01";
+ let to = "2029-01-01";
+ let filterBy = "user";
+ if (req.query.from) from = req.query.from;
+ if (req.query.to) to = req.query.to;
+ if (req.query.filterBy) filterBy = req.query.filterBy;
+ let results, fields;
+ let filterBySql = filterBy === "user" ? "t.user" : "t.project";
+ try {
+ [results, fields] = await connection.query(
+ "SELECT t.user,t.date,t.project,u.f_name,u.l_name,p.name,SUM(t.time) as total_time \
+ FROM Timelog t \
+ INNER JOIN Project p ON p.id=t.project \
+ INNER JOIN User u ON u.id=t.user \
+ WHERE t.date BETWEEN ? AND ? \
+ GROUP BY ?? \
+ ORDER BY total_time DESC\
+ LIMIT 10;",
+ [from, to, filterBySql],
+ );
+ } catch (err) {
+ console.log(err);
+ res.status(400).json({ message: "Error" });
+ }
+ // how much time each user has logged during that time period
+ // let items = {};
+ // let itemIdtoName = {};
+ // for (let i = 0; i < results.length; i++) {
+ // if (results[i][filterBy] in items) {
+ // items[results[i][filterBy]] += results[i].time;
+ // } else {
+ // items[results[i][filterBy]] = results[i].time;
+ // if (filterBy === "user")
+ // itemIdtoName[results[i][filterBy]] =
+ // results[i].f_name + " " + results[i].l_name;
+ // else itemIdtoName[results[i][filterBy]] = results[i].name;
+ // }
+ // }
+ // let respData = {};
+ // for (let key in items) {
+ // if (items.hasOwnProperty(key)) {
+ // respData[itemIdtoName[key]] = items[key];
+ // }
+ // }
+ // // transform obj to array
+ // respData = Object.keys(items).map(function (key) {
+ // return [key, items[key]];
+ // });
+ //
+ // // sort the array based on the second element
+ // respData.sort(function (first, second) {
+ // return second[1] - first[1];
+ // });
+ //
+ // // console.log(itemIdtoName);
+ // // console.log(respData);
+ // // Create a new array with only the first 10 items
+ // respData = respData.slice(0, 10);
+
+ res.json(results);
+});
+
+export default router;
diff --git a/backend/routers/getUser.js b/backend/routers/getUser.js
new file mode 100644
index 0000000..b52b3b3
--- /dev/null
+++ b/backend/routers/getUser.js
@@ -0,0 +1,42 @@
+import express from "express";
+import connection from "../db.js";
+
+const router = express.Router();
+
+router.get("/getUser", async (req, res) => {
+ const userId = req.query.userid;
+ let results, fields;
+ try {
+ [results, fields] = await connection.query(
+ "SELECT p.name,t.time,t.project \
+ FROM Timelog t \
+ INNER JOIN Project p ON p.id=t.project \
+ INNER JOIN User u ON u.id=t.user \
+ WHERE USER = ? ;",
+ [userId],
+ );
+ } catch (err) {
+ console.log(err);
+ res.status(400).json("ERROR");
+ }
+ let projects = {};
+ let projectIdtoName = {};
+ for (let i = 0; i < results.length; i++) {
+ if (results[i].project in projects) {
+ projects[results[i].project] += results[i].time;
+ } else {
+ projects[results[i].project] = results[i].time;
+ projectIdtoName[results[i].project] = results[i].name;
+ }
+ }
+ // map projectIds to project names before sending the data
+ let respData = {};
+ for (let key in projects) {
+ if (projects.hasOwnProperty(key)) {
+ respData[projectIdtoName[key]] = projects[key];
+ }
+ }
+ res.json(respData);
+});
+
+export default router;
diff --git a/backend/routers/reset.js b/backend/routers/reset.js
new file mode 100644
index 0000000..50400fe
--- /dev/null
+++ b/backend/routers/reset.js
@@ -0,0 +1,16 @@
+import express from "express";
+import connection from "../db.js";
+
+const router = express.Router();
+
+router.get("/reset", async (req, res) => {
+ try {
+ await connection.query("CALL InitDb;", []);
+ } catch (err) {
+ console.log(err);
+ res.status(400).json({ message: "Error" });
+ }
+ res.status(200).json({ message: "Success" });
+});
+
+export default router;
diff --git a/backend/sql/commands.sql b/backend/sql/commands.sql
index 87db71c..e4dfe67 100644
--- a/backend/sql/commands.sql
+++ b/backend/sql/commands.sql
@@ -127,3 +127,11 @@ END$$
DELIMITER ;
+ SELECT t.user,t.date,t.project,u.f_name,u.l_name,p.name,SUM(t.time) as total_time
+ FROM Timelog t
+ INNER JOIN Project p ON p.id=t.project
+ INNER JOIN User u ON u.id=t.user
+ GROUP BY t.user
+ ORDER BY total_time DESC
+ LIMIT 10;
+
diff --git a/backend/sql/current.sql b/backend/sql/current.sql
index 0078014..b0df285 100644
--- a/backend/sql/current.sql
+++ b/backend/sql/current.sql
@@ -84,14 +84,28 @@ BEGIN
DECLARE hours FLOAT;
DECLARE project INT;
DECLARE curDate DATE DEFAULT "2024-11-18";
+ DECLARE h2 INT;
WHILE users <= 100 DO
SET logs = FLOOR(1+(RAND()*20));
SET j=1;
WHILE j <= logs DO
- SET hours = (RAND() * (8 - 0.25)) + 0.25;
- SET curDate = DATE_ADD(curDate, INTERVAL 1 DAY);
SET project = FLOOR(1+(RAND()*3));
+ SET curDate = DATE_ADD('2020-01-01', INTERVAL FLOOR(RAND() * DATEDIFF('2020-02-01', '2020-01-01')) DAY);
+ SET hours = (RAND() * (8 - 0.25)) + 0.25;
+
+ SELECT SUM(time) INTO h2
+ FROM Timelog
+ WHERE date = curdate && user = users ;
+
+ WHILE (h2+hours) > 8 DO
+ SET curDate = DATE_ADD('2020-01-01', INTERVAL FLOOR(RAND() * DATEDIFF('2020-02-01', '2020-01-01')) DAY);
+
+ SELECT SUM(time)INTO h2
+ FROM Timelog
+ WHERE date = curdate && user = users ;
+
+ END WHILE;
INSERT INTO Timelog (user, project, date,time ) VALUES (users,project,curDate,hours);
SET j=j+1;
END WHILE;
@@ -104,3 +118,28 @@ DELIMITER ;
##
-- get data
SELECT t.time,t.date,p.name,u.f_name,u.l_name,u.mail FROM Timelog t INNER JOIN Project p ON p.id=t.project INNER JOIN User u ON u.id=t.user;
+
+CREATE PROCEDURE fill_timelog ()
+BEGIN
+ DECLARE j INT DEFAULT 1;
+ DECLARE users INT DEFAULT 1;
+ DECLARE logs INT;
+ DECLARE hours FLOAT;
+ DECLARE project INT;
+ DECLARE curDate DATE DEFAULT "2024-11-18";
+
+WHILE users <= 100 DO
+ SET logs = FLOOR(1+(RAND()*20));
+ SET j=1;
+ WHILE j <= logs DO
+ SET hours = (RAND() * (8 - 0.25)) + 0.25;
+ SET project = FLOOR(1+(RAND()*3));
+ SET curDate = DATE_ADD(curDate, INTERVAL 1 DAY);
+ INSERT INTO Timelog (user, project, date,time ) VALUES (users,project,curDate,hours);
+ SET j=j+1;
+ END WHILE;
+ SET users=users+1;
+END WHILE;
+END$$
+
+DELIMITER ;
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index f9c5dc1..946873a 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -8,6 +8,8 @@
"name": "frontend",
"version": "0.0.0",
"dependencies": {
+ "@emotion/styled": "^11.13.5",
+ "@mui/material": "^6.1.8",
"axios": "^1.7.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -45,7 +47,6 @@
"version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.25.9",
@@ -101,7 +102,6 @@
"version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz",
"integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.26.2",
@@ -135,7 +135,6 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
"integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.25.9",
@@ -177,7 +176,6 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -187,7 +185,6 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -221,7 +218,6 @@
"version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz",
"integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.26.0"
@@ -265,11 +261,22 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/runtime": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
+ "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
+ "license": "MIT",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.25.9",
@@ -284,7 +291,6 @@
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz",
"integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.25.9",
@@ -303,7 +309,6 @@
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -313,7 +318,6 @@
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
"integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
@@ -323,6 +327,159 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emotion/babel-plugin": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
+ "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.16.7",
+ "@babel/runtime": "^7.18.3",
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/serialize": "^1.3.3",
+ "babel-plugin-macros": "^3.1.0",
+ "convert-source-map": "^1.5.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-root": "^1.1.0",
+ "source-map": "^0.5.7",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/cache": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.5.tgz",
+ "integrity": "sha512-Z3xbtJ+UcK76eWkagZ1onvn/wAVb1GOMuR15s30Fm2wrMgC7jzpnO2JZXr4eujTTqoQFUrZIw/rT0c6Zzjca1g==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/sheet": "^1.4.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
+ "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz",
+ "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
+ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/react": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz",
+ "integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/cache": "^11.13.5",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "hoist-non-react-statics": "^3.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/serialize": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
+ "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/unitless": "^0.10.0",
+ "@emotion/utils": "^1.4.2",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@emotion/sheet": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
+ "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/styled": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz",
+ "integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/is-prop-valid": "^1.3.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
+ "@emotion/utils": "^1.4.2"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.0.0-rc.0",
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
+ "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz",
+ "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@emotion/utils": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
+ "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/weak-memoize": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
+ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
+ "license": "MIT"
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -921,7 +1078,6 @@
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
@@ -936,7 +1092,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -946,7 +1101,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -956,20 +1110,222 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@mui/core-downloads-tracker": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.8.tgz",
+ "integrity": "sha512-TGAvzwUg9hybDacwfIGFjI2bXYXrIqky+vMfaeay8rvT56/PNAlvIDUJ54kpT5KRc9AWAihOvtDI7/LJOThOmQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ }
+ },
+ "node_modules/@mui/material": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.8.tgz",
+ "integrity": "sha512-QZdQFnXct+7NXIzHgT3qt+sQiO7HYGZU2vymP9Xl9tUMXEOA/S1mZMMb7+WGZrk5TzNlU/kP/85K0da5V1jXoQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/core-downloads-tracker": "^6.1.8",
+ "@mui/system": "^6.1.8",
+ "@mui/types": "^7.2.19",
+ "@mui/utils": "^6.1.8",
+ "@popperjs/core": "^2.11.8",
+ "@types/react-transition-group": "^4.4.11",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.3.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@mui/material-pigment-css": "^6.1.8",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@mui/material-pigment-css": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/private-theming": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.8.tgz",
+ "integrity": "sha512-TuKl7msynCNCVvhX3c0ef1sF0Qb3VHcPs8XOGB/8bdOGBr/ynmIG1yTMjZeiFQXk8yN9fzK/FDEKMFxILNn3wg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/utils": "^6.1.8",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/styled-engine": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.8.tgz",
+ "integrity": "sha512-ZvEoT0U2nPLSLI+B4by4cVjaZnPT2f20f4JUPkyHdwLv65ZzuoHiTlwyhqX1Ch63p8bcJzKTHQVGisEoMK6PGA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@emotion/cache": "^11.13.1",
+ "@emotion/serialize": "^1.3.2",
+ "@emotion/sheet": "^1.4.0",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.4.1",
+ "@emotion/styled": "^11.3.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/system": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.8.tgz",
+ "integrity": "sha512-i1kLfQoWxzFpXTBQIuPoA3xKnAnP3en4I2T8xIolovSolGQX5k8vGjw1JaydQS40td++cFsgCdEU458HDNTGUA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/private-theming": "^6.1.8",
+ "@mui/styled-engine": "^6.1.8",
+ "@mui/types": "^7.2.19",
+ "@mui/utils": "^6.1.8",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/types": {
+ "version": "7.2.19",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz",
+ "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils": {
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.8.tgz",
+ "integrity": "sha512-O2DWb1kz8hiANVcR7Z4gOB3SvPPsSQGUmStpyBDzde6dJIfBzgV9PbEQOBZd3EBsd1pB+Uv1z5LAJAbymmawrA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/types": "^7.2.19",
+ "@types/prop-types": "^15.7.13",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.3.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1008,6 +1364,16 @@
"node": ">= 8"
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.27.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.2.tgz",
@@ -1319,18 +1685,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/parse-json": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
+ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
+ "license": "MIT"
+ },
"node_modules/@types/prop-types": {
"version": "15.7.13",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.12",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
"integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
@@ -1347,6 +1717,15 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-transition-group": {
+ "version": "4.4.11",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
+ "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz",
@@ -1689,6 +2068,21 @@
"proxy-from-env": "^1.1.0"
}
},
+ "node_modules/babel-plugin-macros": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
+ "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "cosmiconfig": "^7.0.0",
+ "resolve": "^1.19.0"
+ },
+ "engines": {
+ "node": ">=10",
+ "npm": ">=6"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1757,7 +2151,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -1801,6 +2194,15 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -1847,6 +2249,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cosmiconfig": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+ "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
@@ -1866,14 +2284,12 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
"license": "MIT"
},
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -1903,6 +2319,16 @@
"node": ">=0.4.0"
}
},
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.62",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz",
@@ -1910,6 +2336,15 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
"node_modules/esbuild": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
@@ -1963,7 +2398,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -2236,6 +2670,12 @@
"node": ">=8"
}
},
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "license": "MIT"
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -2323,6 +2763,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -2376,6 +2825,35 @@
"node": ">=8"
}
},
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "peer": true,
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -2390,7 +2868,6 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
@@ -2413,6 +2890,27 @@
"node": ">=0.8.19"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT"
+ },
+ "node_modules/is-core-module": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
+ "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2476,7 +2974,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
"integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
- "dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -2492,6 +2989,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT"
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -2543,6 +3046,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -2650,7 +3159,6 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -2686,6 +3194,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -2740,7 +3257,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
@@ -2749,6 +3265,24 @@
"node": ">=6"
}
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -2769,11 +3303,25 @@
"node": ">=8"
}
},
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "license": "MIT"
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
@@ -2828,6 +3376,23 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/prop-types/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -2900,6 +3465,12 @@
"react-dom": ">=16.3.0"
}
},
+ "node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "license": "MIT"
+ },
"node_modules/react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@@ -2910,11 +3481,49 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "license": "MIT"
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -3035,6 +3644,15 @@
"node": ">=8"
}
},
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -3058,6 +3676,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
+ "license": "MIT"
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -3071,6 +3695,18 @@
"node": ">=8"
}
},
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -3282,6 +3918,15 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index becd3f8..0eba5ce 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -10,6 +10,8 @@
"preview": "vite preview"
},
"dependencies": {
+ "@emotion/styled": "^11.13.5",
+ "@mui/material": "^6.1.8",
"axios": "^1.7.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/frontend/src/App.css b/frontend/src/App.css
index b9d355d..8b13789 100644
--- a/frontend/src/App.css
+++ b/frontend/src/App.css
@@ -1,42 +1 @@
-#root {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: no-preference) {
- a:nth-of-type(2) .logo {
- animation: logo-spin infinite 20s linear;
- }
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
-}
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index e63b4b6..860d878 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,13 +1,18 @@
import "./App.css";
import LeftSide from "./components/LeftSide";
import RightSide from "./components/RightSide";
+import Grid from "@mui/material/Grid2";
function App() {
return (
-
-
-
-
+
+
+
+
+
+
+
+
);
}
diff --git a/frontend/src/components/LeftSide.tsx b/frontend/src/components/LeftSide.tsx
index 47a1a05..aecab08 100644
--- a/frontend/src/components/LeftSide.tsx
+++ b/frontend/src/components/LeftSide.tsx
@@ -1,15 +1,27 @@
import { useEffect, useState } from "react";
import api from "../utils/api";
+import Grid from "@mui/material/Grid2";
+import {
+ TableRow,
+ TableBody,
+ TableCell,
+ TableHead,
+ Table,
+} from "@mui/material";
const LeftSide = () => {
+ // next prev and sort
const [users, setUsers] = useState();
const [params, setParams] = useState({ offset: 0, sortby: "f_name" });
-
+ // reset button
const [reset, setReset] = useState(true);
// date
const [date, setDate] = useState({ from: "2021-01-01", to: "2028-01-01" });
- const [dateToSubmit, setDateToSubmit] = useState({});
+ const [dateToSubmit, setDateToSubmit] = useState({
+ from: "2021-01-01",
+ to: "2028-01-01",
+ });
useEffect(() => {
async function fetchData() {
@@ -28,13 +40,7 @@ const LeftSide = () => {
fetchData();
}, [reset, params, dateToSubmit]);
- const handleButtonClick = () => {
- // When the button is clicked, update the dateToShow state and trigger a re-render
- setDateToSubmit(date);
- };
-
const viewProjectHours = (user) => {
- console.log(user);
async function fetchHours() {
const resp = await api.get("/getUser", {
params: { userid: user },
@@ -47,8 +53,8 @@ const LeftSide = () => {
if (!users) return <>>;
return (
-
-
+
+
{
value={date.to}
onChange={(event) => setDate({ ...date, to: event.target.value })}
/>
-
-
-
-
Select a sort:
+
+
+
+ Select a sort:
-
-
-
-
-
-
- | First Name |
- Last Name |
- Email |
- Project name |
- Date |
- Hours |
-
-
-
+
+
+
+
+
+
+
+
+
+
+ First Name
+ Last Name
+ Email
+ Project name
+ Date
+ Hours
+
+
+
{users.length > 0 && Array.isArray(users) ? (
users.map((post, idx) => (
-
- | {post.f_name} |
- {post.l_name} |
- {post.mail} |
- {post.name} |
- {post.date} |
- {post.time} |
-
+
+ {post.f_name}
+ {post.l_name}
+ {post.mail}
+ {post.name}
+ {post.date.slice(0, 10)}
+ {post.time}
+
- |
-
+
+
))
) : (
No posts found...
)}
-
-
-
-
+
+
+
+
+
+
+
);
};
diff --git a/frontend/src/components/RightSide.tsx b/frontend/src/components/RightSide.tsx
index 285feaf..f881425 100644
--- a/frontend/src/components/RightSide.tsx
+++ b/frontend/src/components/RightSide.tsx
@@ -3,22 +3,39 @@ import api from "../utils/api";
import { Chart } from "react-google-charts";
const RightSide = () => {
- const [topten, setTopten] = useState();
- // input field
- const [date, setDate] = useState({ from: "2021-01-01", to: "2028-01-01" });
+ // graph date
+ const [topten, setTopten] = useState({
+ from: "2000-01-01",
+ to: "2100-01-01",
+ });
+ // date input field
+ const [date, setDate] = useState({ from: "2000-01-01", to: "2100-01-01" });
const [dateToSubmit, setDateToSubmit] = useState({});
- // radio
+ // radio button
const [selectedOption, setSelectedOption] = useState("project");
+
useEffect(() => {
async function fetchData() {
const resp = await api.get("/gettopten", {
params: {
- to: dateToSubmit.to,
from: dateToSubmit.from,
+ to: dateToSubmit.to,
filterBy: selectedOption,
},
});
resp.data.unshift(["User", "Hours"]);
+ // turn the data into form suitable to charts
+ if (selectedOption === "project")
+ for (let idx = 1; idx < resp.data.length; idx++) {
+ resp.data[idx] = [resp.data[idx].name, resp.data[idx].total_time];
+ }
+ else if (selectedOption === "user")
+ for (let idx = 1; idx < resp.data.length; idx++) {
+ resp.data[idx] = [
+ resp.data[idx].f_name + " " + resp.data[idx].l_name,
+ resp.data[idx].total_time,
+ ];
+ }
setTopten(resp.data);
}
fetchData();
@@ -27,29 +44,21 @@ const RightSide = () => {
// Chart options
const options = {
title: "Most comitted hours per user",
- chartArea: { width: "50%" },
+ chartArea: { width: "70%" },
hAxis: {
title: "Hours",
minValue: 0,
},
vAxis: {
- title: "User",
+ title: selectedOption,
},
};
- const handleButtonClick = () => {
- // When the button is clicked, update the dateToShow state and trigger a re-render
- setDateToSubmit(date);
- };
-
- // Handle the change when a radio button is selected
- const handleChange = (event) => {
- setSelectedOption(event.target.value);
- };
if (!topten) <>>;
+
return (
-