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.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/templates/HRMS (reba kuri iyi bro)/README.md +1 -0
  3. package/templates/{index/backend/controllers/authController.js → HRMS (reba kuri iyi bro)/backend/controllers/authController.js } +60 -10
  4. package/templates/HRMS (reba kuri iyi bro)/backend/cookiejar.txt +4 -0
  5. package/templates/HRMS (reba kuri iyi bro)/backend/middleware/auth.js +28 -0
  6. package/templates/{index/backend/models/User.js → HRMS (reba kuri iyi bro)/backend/models/User.js } +5 -0
  7. package/templates/{index/backend/package-lock.json → HRMS (reba kuri iyi bro)/backend/package-lock.json } +54 -13
  8. package/templates/{index/backend/package.json → HRMS (reba kuri iyi bro)/backend/package.json } +1 -0
  9. package/templates/HRMS (reba kuri iyi bro)/backend/routes/authRoutes.js +13 -0
  10. package/templates/{index/backend/routes/departmentRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/departmentRoutes.js } +4 -4
  11. package/templates/{index/backend/routes/employeeRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/employeeRoutes.js } +4 -4
  12. package/templates/{index/backend/routes/positionRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/positionRoutes.js } +4 -4
  13. package/templates/{index/backend/routes/reportRoutes.js → HRMS (reba kuri iyi bro)/backend/routes/reportRoutes.js } +2 -2
  14. package/templates/{index/backend/server.js → HRMS (reba kuri iyi bro)/backend/server.js } +23 -1
  15. package/templates/{index/frontend/src/App.jsx → HRMS (reba kuri iyi bro)/frontend/src/App.jsx } +3 -1
  16. package/templates/{index/frontend/src/components/DashboardLayout.jsx → HRMS (reba kuri iyi bro)/frontend/src/components/DashboardLayout.jsx } +24 -5
  17. package/templates/{index/frontend/src/components/ProtectedRoute.jsx → HRMS (reba kuri iyi bro)/frontend/src/components/ProtectedRoute.jsx } +2 -2
  18. package/templates/{index/frontend/src/main.jsx → HRMS (reba kuri iyi bro)/frontend/src/main.jsx } +4 -1
  19. package/templates/HRMS (reba kuri iyi bro)/frontend/src/pages/CreateUser.jsx +150 -0
  20. package/templates/{index/frontend/src/pages/DashboardHome.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/DashboardHome.jsx } +4 -4
  21. package/templates/{index/frontend/src/pages/Department.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Department.jsx } +47 -36
  22. package/templates/{index/frontend/src/pages/Employee.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Employee.jsx } +27 -16
  23. package/templates/{index/frontend/src/pages/Login.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Login.jsx } +7 -3
  24. package/templates/{index/frontend/src/pages/Position.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Position.jsx } +27 -16
  25. package/templates/{index/frontend/src/pages/Register.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Register.jsx } +10 -6
  26. package/templates/{index/frontend/src/pages/Reports.jsx → HRMS (reba kuri iyi bro)/frontend/src/pages/Reports.jsx } +2 -3
  27. package/templates/HRMS (reba kuri iyi bro)/frontend/vite.config.js +18 -0
  28. package/templates/index/README.md +0 -34
  29. package/templates/index/backend/middleware/auth.js +0 -27
  30. package/templates/index/backend/routes/authRoutes.js +0 -11
  31. package/templates/index/frontend/vite.config.js +0 -7
  32. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/config/db.js +0 -0
  33. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/departmentController.js +0 -0
  34. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/employeeController.js +0 -0
  35. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/positionController.js +0 -0
  36. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/controllers/reportController.js +0 -0
  37. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/models/Department.js +0 -0
  38. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/models/Employee.js +0 -0
  39. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/models/Position.js +0 -0
  40. /package/templates/{index → HRMS (reba kuri iyi bro)}/backend/routes/protectedRoutes.js +0 -0
  41. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/README.md +0 -0
  42. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/eslint.config.js +0 -0
  43. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/index.html +0 -0
  44. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/package-lock.json +0 -0
  45. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/package.json +0 -0
  46. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/public/favicon.svg +0 -0
  47. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/src/App.css +0 -0
  48. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/src/assets/hero.png +0 -0
  49. /package/templates/{index → HRMS (reba kuri iyi bro)}/frontend/src/index.css +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-jinmankn-app",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-jinmankn-app": "./bin/index.js"
@@ -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 JWT_SECRET = 'change_this_to_a_long_random_secret';
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 token = createToken(user._id);
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
- const token = createToken(user._id);
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,4 @@
1
+ # Netscape HTTP Cookie File
2
+ # https://curl.se/docs/http-cookies.html
3
+ # This file was generated by libcurl! Edit at your own risk.
4
+
@@ -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
+ };
@@ -19,6 +19,11 @@ const userSchema = new mongoose.Schema(
19
19
  required: true,
20
20
  minlength: 6,
21
21
  },
22
+ role: {
23
+ type: String,
24
+ enum: ['admin', 'user', 'employee'],
25
+ default: 'user',
26
+ },
22
27
  employee: {
23
28
  type: mongoose.Schema.Types.ObjectId,
24
29
  ref: 'Employee',
@@ -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",
@@ -13,6 +13,7 @@
13
13
  "bcrypt": "^5.1.1",
14
14
  "cors": "^2.8.5",
15
15
  "express": "^4.21.2",
16
+ "express-session": "^1.19.0",
16
17
  "jsonwebtoken": "^9.0.2",
17
18
  "mongoose": "^8.9.3"
18
19
  },
@@ -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.use(cors());
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);
@@ -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('http://localhost:5006/api/auth/me', {
25
- headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
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
- localStorage.removeItem('token');
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
- {navItems.map((item) => (
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 token = localStorage.getItem('token');
6
- if (!token) return <Navigate to="/login" replace />;
5
+ const user = localStorage.getItem('user');
6
+ if (!user) return <Navigate to="/login" replace />;
7
7
  return children;
8
8
  }
9
9
 
@@ -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
+