diff --git a/Learnings.md b/Learnings.md index 0d874e3..6a8a5a9 100644 --- a/Learnings.md +++ b/Learnings.md @@ -2,4 +2,29 @@ -->Make sure to include type:module --->correct file name extensions i.e .js .ts etc \ No newline at end of file +-->correct file name extensions i.e .js .ts etc + + +-->🔥 Real backend example +❌ Without Promise.all (slow) +const user = await User.findById(id); +const orders = await Order.find({ userId: id }); +const payments = await Payment.find({ userId: id }); + +👉 Runs one after another (sequential) + +✅ With Promise.all (fast) +const [user, orders, payments] = await Promise.all([ + User.findById(id), + Order.find({ userId: id }), + Payment.find({ userId: id }) +]); + +👉 Runs all queries together (parallel) + +⚡ Performance gain +Sequential → takes sum of all times +Parallel → takes max of all times + + +--> \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 0834567..0000000 --- a/package-lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "EMS", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "bcryptjs": "^3.0.3" - } - }, - "node_modules/bcryptjs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", - "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", - "license": "BSD-3-Clause", - "bin": { - "bcrypt": "bin/bcrypt" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 1432103..0000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "bcryptjs": "^3.0.3" - } -} diff --git a/server/controllers/dashboardController.js b/server/controllers/dashboardController.js new file mode 100644 index 0000000..ac2b2f0 --- /dev/null +++ b/server/controllers/dashboardController.js @@ -0,0 +1,68 @@ +import { DEPARTMENTS } from "../constants/departments.js"; +import Attendance from "../models/Attendance.js" +import Employee from "../models/Employee.js" +import LeaveApplication from "../models/LeaveApplication.js"; + + +//Get dashboard for employee and admin +//GET /api/dashboard +export const getDashboard = async (req, res) => { + try { + + const session = req.session; + + if (session.role === "ADMIN") { + const [totalEmployees, todayAttendance, pendingLeaves] = await + Promise.all([ + Employee.countDocuments({ isDeleted: { $ne: true } }), + Attendance.countDocuments({ + date: { + $gte: new Date(new Date().setHours(0, 0, 0, 0)), + $lt: new Date(new Date().setHours(0, 0, 0, 0)), + } + }), + LeaveApplication.countDocuments({ status: "PENDING" }) + ]); + + return res.json({ + role: "ADMIN", + totalEmployees, + totalDepartments: DEPARTMENTS.length, + todayAttendance, + pendingLeaves, + }); + } else { + const employee = await Employee.findOne({ userId: session.userId }).lean(); + + if (!employee) + return res.status(404).json({ error: "Employee not found" }); + + const [currentMonthAttendance, pendingLeaves, latestPayslip] = await Promise.all([ + Attendance.countDocuments({ + employeeId: employee._id, + date: { + $gte: new Date(today.getFullYear(), today.getMonth(), today.getDate(), 1), + $lt: new Date(today.getFullYear(), today.getMonth() + 1, 1), + } + }), + + LeaveApplication.countDocuments({ + employeeId: employee._id, + status: "PENDING", + }), + Payslip.findOne({ employeeId: employee._id }).sort({ createdAt: -1 }).lean() + ]) + + return res.json({ + role: "EMPLOYEE", + employee: { ...employee, id: employee._id.toString() }, + currentMonthAttendance, + pendingLeaves, + latestPayslip: latestPayslip ? { ...latestPayslip, id: latestPayslip._id.toString() } : null, + }); + } + } catch (error) { + console.error("Dashbaord error:", error); + return res.status(500).json({ error: "Failed" }); + } +} \ No newline at end of file diff --git a/server/package-lock.json b/server/package-lock.json index 36b3e0d..14af512 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "bcrypt": "^6.0.0", + "bcryptjs": "^3.0.3", "cors": "^2.8.6", "dotenv": "^17.4.2", "express": "^5.2.1", @@ -102,6 +103,15 @@ "node": ">= 18" } }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", diff --git a/server/package.json b/server/package.json index 5ec67f5..ad2ea71 100644 --- a/server/package.json +++ b/server/package.json @@ -13,6 +13,7 @@ "description": "", "dependencies": { "bcrypt": "^6.0.0", + "bcryptjs": "^3.0.3", "cors": "^2.8.6", "dotenv": "^17.4.2", "express": "^5.2.1", @@ -23,4 +24,4 @@ "devDependencies": { "nodemon": "^3.1.14" } -} \ No newline at end of file +} diff --git a/server/routes/dashboardRoutes.js b/server/routes/dashboardRoutes.js new file mode 100644 index 0000000..33cb702 --- /dev/null +++ b/server/routes/dashboardRoutes.js @@ -0,0 +1,13 @@ +import { Router } from "express"; +import { protect } from "../middlewares/protect.js"; +import { getDashboard } from "../controllers/dashboardController.js"; + + + +const dashboardRouter = Router(); + + +dashboardRouter.get("/", protect, getDashboard); + + +export default dashboardRouter; \ No newline at end of file diff --git a/server/server.js b/server/server.js index 6dac82f..07ec8c6 100644 --- a/server/server.js +++ b/server/server.js @@ -10,7 +10,7 @@ import profileRouter from "./routes/profileRoutes.js"; import attendanceRouter from "./routes/AttendanceRoutes.js"; import leaveRouter from "./routes/leaveRoutes.js"; import paySlipRouter from "./routes/paySlipsRoutes.js"; - +import dashboardRouter from "./routes/dashboardRoutes.js"; const app = express() @@ -34,6 +34,7 @@ app.use('/api/profile', profileRouter); app.use('/api/attendance', attendanceRouter); app.use('/api/leave', leaveRouter); app.use('/api/payslip', paySlipRouter); +app.use('/api/dashboard', dashboardRouter); await connectDb();