create-jinmankn-app 1.0.13 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/HRMS (reba kuri iyi bro)/README.md +1 -0
- package/templates/{index/backend/controllers/authController.js → HRMS (reba kuri iyi bro)/backend/controllers/authController.js } +60 -10
- package/templates/HRMS (reba kuri iyi bro)/backend/cookiejar.txt +4 -0
- package/templates/HRMS (reba kuri iyi bro)/backend/middleware/auth.js +28 -0
- package/templates/{index/backend/models/User.js → HRMS (reba kuri iyi bro)/backend/models/User.js } +5 -0
- package/templates/{index/backend/package-lock.json → HRMS (reba kuri iyi bro)/backend/package-lock.json } +54 -13
- package/templates/{index/backend/package.json → HRMS (reba kuri iyi bro)/backend/package.json } +1 -0
- package/templates/HRMS (reba kuri iyi bro)/backend/routes/authRoutes.js +13 -0
- package/templates/{index/backend/routes/departmentRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/departmentRoutes.js } +4 -4
- package/templates/{index/backend/routes/employeeRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/employeeRoutes.js } +4 -4
- package/templates/{index/backend/routes/positionRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/positionRoutes.js } +4 -4
- package/templates/{index/backend/routes/reportRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/reportRoutes.js } +2 -2
- package/templates/{index/backend/server.js → HRMS (reba kuri iyi bro)/backend/server.js } +23 -1
- package/templates/{index/frontend/src/App.jsx → HRMS (reba kuri iyi bro)/frontend/src/App.jsx } +3 -1
- package/templates/{index/frontend/src/components/DashboardLayout.jsx → HRMS (reba kuri iyi bro)/frontend/src/components/DashboardLayout.jsx } +24 -5
- package/templates/{index/frontend/src/components/ProtectedRoute.jsx → HRMS (reba kuri iyi bro)/frontend/src/components/ProtectedRoute.jsx } +2 -2
- package/templates/{index/frontend/src/main.jsx → HRMS (reba kuri iyi bro)/frontend/src/main.jsx } +4 -1
- package/templates/HRMS (reba kuri iyi bro)/frontend/src/pages/CreateUser.jsx +150 -0
- package/templates/{index/frontend/src/pages/DashboardHome.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/DashboardHome.jsx } +4 -4
- package/templates/{index/frontend/src/pages/Department.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Department.jsx } +47 -36
- package/templates/{index/frontend/src/pages/Employee.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Employee.jsx } +27 -16
- package/templates/{index/frontend/src/pages/Login.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Login.jsx } +7 -3
- package/templates/{index/frontend/src/pages/Position.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Position.jsx } +27 -16
- package/templates/{index/frontend/src/pages/Register.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Register.jsx } +10 -6
- package/templates/{index/frontend/src/pages/Reports.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Reports.jsx } +2 -3
- package/templates/HRMS (reba kuri iyi bro)/frontend/vite.config.js +18 -0
- package/templates/index/README.md +0 -34
- package/templates/index/backend/middleware/auth.js +0 -27
- package/templates/index/backend/routes/authRoutes.js +0 -11
- package/templates/index/frontend/vite.config.js +0 -7
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/config/db.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/departmentController.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/employeeController.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/positionController.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/reportController.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/models/Department.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/models/Employee.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/models/Position.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/routes/protectedRoutes.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/README.md +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/eslint.config.js +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/index.html +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/package-lock.json +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/package.json +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/public/favicon.svg +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/src/App.css +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/src/assets/hero.png +0 -0
- /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/src/index.css +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
umvax mbaye nshyizeho iyi reka mbanze nkore test numona i dakora fresh uze gusubiroho after 10min ndaba naya updatinze
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
const bcrypt = require('bcrypt');
|
|
2
|
-
const jwt = require('jsonwebtoken');
|
|
3
2
|
const User = require('../models/User');
|
|
4
|
-
const
|
|
3
|
+
const Employee = require('../models/Employee');
|
|
5
4
|
|
|
6
|
-
function createToken(userId) {
|
|
7
|
-
return jwt.sign({ userId }, JWT_SECRET, { expiresIn: '7d' });
|
|
8
|
-
}
|
|
9
|
-
//this function is formatting the user object to return the id, name, and email when
|
|
10
5
|
function formatUser(user) {
|
|
11
6
|
return {
|
|
12
7
|
id: user._id,
|
|
13
8
|
name: user.name,
|
|
14
9
|
email: user.email,
|
|
10
|
+
role: user.role || 'user',
|
|
11
|
+
employee: user.employee || null,
|
|
15
12
|
};
|
|
16
13
|
}
|
|
17
14
|
|
|
@@ -32,17 +29,57 @@ exports.register = async (req, res) => {
|
|
|
32
29
|
return res.status(409).json({ message: 'Email already registered' });
|
|
33
30
|
}
|
|
34
31
|
|
|
32
|
+
const userCount = await User.countDocuments();
|
|
33
|
+
if (userCount > 0) {
|
|
34
|
+
return res.status(403).json({ message: 'Registration closed. Ask an admin to create an account.' });
|
|
35
|
+
}
|
|
36
|
+
|
|
35
37
|
const hashedPassword = await bcrypt.hash(password, 10);
|
|
36
38
|
const user = await User.create({
|
|
37
39
|
name: name.trim(),
|
|
38
40
|
email: email.trim().toLowerCase(),
|
|
39
41
|
password: hashedPassword,
|
|
42
|
+
role: 'admin',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
req.session.userId = user._id;
|
|
46
|
+
|
|
47
|
+
res.status(201).json({
|
|
48
|
+
user: formatUser(user),
|
|
40
49
|
});
|
|
50
|
+
} catch (err) {
|
|
51
|
+
res.status(500).json({ message: err.message });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
exports.createUser = async (req, res) => {
|
|
56
|
+
try {
|
|
57
|
+
const { employeeId, password } = req.body;
|
|
58
|
+
|
|
59
|
+
if (!employeeId || !password) {
|
|
60
|
+
return res.status(400).json({ message: 'Employee and password are required' });
|
|
61
|
+
}
|
|
41
62
|
|
|
42
|
-
const
|
|
63
|
+
const employee = await Employee.findById(employeeId);
|
|
64
|
+
if (!employee) {
|
|
65
|
+
return res.status(404).json({ message: 'Employee not found' });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const existing = await User.findOne({ email: employee.email });
|
|
69
|
+
if (existing) {
|
|
70
|
+
return res.status(409).json({ message: 'A user already exists for this employee' });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const hashedPassword = await bcrypt.hash(password, 10);
|
|
74
|
+
const user = await User.create({
|
|
75
|
+
name: `${employee.firstName} ${employee.lastName}`.trim(),
|
|
76
|
+
email: employee.email,
|
|
77
|
+
password: hashedPassword,
|
|
78
|
+
role: 'user',
|
|
79
|
+
employee: employee._id,
|
|
80
|
+
});
|
|
43
81
|
|
|
44
82
|
res.status(201).json({
|
|
45
|
-
token,
|
|
46
83
|
user: formatUser(user),
|
|
47
84
|
});
|
|
48
85
|
} catch (err) {
|
|
@@ -68,10 +105,9 @@ exports.login = async (req, res) => {
|
|
|
68
105
|
return res.status(401).json({ message: 'Invalid email or password' });
|
|
69
106
|
}
|
|
70
107
|
|
|
71
|
-
|
|
108
|
+
req.session.userId = user._id;
|
|
72
109
|
|
|
73
110
|
res.json({
|
|
74
|
-
token,
|
|
75
111
|
user: formatUser(user),
|
|
76
112
|
});
|
|
77
113
|
} catch (err) {
|
|
@@ -86,3 +122,17 @@ exports.getMe = async (req, res) => {
|
|
|
86
122
|
res.status(500).json({ message: err.message });
|
|
87
123
|
}
|
|
88
124
|
};
|
|
125
|
+
|
|
126
|
+
exports.logout = async (req, res) => {
|
|
127
|
+
try {
|
|
128
|
+
req.session.destroy((err) => {
|
|
129
|
+
if (err) {
|
|
130
|
+
return res.status(500).json({ message: 'Logout failed' });
|
|
131
|
+
}
|
|
132
|
+
res.clearCookie('connect.sid');
|
|
133
|
+
res.json({ message: 'Logged out successfully' });
|
|
134
|
+
});
|
|
135
|
+
} catch (err) {
|
|
136
|
+
res.status(500).json({ message: err.message });
|
|
137
|
+
}
|
|
138
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
const User = require('../models/User');
|
|
3
|
+
|
|
4
|
+
exports.protect = async (req, res, next) => {
|
|
5
|
+
try {
|
|
6
|
+
if (!req.session || !req.session.userId) {
|
|
7
|
+
return res.status(401).json({ message: 'Not authorized' });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const user = await User.findById(req.session.userId).select('-password');
|
|
11
|
+
|
|
12
|
+
if (!user) {
|
|
13
|
+
return res.status(401).json({ message: 'Not authorized' });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
req.user = user;
|
|
17
|
+
next();
|
|
18
|
+
} catch (err) {
|
|
19
|
+
return res.status(401).json({ message: 'Not authorized' });
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
exports.admin = (req, res, next) => {
|
|
24
|
+
if (!req.user || req.user.role !== 'admin') {
|
|
25
|
+
return res.status(403).json({ message: 'Admin access required' });
|
|
26
|
+
}
|
|
27
|
+
next();
|
|
28
|
+
};
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"bcrypt": "^5.1.1",
|
|
13
13
|
"cors": "^2.8.5",
|
|
14
|
-
"dotenv": "^16.4.7",
|
|
15
14
|
"express": "^4.21.2",
|
|
15
|
+
"express-session": "^1.19.0",
|
|
16
16
|
"jsonwebtoken": "^9.0.2",
|
|
17
17
|
"mongoose": "^8.9.3"
|
|
18
18
|
},
|
|
@@ -458,18 +458,6 @@
|
|
|
458
458
|
"node": ">=8"
|
|
459
459
|
}
|
|
460
460
|
},
|
|
461
|
-
"node_modules/dotenv": {
|
|
462
|
-
"version": "16.6.1",
|
|
463
|
-
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
|
464
|
-
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
|
465
|
-
"license": "BSD-2-Clause",
|
|
466
|
-
"engines": {
|
|
467
|
-
"node": ">=12"
|
|
468
|
-
},
|
|
469
|
-
"funding": {
|
|
470
|
-
"url": "https://dotenvx.com"
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
461
|
"node_modules/dunder-proto": {
|
|
474
462
|
"version": "1.0.1",
|
|
475
463
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
|
@@ -605,6 +593,29 @@
|
|
|
605
593
|
"url": "https://opencollective.com/express"
|
|
606
594
|
}
|
|
607
595
|
},
|
|
596
|
+
"node_modules/express-session": {
|
|
597
|
+
"version": "1.19.0",
|
|
598
|
+
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.19.0.tgz",
|
|
599
|
+
"integrity": "sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==",
|
|
600
|
+
"license": "MIT",
|
|
601
|
+
"dependencies": {
|
|
602
|
+
"cookie": "~0.7.2",
|
|
603
|
+
"cookie-signature": "~1.0.7",
|
|
604
|
+
"debug": "~2.6.9",
|
|
605
|
+
"depd": "~2.0.0",
|
|
606
|
+
"on-headers": "~1.1.0",
|
|
607
|
+
"parseurl": "~1.3.3",
|
|
608
|
+
"safe-buffer": "~5.2.1",
|
|
609
|
+
"uid-safe": "~2.1.5"
|
|
610
|
+
},
|
|
611
|
+
"engines": {
|
|
612
|
+
"node": ">= 0.8.0"
|
|
613
|
+
},
|
|
614
|
+
"funding": {
|
|
615
|
+
"type": "opencollective",
|
|
616
|
+
"url": "https://opencollective.com/express"
|
|
617
|
+
}
|
|
618
|
+
},
|
|
608
619
|
"node_modules/fill-range": {
|
|
609
620
|
"version": "7.1.1",
|
|
610
621
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
|
@@ -1613,6 +1624,15 @@
|
|
|
1613
1624
|
"node": ">= 0.8"
|
|
1614
1625
|
}
|
|
1615
1626
|
},
|
|
1627
|
+
"node_modules/on-headers": {
|
|
1628
|
+
"version": "1.1.0",
|
|
1629
|
+
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
|
1630
|
+
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
|
1631
|
+
"license": "MIT",
|
|
1632
|
+
"engines": {
|
|
1633
|
+
"node": ">= 0.8"
|
|
1634
|
+
}
|
|
1635
|
+
},
|
|
1616
1636
|
"node_modules/once": {
|
|
1617
1637
|
"version": "1.4.0",
|
|
1618
1638
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
|
@@ -1703,6 +1723,15 @@
|
|
|
1703
1723
|
"url": "https://github.com/sponsors/ljharb"
|
|
1704
1724
|
}
|
|
1705
1725
|
},
|
|
1726
|
+
"node_modules/random-bytes": {
|
|
1727
|
+
"version": "1.0.0",
|
|
1728
|
+
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
|
1729
|
+
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
|
|
1730
|
+
"license": "MIT",
|
|
1731
|
+
"engines": {
|
|
1732
|
+
"node": ">= 0.8"
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1706
1735
|
"node_modules/range-parser": {
|
|
1707
1736
|
"version": "1.2.1",
|
|
1708
1737
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
|
@@ -2103,6 +2132,18 @@
|
|
|
2103
2132
|
"node": ">= 0.6"
|
|
2104
2133
|
}
|
|
2105
2134
|
},
|
|
2135
|
+
"node_modules/uid-safe": {
|
|
2136
|
+
"version": "2.1.5",
|
|
2137
|
+
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
|
2138
|
+
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
|
|
2139
|
+
"license": "MIT",
|
|
2140
|
+
"dependencies": {
|
|
2141
|
+
"random-bytes": "~1.0.0"
|
|
2142
|
+
},
|
|
2143
|
+
"engines": {
|
|
2144
|
+
"node": ">= 0.8"
|
|
2145
|
+
}
|
|
2146
|
+
},
|
|
2106
2147
|
"node_modules/undefsafe": {
|
|
2107
2148
|
"version": "2.0.5",
|
|
2108
2149
|
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const { register, login, getMe, createUser, logout } = require('../controllers/authController');
|
|
3
|
+
const { protect, admin } = require('../middleware/auth');
|
|
4
|
+
|
|
5
|
+
const router = express.Router();
|
|
6
|
+
|
|
7
|
+
router.post('/register', register);
|
|
8
|
+
router.post('/login', login);
|
|
9
|
+
router.post('/logout', protect, logout);
|
|
10
|
+
router.post('/users', protect, admin, createUser);
|
|
11
|
+
router.get('/me', protect, getMe);
|
|
12
|
+
|
|
13
|
+
module.exports = router;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
|
-
const { protect } = require('../middleware/auth');
|
|
3
|
+
const { protect, admin } = require('../middleware/auth');
|
|
4
4
|
const {
|
|
5
5
|
addDepartment,
|
|
6
6
|
getDepartments,
|
|
@@ -9,9 +9,9 @@ const {
|
|
|
9
9
|
} = require('../controllers/departmentController');
|
|
10
10
|
|
|
11
11
|
router.use(protect);
|
|
12
|
-
router.post('/add', addDepartment);
|
|
12
|
+
router.post('/add', admin, addDepartment);
|
|
13
13
|
router.get('/list', getDepartments);
|
|
14
|
-
router.put('/:id', updateDepartment);
|
|
15
|
-
router.delete('/:id', deleteDepartment);
|
|
14
|
+
router.put('/:id', admin, updateDepartment);
|
|
15
|
+
router.delete('/:id', admin, deleteDepartment);
|
|
16
16
|
|
|
17
17
|
module.exports = router;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
|
-
const { protect } = require('../middleware/auth');
|
|
3
|
+
const { protect, admin } = require('../middleware/auth');
|
|
4
4
|
const {
|
|
5
5
|
addEmployee,
|
|
6
6
|
getEmployees,
|
|
@@ -10,10 +10,10 @@ const {
|
|
|
10
10
|
} = require('../controllers/employeeController');
|
|
11
11
|
|
|
12
12
|
router.use(protect);
|
|
13
|
-
router.post('/add', addEmployee);
|
|
13
|
+
router.post('/add', admin, addEmployee);
|
|
14
14
|
router.get('/list', getEmployees);
|
|
15
15
|
router.get('/:id', getEmployee);
|
|
16
|
-
router.put('/:id', updateEmployee);
|
|
17
|
-
router.delete('/:id', deleteEmployee);
|
|
16
|
+
router.put('/:id', admin, updateEmployee);
|
|
17
|
+
router.delete('/:id', admin, deleteEmployee);
|
|
18
18
|
|
|
19
19
|
module.exports = router;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
|
-
const { protect } = require('../middleware/auth');
|
|
3
|
+
const { protect, admin } = require('../middleware/auth');
|
|
4
4
|
const {
|
|
5
5
|
addPosition,
|
|
6
6
|
getPositions,
|
|
@@ -9,9 +9,9 @@ const {
|
|
|
9
9
|
} = require('../controllers/positionController');
|
|
10
10
|
|
|
11
11
|
router.use(protect);
|
|
12
|
-
router.post('/add', addPosition);
|
|
12
|
+
router.post('/add', admin, addPosition);
|
|
13
13
|
router.get('/list', getPositions);
|
|
14
|
-
router.put('/:id', updatePosition);
|
|
15
|
-
router.delete('/:id', deletePosition);
|
|
14
|
+
router.put('/:id', admin, updatePosition);
|
|
15
|
+
router.delete('/:id', admin, deletePosition);
|
|
16
16
|
|
|
17
17
|
module.exports = router;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const { getOnLeaveByDepartment } = require('../controllers/reportController');
|
|
3
|
-
const { protect } = require('../middleware/auth');
|
|
3
|
+
const { protect, admin } = require('../middleware/auth');
|
|
4
4
|
|
|
5
5
|
const router = express.Router();
|
|
6
6
|
|
|
7
|
-
router.get('/on-leave-by-department', protect, getOnLeaveByDepartment);
|
|
7
|
+
router.get('/on-leave-by-department', protect, admin, getOnLeaveByDepartment);
|
|
8
8
|
|
|
9
9
|
module.exports = router;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const cors = require('cors');
|
|
3
|
+
const session = require('express-session');
|
|
3
4
|
|
|
4
5
|
const connectDB = require('./config/db');
|
|
5
6
|
|
|
@@ -12,8 +13,29 @@ const protectedRoutes = require('./routes/protectedRoutes');
|
|
|
12
13
|
|
|
13
14
|
const app = express();
|
|
14
15
|
|
|
15
|
-
app.
|
|
16
|
+
app.set('trust proxy', 1);
|
|
17
|
+
|
|
18
|
+
const corsOptions = {
|
|
19
|
+
origin: 'http://localhost:5173',
|
|
20
|
+
credentials: true,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
app.use(cors(corsOptions));
|
|
24
|
+
app.options('*', cors(corsOptions));
|
|
16
25
|
app.use(express.json());
|
|
26
|
+
app.use(
|
|
27
|
+
session({
|
|
28
|
+
secret: 'change_this_to_a_long_random_secret',
|
|
29
|
+
resave: false,
|
|
30
|
+
saveUninitialized: false,
|
|
31
|
+
cookie: {
|
|
32
|
+
httpOnly: true,
|
|
33
|
+
secure: process.env.NODE_ENV === 'production',
|
|
34
|
+
sameSite: 'lax',
|
|
35
|
+
maxAge: 1000 * 60 * 60 * 24,
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
);
|
|
17
39
|
connectDB();
|
|
18
40
|
|
|
19
41
|
app.use('/api/auth', authRoutes);
|
package/templates/{index/frontend/src/App.jsx → HRMS (reba kuri iyi bro)/frontend/src/App.jsx }
RENAMED
|
@@ -8,6 +8,7 @@ import Department from './pages/Department';
|
|
|
8
8
|
import Employee from './pages/Employee';
|
|
9
9
|
import Position from './pages/Position';
|
|
10
10
|
import Reports from './pages/Reports';
|
|
11
|
+
import CreateUser from './pages/CreateUser';
|
|
11
12
|
|
|
12
13
|
function App() {
|
|
13
14
|
return (
|
|
@@ -22,6 +23,7 @@ function App() {
|
|
|
22
23
|
<Route path="employee" element={<Employee />} />
|
|
23
24
|
<Route path="position" element={<Position />} />
|
|
24
25
|
<Route path="reports" element={<Reports />} />
|
|
26
|
+
<Route path="create-user" element={<CreateUser />} />
|
|
25
27
|
</Route>
|
|
26
28
|
|
|
27
29
|
<Route path="/" element={<Navigate to="/dashboard" replace />} />
|
|
@@ -32,4 +34,4 @@ function App() {
|
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export default App;
|
|
35
|
-
|
|
37
|
+
|
|
@@ -21,8 +21,8 @@ function DashboardLayout() {
|
|
|
21
21
|
setUser(JSON.parse(storedUser));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
axios.get('
|
|
25
|
-
|
|
24
|
+
axios.get('/api/auth/me', {
|
|
25
|
+
withCredentials: true,
|
|
26
26
|
})
|
|
27
27
|
.then((response) => {
|
|
28
28
|
setUser(response.data.user);
|
|
@@ -35,12 +35,22 @@ function DashboardLayout() {
|
|
|
35
35
|
});
|
|
36
36
|
}, []);
|
|
37
37
|
|
|
38
|
-
const handleLogout = () => {
|
|
39
|
-
|
|
38
|
+
const handleLogout = async () => {
|
|
39
|
+
try {
|
|
40
|
+
await axios.post('/api/auth/logout', null, {
|
|
41
|
+
withCredentials: true,
|
|
42
|
+
});
|
|
43
|
+
} catch (err) {
|
|
44
|
+
console.error('Logout failed', err.response?.data || err.message);
|
|
45
|
+
}
|
|
40
46
|
localStorage.removeItem('user');
|
|
41
47
|
navigate('/login');
|
|
42
48
|
};
|
|
43
49
|
|
|
50
|
+
const visibleNav = user?.role === 'employee'
|
|
51
|
+
? navItems.filter((i) => ['/dashboard/employee', '/dashboard/department', '/dashboard/position'].includes(i.to))
|
|
52
|
+
: navItems;
|
|
53
|
+
|
|
44
54
|
return (
|
|
45
55
|
<div className="min-h-screen bg-gray-100">
|
|
46
56
|
<aside className="fixed inset-y-0 left-0 flex w-56 flex-col bg-teal-900 text-white">
|
|
@@ -50,7 +60,7 @@ function DashboardLayout() {
|
|
|
50
60
|
</div>
|
|
51
61
|
|
|
52
62
|
<nav className="flex-1 space-y-1 overflow-y-auto px-2 py-4">
|
|
53
|
-
{
|
|
63
|
+
{visibleNav.map((item) => (
|
|
54
64
|
<NavLink
|
|
55
65
|
key={item.to}
|
|
56
66
|
to={item.to}
|
|
@@ -60,6 +70,14 @@ function DashboardLayout() {
|
|
|
60
70
|
{item.label}
|
|
61
71
|
</NavLink>
|
|
62
72
|
))}
|
|
73
|
+
{user?.role === 'admin' && (
|
|
74
|
+
<NavLink
|
|
75
|
+
to="/dashboard/create-user"
|
|
76
|
+
className={({ isActive }) => `nav-link ${isActive ? 'nav-link-active' : ''}`}
|
|
77
|
+
>
|
|
78
|
+
Create User
|
|
79
|
+
</NavLink>
|
|
80
|
+
)}
|
|
63
81
|
</nav>
|
|
64
82
|
|
|
65
83
|
<div className="border-t border-teal-800 px-4 py-4">
|
|
@@ -87,4 +105,5 @@ function DashboardLayout() {
|
|
|
87
105
|
}
|
|
88
106
|
|
|
89
107
|
export default DashboardLayout;
|
|
108
|
+
|
|
90
109
|
|
|
@@ -2,8 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { Navigate } from 'react-router-dom';
|
|
3
3
|
|
|
4
4
|
export default function ProtectedRoute({ children }) {
|
|
5
|
-
const
|
|
6
|
-
if (!
|
|
5
|
+
const user = localStorage.getItem('user');
|
|
6
|
+
if (!user) return <Navigate to="/login" replace />;
|
|
7
7
|
return children;
|
|
8
8
|
}
|
|
9
9
|
|
package/templates/{index/frontend/src/main.jsx → HRMS (reba kuri iyi bro)/frontend/src/main.jsx }
RENAMED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { StrictMode } from 'react'
|
|
2
2
|
import { createRoot } from 'react-dom/client'
|
|
3
|
+
import axios from 'axios'
|
|
3
4
|
import './index.css'
|
|
4
5
|
import App from './App.jsx'
|
|
5
6
|
|
|
7
|
+
axios.defaults.withCredentials = true
|
|
8
|
+
|
|
6
9
|
createRoot(document.getElementById('root')).render(
|
|
7
10
|
<StrictMode>
|
|
8
11
|
<App />
|
|
9
12
|
</StrictMode>,
|
|
10
13
|
)
|
|
11
|
-
|
|
14
|
+
|