From d811f802da7c4e6dda1e3b12a312d7437f14c0d9 Mon Sep 17 00:00:00 2001
From: Tibebe Solomon <87706650+Tibex88@users.noreply.github.com>
Date: Wed, 5 Jun 2024 15:30:36 +0300
Subject: [PATCH 01/59] added logActivity to mw
---
server/app.js | 2 +-
server/controller/exam/createExam.js | 4 +
server/controller/exam/updateExam.js | 4 +-
server/controller/handlerFactory.js | 86 ++++---------------
server/controller/log/getLogs.js | 11 +++
server/controller/log/index.js | 5 ++
.../notification/getNotification.js | 1 -
.../organization/activateExaminer.js | 4 +
.../organization/createOrganization.js | 2 +
.../organization/deactivateExaminer.js | 3 +
.../organization/joinOrganization.js | 2 +
.../organization/updateOrganizationLogo.js | 2 +
server/controller/profile/fileUpload.js | 2 +-
server/models/log.model.js | 34 ++++++++
server/models/user.model.js | 18 ++--
server/routes/logRoutes.js | 9 ++
server/routes/routes.js | 2 +
server/utils/logActivity.js | 21 +++++
18 files changed, 128 insertions(+), 84 deletions(-)
create mode 100644 server/controller/log/getLogs.js
create mode 100644 server/controller/log/index.js
create mode 100644 server/models/log.model.js
create mode 100644 server/routes/logRoutes.js
create mode 100644 server/utils/logActivity.js
diff --git a/server/app.js b/server/app.js
index 3f9e76e..d3b6157 100644
--- a/server/app.js
+++ b/server/app.js
@@ -2,7 +2,7 @@ const express = require("express");
const app = express();
const cors = require("cors");
const morgan = require("morgan");
-const APIError = require("./utils/APIError");
+const APIError = require("./utils/apiError");
const globalErrorHandler = require("./controller/errorController");
const helmet = require("helmet");
const rateLimit = require("express-rate-limit");
diff --git a/server/controller/exam/createExam.js b/server/controller/exam/createExam.js
index b15f244..009fbc3 100644
--- a/server/controller/exam/createExam.js
+++ b/server/controller/exam/createExam.js
@@ -4,6 +4,8 @@ const APIError = require("../../utils/apiError");
const catchAsync = require("../../utils/catchAsync");
const { fileUpload } = require("../profile/fileUpload");
const generateRandomKey = require("../../utils/generateRandomKey");
+const { logActivity } = require("../../utils/logActivity");
+
exports.createExam = catchAsync(async (req, res, next) => {
// form data will be send in req, holding in the req.file the material that is a PDF file
@@ -80,6 +82,8 @@ exports.createExam = catchAsync(async (req, res, next) => {
await exam.save();
+ await logActivity(req,0,{name:exam?.modelName,id:exam.id} )
+
res.status(201).json({
status: "success",
data: {
diff --git a/server/controller/exam/updateExam.js b/server/controller/exam/updateExam.js
index a203e2f..00aab3f 100644
--- a/server/controller/exam/updateExam.js
+++ b/server/controller/exam/updateExam.js
@@ -2,7 +2,7 @@ const { StatusCodes } = require("http-status-codes");
const Exam = require("../../models/exam.model");
const catchAsync = require("../../utils/catchAsync");
const factory = require("./../handlerFactory");
-const APIError = require("../../utils/APIError");
+const APIError = require("../../utils/apiError");
const { fileUpload } = require("../profile/fileUpload");
const Question = require("../../models/question.model");
@@ -64,6 +64,8 @@ exports.updateExamResource = catchAsync(async (req, res, next) => {
await exam.save();
+ await logActivity(req,1,{name:exam?.modelName,id:exam.id} )
+
res.status(StatusCodes.OK).json({
status: "success",
data: {
diff --git a/server/controller/handlerFactory.js b/server/controller/handlerFactory.js
index cbacab1..bc7c8b2 100644
--- a/server/controller/handlerFactory.js
+++ b/server/controller/handlerFactory.js
@@ -1,13 +1,11 @@
const mongoose = require("mongoose");
-// const Grid = require("gridfs-stream");
const APIError = require("../utils/apiError");
const catchAsync = require("../utils/catchAsync");
-// const transaction = require("../utils/transaction");
+const {logActivity} = require("../utils/logActivity");
const APIFeatures = require("../utils/apiFeatures");
const dbConn = require("../config/db_Connection");
-const OrganizationExaminer = require("../models/organization.examiner.model");
+// const OrganizationExaminer = require("../models/organization.examiner.model");
const { StatusCodes } = require("http-status-codes");
-// const dbAuth = require("../config/db_Authentication");
require("events").EventEmitter.prototype._maxListeners = 70;
require("events").defaultMaxListeners = 70;
@@ -36,12 +34,12 @@ exports.getOne = (Model) =>
exports.getAll = (Model, options = "", obj = {}) =>
catchAsync(async (req, res, next) => {
// currentTime, pathname, method
- // const {currentTime,_parsedOriginalUrl} = req
+ // const {currentTime,_parsedOriginalUrl} = req
// console.log(currentTime)
// console.log(_parsedOriginalUrl.pathname)
let opt = {};
- if (options === "addUser") opt = { user: req.user.id };
+ if (options === "addUser") opt = { user: req.user.id };
if (options === "addOrganization") opt = { organization: req.params.id };
if (options === "addExaminerStatus")
opt = { user: req.user.id, status: "activated" };
@@ -106,6 +104,9 @@ exports.updateOne = (Model) =>
new APIError(`No document found with id = ${req.params.id}`, 404)
);
}
+
+ await logActivity(req,1,{name:Model?.modelName,id:req.params.id})
+
res.status(200).json({
status: "success",
data: {
@@ -129,6 +130,7 @@ exports.deleteOne = (Model) =>
console.log(model)
await model.save();
+ await logActivity(req,5,{name:Model?.modelName,id:req.params.id} )
res.status(StatusCodes.OK).json({
status: "success",
data: null,
@@ -162,6 +164,9 @@ exports.createOne = (Model) =>
new APIError(`An error occured while creating the document`, 404)
);
}
+
+ await logActivity(req,0,{name:Model?.modelName,id:doc.id})
+
res.status(201).json({
status: "success",
data: {
@@ -181,6 +186,7 @@ exports.createMany = (Model, returnOnlyId = false) =>
if (returnOnlyId) {
let id = doc.map((item) => item._id);
+ // await logActivity(req,0,{name:Model?.modelName,id:req.params.id} )
res.status(201).json({
status: "success",
data: {
@@ -188,6 +194,9 @@ exports.createMany = (Model, returnOnlyId = false) =>
},
});
} else {
+
+ // await logActivity(req,0,{name:Model?.modelName,id:req.params.id} )
+
res.status(201).json({
status: "success",
data: {
@@ -196,68 +205,3 @@ exports.createMany = (Model, returnOnlyId = false) =>
});
}
});
-
-// exports.getOneMedia = (collectionName) =>
-// catchAsync(async (req, res, next) => {
-// console.log(req.params.filename);
-// if (collectionName == "userProfile") gridfs = gridfsProfile;
-// else if (collectionName == "media") gridfs = gridfsMedia;
-
-// const result = await gridfs.find({
-// filename: req.params.filename,
-// });
-// var filename = "";
-// await result.forEach((doc) => {
-// filename = doc.filename;
-// return;
-// });
-// const readstream = await gridfs.openDownloadStreamByName(filename);
-
-// readstream
-// .on("data", async (chunk) => {
-// string = await chunk.toString("base64");
-
-// return res.status(200).json({
-// status: "success",
-// data: string,
-// });
-// })
-// .on("end", function () {
-// console.log("end");
-// })
-// .on("error", (err) => {
-// console.log(err, "the error");
-// });
-// });
-
-// exports.updateOneMedia = (collectionName) =>
-// catchAsync(async (req, res, next) => {
-// gfs.collection(collectionName);
-// // gfs.remove({_id:})
-// });
-
-// exports.deleteOneMedia = (collectionName) =>
-// catchAsync(async (req, res, next) => {
-// if (collectionName == "userProfile") gridfs = gridfsProfile;
-// else if (collectionName == "media") gridfs = gridfsMedia;
-
-// await gridfs.delete(new mongoose.Types.ObjectId(req.params.id));
-// res.status(204).json({
-// status: "success",
-// });
-// });
-
-// exports.deleteManyMedia = (collectionName) =>
-// catchAsync(async (req, res, next) => {
-// if (collectionName == "userProfile") gridfs = gridfsProfile;
-// else if (collectionName == "media") gridfs = gridfsMedia;
-
-// // gfs.collection(collectionName + '.chunks');
-// console.log(req.body.delete);
-// // gridfs.delete(`ObjectId("${req.body.delete[0]}")`)
-// await gridfs.delete(new mongoose.Types.ObjectId(req.body.delete[0]));
-
-// res.status(200).json({
-// status: "success",
-// });
-// });
diff --git a/server/controller/log/getLogs.js b/server/controller/log/getLogs.js
new file mode 100644
index 0000000..65c7bf4
--- /dev/null
+++ b/server/controller/log/getLogs.js
@@ -0,0 +1,11 @@
+const Log = require("../../models/log.model");
+const factory = require("../handlerFactory");
+
+// const { TokenModel } = require("../../models/Token.model");
+// const { UserModel } = require("../../models/User.model");
+// const { isTokenValid } = require("../utils");
+
+const getLogs = factory.getAll(Log);
+
+module.exports = getLogs;
+
diff --git a/server/controller/log/index.js b/server/controller/log/index.js
new file mode 100644
index 0000000..e43f482
--- /dev/null
+++ b/server/controller/log/index.js
@@ -0,0 +1,5 @@
+const getLogs = require("./getLogs");
+
+module.exports = {
+ getLogs
+}
\ No newline at end of file
diff --git a/server/controller/notification/getNotification.js b/server/controller/notification/getNotification.js
index f7178df..5a4c314 100644
--- a/server/controller/notification/getNotification.js
+++ b/server/controller/notification/getNotification.js
@@ -1,6 +1,5 @@
const factory = require("../handlerFactory");
const Notification = require("../../models/notification.model");
-const catchAsync = require("../../utils/catchAsync");
const getNotification = factory.getAll(Notification, "addUser");
diff --git a/server/controller/organization/activateExaminer.js b/server/controller/organization/activateExaminer.js
index 5b078a1..9e93547 100644
--- a/server/controller/organization/activateExaminer.js
+++ b/server/controller/organization/activateExaminer.js
@@ -4,6 +4,7 @@ const APIError = require("../../utils/apiError");
const catchAsync = require("../../utils/catchAsync");
const OrganizationExaminer = require("../../models/organization.examiner.model");
const Notification = require("../../models/notification.model");
+const { logActivity } = require("../../utils/logActivity");
exports.activateExaminer = catchAsync(async (req, res, next) => {
const { userId } = req.body;
@@ -49,6 +50,9 @@ exports.activateExaminer = catchAsync(async (req, res, next) => {
message: `Your account as an Examiner has been Activated. In the Organization ${organization.name}`,
});
+ await logActivity(req,6,{name:organizationExaminer?.modelName,id:user.id} )
+
+
res.status(StatusCodes.OK).json({
status: "success",
message: "You have successfully approved the join request.",
diff --git a/server/controller/organization/createOrganization.js b/server/controller/organization/createOrganization.js
index 3e12ade..03b7b86 100644
--- a/server/controller/organization/createOrganization.js
+++ b/server/controller/organization/createOrganization.js
@@ -6,6 +6,7 @@ const factory = require("../handlerFactory");
const APIError = require("../../utils/apiError");
const { fileUpload } = require("../profile/fileUpload");
const OrganizationExaminer = require("../../models/organization.examiner.model");
+const { logActivity } = require("../../utils/logActivity");
exports.createOrganization = catchAsync(async (req, res, next) => {
if (!req.files) {
@@ -51,6 +52,7 @@ exports.createOrganization = catchAsync(async (req, res, next) => {
status: "activated",
});
+ await logActivity(req,0,{name:Organization?.modelName,id:newOrganization.id} )
res.status(StatusCodes.CREATED).json({
sucess: true,
diff --git a/server/controller/organization/deactivateExaminer.js b/server/controller/organization/deactivateExaminer.js
index 057e48f..62460c9 100644
--- a/server/controller/organization/deactivateExaminer.js
+++ b/server/controller/organization/deactivateExaminer.js
@@ -3,6 +3,7 @@ const Organization = require("../../models/organization.model");
const catchAsync = require("../../utils/catchAsync");
const OrganizationExaminer = require("../../models/organization.examiner.model");
const APIError = require("../../utils/apiError");
+const { logActivity } = require("../../utils/logActivity");
exports.deactivateExaminer = catchAsync(async (req, res, next) => {
const { userId } = req.body;
@@ -42,6 +43,8 @@ exports.deactivateExaminer = catchAsync(async (req, res, next) => {
// save the organization
await organizationExaminer.save();
+ await logActivity(req,4,{name:organizationExaminer?.modelName,id:userId} )
+
res.status(StatusCodes.OK).json({
status: "success",
message: "You have successfully deactivated the examinee.",
diff --git a/server/controller/organization/joinOrganization.js b/server/controller/organization/joinOrganization.js
index 57f0009..d892b24 100644
--- a/server/controller/organization/joinOrganization.js
+++ b/server/controller/organization/joinOrganization.js
@@ -51,6 +51,8 @@ exports.joinOrganization = catchAsync(async (req, res, next) => {
message: `User with id ${userId} has requested to join the organization `,
});
+ await logActivity(req,7,{name:organization?.modelName,id:organization.id} )
+
res.status(StatusCodes.OK).json({
status: "success",
message:
diff --git a/server/controller/organization/updateOrganizationLogo.js b/server/controller/organization/updateOrganizationLogo.js
index 52bbc1e..21c3309 100644
--- a/server/controller/organization/updateOrganizationLogo.js
+++ b/server/controller/organization/updateOrganizationLogo.js
@@ -38,6 +38,8 @@ exports.updateOrganizationLogo = catchAsync(async (req, res, next) => {
organization.logo = logo;
await organization.save();
+ await logActivity(req,1,{name:organization?.modelName,id:organization.id} )
+
res.status(StatusCodes.CREATED).json({
status: "success",
data: null,
diff --git a/server/controller/profile/fileUpload.js b/server/controller/profile/fileUpload.js
index 11bf45b..d8e4446 100644
--- a/server/controller/profile/fileUpload.js
+++ b/server/controller/profile/fileUpload.js
@@ -3,7 +3,7 @@ const catchAsync = require("./../../utils/catchAsync");
const fs = require("fs");
const { StatusCodes } = require("http-status-codes");
-const APIError = require("../../utils/APIError");
+const APIError = require("../../utils/apiError");
const { CLIENT_RENEG_LIMIT } = require("tls");
const fileUpload =
diff --git a/server/models/log.model.js b/server/models/log.model.js
new file mode 100644
index 0000000..c93c6f7
--- /dev/null
+++ b/server/models/log.model.js
@@ -0,0 +1,34 @@
+const mongoose = require("mongoose");
+
+const logSchema = new mongoose.Schema({
+ user: {
+ type: mongoose.Schema.Types.ObjectId,
+ ref: "User",
+ },
+ ipAddress: {
+ type: String,
+ required: true
+ },
+ action: {
+ type: String,
+ required: true,
+ default:'unknown'
+ },
+ entity:{
+ name:{
+ type:String,
+ default:'none'
+ },
+ id:{
+ type:mongoose.Schema.Types.ObjectId
+ }
+ }
+ },
+ {
+ timestamps: true,
+ }
+ );
+
+const LogModel = mongoose.model("Logs", logSchema);
+
+module.exports = LogModel;
\ No newline at end of file
diff --git a/server/models/user.model.js b/server/models/user.model.js
index e14ddb7..4673cf5 100644
--- a/server/models/user.model.js
+++ b/server/models/user.model.js
@@ -108,15 +108,15 @@ const user = new mongoose.Schema(
type: Boolean,
default: true,
},
- role: {
- type: String,
- required: false,
- default: "user",
- enum: {
- values: ["manager", "receptionist", "user"],
- message: "role can be either reception, manager or user",
- },
- },
+ // role: {
+ // type: String,
+ // required: false,
+ // default: "user",
+ // enum: {
+ // values: ["manager", "receptionist", "user"],
+ // message: "role can be either reception, manager or user",
+ // },
+ // },
// notificationCount: {
// type: Number,
// default: 0,
diff --git a/server/routes/logRoutes.js b/server/routes/logRoutes.js
new file mode 100644
index 0000000..083b5cf
--- /dev/null
+++ b/server/routes/logRoutes.js
@@ -0,0 +1,9 @@
+const express = require('express');
+const router = express.Router();
+const {getLogs} = require('../controller/log')
+
+router
+ .route("/")
+ .get(getLogs);
+
+module.exports = router;
\ No newline at end of file
diff --git a/server/routes/routes.js b/server/routes/routes.js
index 53bf599..b0766fd 100644
--- a/server/routes/routes.js
+++ b/server/routes/routes.js
@@ -7,6 +7,7 @@ const questionRouter = require("./questionRoutes");
const organizationRouter = require("./organizationRoutes");
const notificationRouter = require("./notificationRoutes");
const userAnswerRouter = require("./userAnswerRoutes");
+const logRouter = require("./logRoutes");
router.use("/users", userRouter);
router.use("/exams", examRouter);
@@ -14,5 +15,6 @@ router.use("/questions", questionRouter);
router.use("/organizations", organizationRouter);
router.use("/notifications", notificationRouter);
router.use("/useranswers", userAnswerRouter);
+router.use("/log", logRouter);
module.exports = router;
diff --git a/server/utils/logActivity.js b/server/utils/logActivity.js
new file mode 100644
index 0000000..d8be750
--- /dev/null
+++ b/server/utils/logActivity.js
@@ -0,0 +1,21 @@
+const Log = require("../models/log.model");
+const actionTypes = ["created","edited","archived","loggedIn","deactivated", "delete","activated","joined"]
+// const entities = ["an organization","an exam","user"]
+
+
+const logActivity = async (req,actionIndex, {name,id}) => {
+
+ await Log.create({
+ user: req.user.id? req.user._id : 'Unknown',
+ ipAddress: req.ip? req.ip : 'Unknown',
+ action:`${actionTypes[actionIndex]}`,
+ entity:{
+ name,
+ id
+ }
+ });
+ };
+
+module.exports = {
+ logActivity,
+};
\ No newline at end of file
From a182e50ee2e9e0bc66f4e30722b0ac97440e68d3 Mon Sep 17 00:00:00 2001
From: Tibebe Solomon <87706650+Tibex88@users.noreply.github.com>
Date: Wed, 5 Jun 2024 15:43:34 +0300
Subject: [PATCH 02/59] added logging and debugged
---
server/controller/exam/createExam.js | 2 +-
server/controller/exam/updateExam.js | 2 +-
server/controller/organization/activateExaminer.js | 2 +-
server/controller/organization/createOrganization.js | 2 +-
server/controller/organization/deactivateExaminer.js | 2 +-
server/controller/organization/joinOrganization.js | 2 +-
server/controller/organization/updateOrganizationLogo.js | 2 +-
server/models/log.model.js | 2 +-
server/utils/logActivity.js | 5 +++--
9 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/server/controller/exam/createExam.js b/server/controller/exam/createExam.js
index 009fbc3..6c93712 100644
--- a/server/controller/exam/createExam.js
+++ b/server/controller/exam/createExam.js
@@ -82,7 +82,7 @@ exports.createExam = catchAsync(async (req, res, next) => {
await exam.save();
- await logActivity(req,0,{name:exam?.modelName,id:exam.id} )
+ await logActivity(req,0,{name:'exam',id:exam.id} )
res.status(201).json({
status: "success",
diff --git a/server/controller/exam/updateExam.js b/server/controller/exam/updateExam.js
index 00aab3f..e84c8c0 100644
--- a/server/controller/exam/updateExam.js
+++ b/server/controller/exam/updateExam.js
@@ -64,7 +64,7 @@ exports.updateExamResource = catchAsync(async (req, res, next) => {
await exam.save();
- await logActivity(req,1,{name:exam?.modelName,id:exam.id} )
+ await logActivity(req,1,{name:'exam',id:exam.id} )
res.status(StatusCodes.OK).json({
status: "success",
diff --git a/server/controller/organization/activateExaminer.js b/server/controller/organization/activateExaminer.js
index 9e93547..b7ff088 100644
--- a/server/controller/organization/activateExaminer.js
+++ b/server/controller/organization/activateExaminer.js
@@ -50,7 +50,7 @@ exports.activateExaminer = catchAsync(async (req, res, next) => {
message: `Your account as an Examiner has been Activated. In the Organization ${organization.name}`,
});
- await logActivity(req,6,{name:organizationExaminer?.modelName,id:user.id} )
+ await logActivity(req,6,{name:'Organization Examiner',id:user.id} )
res.status(StatusCodes.OK).json({
diff --git a/server/controller/organization/createOrganization.js b/server/controller/organization/createOrganization.js
index 03b7b86..0fdd89d 100644
--- a/server/controller/organization/createOrganization.js
+++ b/server/controller/organization/createOrganization.js
@@ -52,7 +52,7 @@ exports.createOrganization = catchAsync(async (req, res, next) => {
status: "activated",
});
- await logActivity(req,0,{name:Organization?.modelName,id:newOrganization.id} )
+ await logActivity(req,0,{name:'Organization',id:newOrganization.id} )
res.status(StatusCodes.CREATED).json({
sucess: true,
diff --git a/server/controller/organization/deactivateExaminer.js b/server/controller/organization/deactivateExaminer.js
index 62460c9..51c0231 100644
--- a/server/controller/organization/deactivateExaminer.js
+++ b/server/controller/organization/deactivateExaminer.js
@@ -43,7 +43,7 @@ exports.deactivateExaminer = catchAsync(async (req, res, next) => {
// save the organization
await organizationExaminer.save();
- await logActivity(req,4,{name:organizationExaminer?.modelName,id:userId} )
+ await logActivity(req,4,{name:'organization Examiner',id:userId} )
res.status(StatusCodes.OK).json({
status: "success",
diff --git a/server/controller/organization/joinOrganization.js b/server/controller/organization/joinOrganization.js
index d892b24..e61fb1e 100644
--- a/server/controller/organization/joinOrganization.js
+++ b/server/controller/organization/joinOrganization.js
@@ -51,7 +51,7 @@ exports.joinOrganization = catchAsync(async (req, res, next) => {
message: `User with id ${userId} has requested to join the organization `,
});
- await logActivity(req,7,{name:organization?.modelName,id:organization.id} )
+ await logActivity(req,7,{name:'Organization',id:organization.id} )
res.status(StatusCodes.OK).json({
status: "success",
diff --git a/server/controller/organization/updateOrganizationLogo.js b/server/controller/organization/updateOrganizationLogo.js
index 21c3309..b18b6f6 100644
--- a/server/controller/organization/updateOrganizationLogo.js
+++ b/server/controller/organization/updateOrganizationLogo.js
@@ -38,7 +38,7 @@ exports.updateOrganizationLogo = catchAsync(async (req, res, next) => {
organization.logo = logo;
await organization.save();
- await logActivity(req,1,{name:organization?.modelName,id:organization.id} )
+ await logActivity(req,1,{name:'Organization',id:organization.id} )
res.status(StatusCodes.CREATED).json({
status: "success",
diff --git a/server/models/log.model.js b/server/models/log.model.js
index c93c6f7..8a80d71 100644
--- a/server/models/log.model.js
+++ b/server/models/log.model.js
@@ -20,7 +20,7 @@ const logSchema = new mongoose.Schema({
default:'none'
},
id:{
- type:mongoose.Schema.Types.ObjectId
+ type:String
}
}
},
diff --git a/server/utils/logActivity.js b/server/utils/logActivity.js
index d8be750..8294cf0 100644
--- a/server/utils/logActivity.js
+++ b/server/utils/logActivity.js
@@ -5,9 +5,10 @@ const actionTypes = ["created","edited","archived","loggedIn","deactivated", "de
const logActivity = async (req,actionIndex, {name,id}) => {
+ console.log(req.user.id)
await Log.create({
- user: req.user.id? req.user._id : 'Unknown',
- ipAddress: req.ip? req.ip : 'Unknown',
+ user: req.user.id? req.user.id : 'Unknown',
+ ipAddress: req .ip? req.ip : 'Unknown',
action:`${actionTypes[actionIndex]}`,
entity:{
name,
From bebcaf33faf023fc0f8344ec170626fecb2d2f7f Mon Sep 17 00:00:00 2001
From: Yohannes Teshome <83913756+johannesteshome@users.noreply.github.com>
Date: Fri, 7 Jun 2024 12:33:23 +0300
Subject: [PATCH 03/59] landing page route done
---
client/package-lock.json | 534 +-----------------
client/src/Components/NavBar.jsx | 10 +-
.../src/Screens/LandingPageScreens/About.jsx | 7 +-
.../Screens/LandingPageScreens/Customers.jsx | 7 +-
.../src/Screens/LandingPageScreens/Home.jsx | 45 +-
client/tests/example.spec.js | 2 +-
6 files changed, 62 insertions(+), 543 deletions(-)
diff --git a/client/package-lock.json b/client/package-lock.json
index c577057..8fef2bf 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -514,336 +514,6 @@
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
},
- "node_modules/@esbuild/aix-ppc64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
- "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
- "cpu": [
- "ppc64"
- ],
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
- "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
- "cpu": [
- "arm"
- ],
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
- "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
- "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
- "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
- "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
- "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
- "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
- "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
- "cpu": [
- "arm"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
- "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
- "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
- "cpu": [
- "ia32"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
- "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
- "cpu": [
- "loong64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
- "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
- "cpu": [
- "mips64el"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
- "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
- "cpu": [
- "ppc64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
- "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
- "cpu": [
- "riscv64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
- "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
- "cpu": [
- "s390x"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
- "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
- "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
- "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
- "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
- "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
- "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
- "cpu": [
- "ia32"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
"node_modules/@esbuild/win32-x64": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
@@ -1197,15 +867,6 @@
"node": ">=14"
}
},
- "node_modules/@rc-component/async-validator": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz",
- "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==",
- "dependencies": {
- "@babel/runtime": "^7.24.4"
- },
- "engines": {
- "node": ">=14.x"
"node_modules/@playwright/test": {
"version": "1.44.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz",
@@ -1221,6 +882,17 @@
"node": ">=16"
}
},
+ "node_modules/@rc-component/async-validator": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz",
+ "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==",
+ "dependencies": {
+ "@babel/runtime": "^7.24.4"
+ },
+ "engines": {
+ "node": ">=14.x"
+ }
+ },
"node_modules/@rc-component/color-picker": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.5.3.tgz",
@@ -1525,150 +1197,6 @@
"node": ">=14.0.0"
}
},
- "node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
- "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==",
- "cpu": [
- "arm"
- ],
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-android-arm64": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz",
- "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz",
- "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz",
- "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz",
- "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==",
- "cpu": [
- "arm"
- ],
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz",
- "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz",
- "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz",
- "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==",
- "cpu": [
- "riscv64"
- ],
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz",
- "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz",
- "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz",
- "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz",
- "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==",
- "cpu": [
- "ia32"
- ],
- "optional": true,
- "os": [
- "win32"
- ]
- },
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz",
@@ -4147,19 +3675,6 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "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",
@@ -5962,20 +5477,6 @@
"node": ">=16"
}
},
- "node_modules/playwright/node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/possible-typed-array-names": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
@@ -8321,7 +7822,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
-
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "devOptional": true
+ },
"node_modules/unicode-properties": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
@@ -8344,12 +7850,6 @@
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
-
- "node_modules/undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "devOptional": true
},
"node_modules/unload": {
"version": "2.2.0",
diff --git a/client/src/Components/NavBar.jsx b/client/src/Components/NavBar.jsx
index fda3012..995b516 100644
--- a/client/src/Components/NavBar.jsx
+++ b/client/src/Components/NavBar.jsx
@@ -11,7 +11,7 @@ import fetena_logo from "../assets/fetena_logo.png"
import Hamburger from "hamburger-react"
-const NavBar = () => {
+const NavBar = ({displayPage, setDisplayPage}) => {
const [isOpen, setOpen] = useState(false)
@@ -59,6 +59,7 @@ const NavBar = () => {
-
setDisplayPage('home')}
href='#'
className='block py-2 px-3 text-white bg-primary-500 rounded md:bg-transparent md:text-primary-500 md:p-0 md:dark:text-primary-500'>
Home
@@ -66,6 +67,7 @@ const NavBar = () => {
-
setDisplayPage('home')}
href='#how-it-works'
className='block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-primary-500 md:p-0 '>
How It Works
@@ -73,14 +75,16 @@ const NavBar = () => {
-
setDisplayPage('customers')}
+ href="#"
className='block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-primary-500 md:p-0 '>
Customers
-
setDisplayPage('about')}
+ href="#"
className='block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 '>
About
diff --git a/client/src/Screens/LandingPageScreens/About.jsx b/client/src/Screens/LandingPageScreens/About.jsx
index 7ca86aa..4c1047c 100644
--- a/client/src/Screens/LandingPageScreens/About.jsx
+++ b/client/src/Screens/LandingPageScreens/About.jsx
@@ -12,7 +12,7 @@ import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
-const Home = () => {
+const About = () => {
const navigate = useNavigate()
@@ -36,7 +36,8 @@ const Home = () => {
return (
<>
-
+
About
+
@@ -52,4 +53,4 @@ const Home = () => {
>
);
};
-export default Home;
+export default About;
diff --git a/client/src/Screens/LandingPageScreens/Customers.jsx b/client/src/Screens/LandingPageScreens/Customers.jsx
index 7ca86aa..0751ab3 100644
--- a/client/src/Screens/LandingPageScreens/Customers.jsx
+++ b/client/src/Screens/LandingPageScreens/Customers.jsx
@@ -12,7 +12,7 @@ import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
-const Home = () => {
+const Customers = () => {
const navigate = useNavigate()
@@ -36,7 +36,7 @@ const Home = () => {
return (
<>
-
+ Customers
@@ -48,8 +48,7 @@ const Home = () => {
-
>
);
};
-export default Home;
+export default Customers;
diff --git a/client/src/Screens/LandingPageScreens/Home.jsx b/client/src/Screens/LandingPageScreens/Home.jsx
index 7ca86aa..7ba2487 100644
--- a/client/src/Screens/LandingPageScreens/Home.jsx
+++ b/client/src/Screens/LandingPageScreens/Home.jsx
@@ -10,13 +10,16 @@ import Footer from "../../Components/Footer";
import TestimonySection from "../../Components/TestimonySection";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
-import { useEffect } from "react";
+import { useEffect, useState } from "react";
+import About from "./About";
+import Customers from "./Customers";
const Home = () => {
+ const navigate = useNavigate();
- const navigate = useNavigate()
+ const [displayPage, setDisplayPage] = useState("home");
- const { isAuthenticated } = useSelector((state) => state.auth)
+ const { isAuthenticated } = useSelector((state) => state.auth);
useEffect(() => {
if (isAuthenticated) {
@@ -36,18 +39,30 @@ const Home = () => {
return (
<>
-
-
-
-
-
-
-
-
-
-
-
-
+
+ {displayPage === "home" ? (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ ) : displayPage === "customers" ? (
+
+ ) : (
+
+ )}
+
>
);
diff --git a/client/tests/example.spec.js b/client/tests/example.spec.js
index d5082f1..627e3e5 100644
--- a/client/tests/example.spec.js
+++ b/client/tests/example.spec.js
@@ -1,4 +1,4 @@
-import { test, expect } from "@playwright/test"
+import { test, expect } from "@playwright/test";
// Mock user credentials
const validEmail = "johnrobitm@gmail.com";
From 569cd1da5000bbb7e2e62a67d9043eb90d1e9cd2 Mon Sep 17 00:00:00 2001
From: Yohannes Teshome <83913756+johannesteshome@users.noreply.github.com>
Date: Fri, 7 Jun 2024 18:09:19 +0300
Subject: [PATCH 04/59] finished organziation details
---
client/src/Components/ExamCard.jsx | 17 ++--
client/src/Pages/ExamDetailPage.jsx | 7 +-
client/src/Pages/OrganizationsDetails.jsx | 111 ++++++++++++++++++----
server/routes/examRoutes.js | 3 +-
server/sockets/chatSocket.js | 7 +-
5 files changed, 110 insertions(+), 35 deletions(-)
diff --git a/client/src/Components/ExamCard.jsx b/client/src/Components/ExamCard.jsx
index 851114c..fca238c 100644
--- a/client/src/Components/ExamCard.jsx
+++ b/client/src/Components/ExamCard.jsx
@@ -3,9 +3,9 @@ import { Card, Tag } from "antd";
import { Link } from "react-router-dom";
Icon
-const ExamCard = () => {
+const ExamCard = ({exam, key}) => {
return (
-
+
{
className='text-4xl text-blue-700'
/>
-
English exam
-
- English
- Maths
- Physics
-
+
{ exam.examName }
- AASTU{" "}
-
+ {exam.organization?.name}
+ { exam.organization?.isVerified &&
-
+ }
diff --git a/client/src/Pages/ExamDetailPage.jsx b/client/src/Pages/ExamDetailPage.jsx
index 7b318c2..b951f6f 100644
--- a/client/src/Pages/ExamDetailPage.jsx
+++ b/client/src/Pages/ExamDetailPage.jsx
@@ -41,12 +41,11 @@ const ExamDetailPage = () => {
-
- window.history.back()}
icon='fluent-emoji-high-contrast:left-arrow'
- className='text-2xl text-primary-500'
+ className='text-2xl text-primary-500 cursor-pointer'
/>
-
Exam Details
diff --git a/client/src/Pages/OrganizationsDetails.jsx b/client/src/Pages/OrganizationsDetails.jsx
index a3de3eb..1397e73 100644
--- a/client/src/Pages/OrganizationsDetails.jsx
+++ b/client/src/Pages/OrganizationsDetails.jsx
@@ -4,15 +4,19 @@ import {
followOrganization,
unfollowOrganization,
getOneOrganization,
+ organizationStaff,
} from "../Redux/features/dataActions";
import { useDispatch, useSelector } from "react-redux";
import { toast } from "react-toastify";
-import { Card, Divider } from "antd";
+import { Card, Avatar } from "antd";
import { Icon } from "@iconify/react";
import Button from "../Components/Button";
import { Link } from "react-router-dom";
import ExamCard from "../Components/ExamCard";
import { getMe } from "../Redux/features/authActions";
+import axios from "axios";
+
+const {Meta} = Card
const OrganizationsDetails = () => {
const { "*": id } = useParams();
@@ -21,6 +25,8 @@ const OrganizationsDetails = () => {
const { user } = useSelector((state) => state.auth);
const [activeTabKey, setActiveTabKey] = useState("exams");
const [followedOrganizations, setFollowedOrganizations] = useState([]);
+ const [personnels, setPersonnels] = useState([]);
+ const [exams, setExams] = useState([])
const serverURL = "http://localhost:3000";
console.log(user.organizationsFollowed, id, "user at first");
@@ -42,9 +48,52 @@ const OrganizationsDetails = () => {
setFollowedOrganizations((prevItems) => [...prevItems, org._id]);
}
console.log(followedOrganizations, "followedOrganizations");
+ // fetchOrganizationStaffs();
}, []);
+
+
+ const fetchOrganizationStaffs = () => {
+ setPersonnels([]);
+ dispatch(organizationStaff(id))
+ .then((res) => {
+ if (res.meta.requestStatus === "fulfilled") {
+ console.log(res.payload.data.data);
+ const data = res.payload.data.data;
+ const updatedStaffs = data.map((item) => ({
+ id: item.user._id,
+ profilePhoto: item.user.profilePhoto,
+ fullName: item.user.fullName,
+ email: item.user.email,
+ userType: item.user.userType,
+ }));
+ setPersonnels(updatedStaffs);
+ } else {
+ toast.error(res.payload.message);
+ }
+ })
+ .catch((error) => {
+ console.log(error);
+ toast.error("There is some error in the server!");
+ });
+ };
+
+ const fetchExams = async (page = 1, active = true, access = "open") => {
+
+ try {
+ const response = await axios.get(
+ `/api/exams/my-exam/${id}?active=${active}&access=${access}`
+ );
+
+ console.log(response, "bitch");
+ setExams(response.data.data.data);
+ console.log(exams, "exams");
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ }
+ };
+
// Function to handle organization follow action
const handleFollowOrganization = (id) => {
// Dispatch action to follow organization
@@ -109,28 +158,56 @@ const OrganizationsDetails = () => {
setActiveTabKey(key);
};
- const ExamPageView = () => {
+ useEffect(() => {
+ if (activeTabKey === "personnel") {
+ fetchOrganizationStaffs();
+ } else if (activeTabKey === "exams") {
+ fetchExams();
+ }
+ }, [activeTabKey]);
+
+ const ExamPageView = ({ exams }) => {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ {exams.length === 0 ? (
+
No Exams
+ ) : (
+
+ {exams.map((exam, index) => (
+
+ ))}
+
+ )}
);
};
+ const PersonnelPageView = ({personnels}) => {
+ return (
+
+ {personnels.map((personnel) => (
+
+
+ }
+ title={personnel.fullName}
+ description={personnel.userType}
+ />
+
+ ))}
+
+ );
+ }
+
const contentList = {
- exams:
,
- personnel: "as",
+ exams:
,
+ personnel:
,
};
const tabList = [
diff --git a/server/routes/examRoutes.js b/server/routes/examRoutes.js
index 9526c35..c62cbf8 100644
--- a/server/routes/examRoutes.js
+++ b/server/routes/examRoutes.js
@@ -16,9 +16,10 @@ const {
updateManyQuestion,
} = require("../controller/exam");
+
router.use(takeExamRouter);
-const { protect } = require("../controller/auth");
+const { protect, restrictTo } = require("../controller/auth");
router.route("/").get(protect, getAllExam).post(protect, createExam);
diff --git a/server/sockets/chatSocket.js b/server/sockets/chatSocket.js
index 1b1471d..7dcc5ec 100644
--- a/server/sockets/chatSocket.js
+++ b/server/sockets/chatSocket.js
@@ -1,7 +1,6 @@
const Exam = require("../models/exam.model");
const TakeExam = require("../models/take.exam.model");
-
const chatSocket = (io, socket) => {
// Join a room
socket.on("joinExam", async (examId, takeExamId) => {
@@ -102,7 +101,11 @@ const chatSocket = (io, socket) => {
await takeExam.save();
const invigilatorSocketId = exam.socketId;
- console.log("message sent successfully by examinee", message, invigilatorSocketId);
+ console.log(
+ "message sent successfully by examinee",
+ message,
+ invigilatorSocketId
+ );
// send the message to the invigilator
io.to(invigilatorSocketId).emit("receiveMessage", message);
From 07c28a5e9f048978a20f4bb7f58489e1f3ac33d9 Mon Sep 17 00:00:00 2001
From: yosef lakew <80267669+yoseflakew25@users.noreply.github.com>
Date: Sat, 8 Jun 2024 09:10:50 +0300
Subject: [PATCH 05/59] updated the styles of the exam monitoring pages
---
.../src/Pages/MonitoringPage/ChatWindow.jsx | 26 +++-
.../MonitoringPage/ExamineeListWindow.jsx | 56 +++++---
.../Pages/MonitoringPage/MonitoringPage.jsx | 26 ++--
.../Pages/MonitoringPage/MonitoringTab.jsx | 19 +--
.../src/Screens/LandingPageScreens/About.jsx | 112 ++++++++-------
.../Screens/LandingPageScreens/Customers.jsx | 129 ++++++++++++------
server/controller/profile/fileUpload.js | 7 +-
7 files changed, 236 insertions(+), 139 deletions(-)
diff --git a/client/src/Pages/MonitoringPage/ChatWindow.jsx b/client/src/Pages/MonitoringPage/ChatWindow.jsx
index b04663c..30d994c 100644
--- a/client/src/Pages/MonitoringPage/ChatWindow.jsx
+++ b/client/src/Pages/MonitoringPage/ChatWindow.jsx
@@ -1,6 +1,6 @@
import { Icon } from "@iconify/react";
import { current } from "@reduxjs/toolkit";
-import { Card, Input } from "antd";
+import { Card, Input,Tag } from "antd";
import { useEffect, useState } from "react";
import { MessageList } from "react-chat-elements";
import { useSelector } from "react-redux";
@@ -109,8 +109,26 @@ const ChatWindow = ({ currentUser, seeStatusOf, currentExam, socket }) => {
};
return (
-
-
+
+
+ {seeStatusOf === "all" ? (
+
+ ) : (
+
+ )}
+
+ {seeStatusOf === "all"
+ ? "Announce"
+ : "Message " + currentUser?.user?.fullName}
+
+
+ {/*
{seeStatusOf === "all" ? (
{
? "Announce"
: "Message " + currentUser?.user?.fullName}
-
+ */}
{
+const ExamineeListWindow = ({ examineeList, setSeeStatusOf }) => {
return (
-
-
-
Examinees
+
+
+
+ Examinees
+
{/*
{
{/* Submitted (4) */}
(
@@ -27,26 +27,46 @@ const ExamineeListWindow = ({examineeList, setSeeStatusOf}) => {
avatar={
+
}
/>
}
- title={ setSeeStatusOf("all")}>{item.title}}
+ title={
+
+ setSeeStatusOf("all")}
+ >
+ {item.title}
+
+
+ }
/>
)}
/>
(
-
+ setSeeStatusOf(item.user._id)}>
}
+ avatar={
+
+ }
title={
- setSeeStatusOf(item.user._id)}>
- {item.user.fullName}
-
+
}
/>
@@ -56,4 +76,4 @@ const ExamineeListWindow = ({examineeList, setSeeStatusOf}) => {
);
};
-export default ExamineeListWindow
\ No newline at end of file
+export default ExamineeListWindow;
diff --git a/client/src/Pages/MonitoringPage/MonitoringPage.jsx b/client/src/Pages/MonitoringPage/MonitoringPage.jsx
index f64cab8..404eca6 100644
--- a/client/src/Pages/MonitoringPage/MonitoringPage.jsx
+++ b/client/src/Pages/MonitoringPage/MonitoringPage.jsx
@@ -1,5 +1,5 @@
import { Icon } from "@iconify/react";
-import { Select, Card } from "antd";
+import { Select, Card,Tag } from "antd";
import React, { useState, useEffect, useRef } from "react";
import { useSelector } from "react-redux";
import useSocketIO from "../../utils/socket/useSocketIO";
@@ -223,16 +223,16 @@ const MonitoringPage = () => {
{!examsList.length ? (
-
Exam Monitoring
+ Exam Monitoring
You currently have no exams created.
) : (
-
-
Exam Monitoring
+
+
Exam Monitoring
-
Exam:
+
Exam :