create-jinmankn-app 1.0.11 → 1.0.13
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/EPMS(Employee Payroll Managment System)/backend/routes/protectedRoutes.js +10 -0
- package/templates/EPMS(Employee Payroll Managment System)/backend/server.js +2 -0
- package/templates/EPMS(Employee Payroll Managment System)/frontend/src/App.jsx +2 -1
- package/templates/EPMS(Employee Payroll Managment System)/frontend/src/components/ProtectedRoute.jsx +8 -0
- package/templates/EPMS(Employee Payroll Managment System)/package-lock.json +13 -0
- package/templates/Faisal Hospital Managment System (FHMS) mysql/backend/routes/secureRoutes.js +14 -0
- package/templates/Faisal Hospital Managment System (FHMS) mysql/backend/server.js +2 -0
- package/templates/Faisal Hospital Managment System (FHMS) mysql/frontend/src/components/ProtectedRoute.jsx +2 -3
- package/templates/Faisal Hospital Managment System (FHMS) mysql/frontend/src/utils/auth.js +13 -0
- package/templates/LMS(Library Managment System)/backend/controllers/authController.js +32 -0
- package/templates/LMS(Library Managment System)/backend/routes/authRoutes.js +2 -1
- package/templates/LMS(Library Managment System)/backend/routes/protectedRoutes.js +19 -0
- package/templates/LMS(Library Managment System)/backend/server.js +2 -0
- package/templates/LMS(Library Managment System)/frontend/src/App.jsx +74 -15
- package/templates/LMS(Library Managment System)/frontend/src/ProtectedRoute.jsx +13 -0
- package/templates/LMS(Library Managment System)/frontend/src/pages/Login.jsx +4 -1
- package/templates/LMS(Library Managment System)/frontend/src/pages/Register.jsx +87 -0
- package/templates/SCMS(Supply Chain Managment System)/backend/routes/protectedRoutes.js +10 -0
- package/templates/SCMS(Supply Chain Managment System)/backend/server.js +2 -0
- package/templates/SCMS(Supply Chain Managment System)/frontend/src/App.jsx +2 -1
- package/templates/SCMS(Supply Chain Managment System)/frontend/src/components/ProtectedRoute.jsx +30 -0
- package/templates/SFM(School Fee Managment)/backend/middleware/protectedRoutes.js +10 -0
- package/templates/SFM(School Fee Managment)/frontend/src/App.jsx +7 -5
- package/templates/SFM(School Fee Managment)/frontend/src/components/ProtectedRoute.jsx +13 -0
- package/templates/SIMS(Stock Inventory Managment System)/backend/controllers/protectedController.js +14 -0
- package/templates/SIMS(Stock Inventory Managment System)/backend/routes/protectedRoutes.js +10 -0
- package/templates/SIMS(Stock Inventory Managment System)/backend/server.js +2 -1
- package/templates/SIMS(Stock Inventory Managment System)/frontend/src/App.jsx +57 -7
- package/templates/SIMS(Stock Inventory Managment System)/frontend/src/components/ProtectedRoute.jsx +8 -0
- package/templates/SMS(Stock Managment System)/backend-project/routes/protectedRoutes.js +18 -0
- package/templates/SMS(Stock Managment System)/backend-project/server.js +3 -1
- package/templates/SMS(Stock Managment System)/frontend-project/src/App.jsx +36 -7
- package/templates/SMS(Stock Managment System)/frontend-project/src/components/AppLayout.jsx +1 -1
- package/templates/SMS(Stock Managment System)/frontend-project/src/components/ProtectedRoute.jsx +13 -0
- package/templates/SMS(Stock Managment System)/frontend-project/src/pages/Login.jsx +1 -1
- package/templates/SMS(Stock Managment System)/frontend-project/src/pages/Product.jsx +211 -78
- package/templates/SMS(Stock Managment System)/frontend-project/src/pages/Profile.jsx +1 -1
- package/templates/SMS(Stock Managment System)/frontend-project/src/pages/Register.jsx +1 -1
- package/templates/SMS(Stock Managment System)/frontend-project/src/pages/Reports.jsx +1 -1
- package/templates/SMS(Stock Managment System)/frontend-project/src/pages/Sales.jsx +6 -6
- package/templates/SMS(Stock Managment System)/frontend-project/src/pages/Warehouse.jsx +150 -44
- package/templates/SMS(Stock Managment System)/package-lock.json +13 -0
- package/templates/SRMS(Sales Record Management System)/backend/routes/protectedRoutes.js +13 -0
- package/templates/SRMS(Sales Record Management System)/backend/server.js +2 -0
- package/templates/SRMS(Sales Record Management System)/frontend/src/App.jsx +2 -1
- package/templates/SRMS(Sales Record Management System)/frontend/src/components/ProtectedRoute.jsx +22 -0
- package/templates/index/README.md +34 -0
- package/templates/index/backend/config/db.js +12 -0
- package/templates/index/backend/controllers/authController.js +88 -0
- package/templates/index/backend/controllers/departmentController.js +74 -0
- package/templates/index/backend/controllers/employeeController.js +204 -0
- package/templates/index/backend/controllers/positionController.js +78 -0
- package/templates/index/backend/controllers/reportController.js +45 -0
- package/templates/index/backend/middleware/auth.js +27 -0
- package/templates/index/backend/models/Department.js +15 -0
- package/templates/index/backend/models/Employee.js +73 -0
- package/templates/index/backend/models/Position.js +20 -0
- package/templates/index/backend/models/User.js +32 -0
- package/templates/index/backend/package-lock.json +2190 -0
- package/templates/index/backend/package.json +22 -0
- package/templates/index/backend/routes/authRoutes.js +11 -0
- package/templates/index/backend/routes/departmentRoutes.js +17 -0
- package/templates/index/backend/routes/employeeRoutes.js +19 -0
- package/templates/index/backend/routes/positionRoutes.js +17 -0
- package/templates/index/backend/routes/protectedRoutes.js +10 -0
- package/templates/index/backend/routes/reportRoutes.js +9 -0
- package/templates/index/backend/server.js +30 -0
- package/templates/index/frontend/README.md +16 -0
- package/templates/index/frontend/eslint.config.js +21 -0
- package/templates/index/frontend/index.html +13 -0
- package/templates/index/frontend/package-lock.json +3095 -0
- package/templates/index/frontend/package.json +31 -0
- package/templates/index/frontend/public/favicon.svg +1 -0
- package/templates/index/frontend/src/App.css +0 -0
- package/templates/index/frontend/src/App.jsx +35 -0
- package/templates/index/frontend/src/assets/hero.png +0 -0
- package/templates/index/frontend/src/components/DashboardLayout.jsx +90 -0
- package/templates/index/frontend/src/components/ProtectedRoute.jsx +9 -0
- package/templates/index/frontend/src/index.css +59 -0
- package/templates/index/frontend/src/main.jsx +11 -0
- package/templates/index/frontend/src/pages/DashboardHome.jsx +58 -0
- package/templates/index/frontend/src/pages/Department.jsx +150 -0
- package/templates/index/frontend/src/pages/Employee.jsx +366 -0
- package/templates/index/frontend/src/pages/Login.jsx +81 -0
- package/templates/index/frontend/src/pages/Position.jsx +169 -0
- package/templates/index/frontend/src/pages/Register.jsx +102 -0
- package/templates/index/frontend/src/pages/Reports.jsx +94 -0
- package/templates/index/frontend/vite.config.js +7 -0
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
2
|
import axios from 'axios';
|
|
3
3
|
import AppLayout from '../components/AppLayout';
|
|
4
4
|
|
|
5
|
+
const API_BASE = 'http://localhost:1000/api/warehouse';
|
|
6
|
+
|
|
5
7
|
function Warehouse() {
|
|
8
|
+
const [warehouses, setWarehouses] = useState([]);
|
|
6
9
|
const [warehouseCode, setWarehouseCode] = useState('');
|
|
7
10
|
const [warehouseName, setWarehouseName] = useState('');
|
|
8
11
|
const [warehouseLocation, setWarehouseLocation] = useState('');
|
|
9
12
|
const [message, setMessage] = useState('');
|
|
13
|
+
const [error, setError] = useState('');
|
|
14
|
+
const [editingId, setEditingId] = useState(null);
|
|
10
15
|
|
|
11
16
|
const headers = {
|
|
12
17
|
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
|
@@ -16,64 +21,165 @@ function Warehouse() {
|
|
|
16
21
|
setWarehouseCode('');
|
|
17
22
|
setWarehouseName('');
|
|
18
23
|
setWarehouseLocation('');
|
|
24
|
+
setEditingId(null);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const fetchWarehouses = async () => {
|
|
28
|
+
try {
|
|
29
|
+
const response = await axios.get(`${API_BASE}/getwarehouse`, { headers });
|
|
30
|
+
setWarehouses(response.data);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
setError('Failed to load warehouses');
|
|
33
|
+
console.error(err);
|
|
34
|
+
}
|
|
19
35
|
};
|
|
20
36
|
|
|
21
37
|
const handleSubmit = async (e) => {
|
|
22
38
|
e.preventDefault();
|
|
23
39
|
setMessage('');
|
|
40
|
+
setError('');
|
|
24
41
|
|
|
25
42
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
if (editingId) {
|
|
44
|
+
await axios.put(
|
|
45
|
+
`${API_BASE}/updatewarehouse/${editingId}`,
|
|
46
|
+
{ warehouseCode, warehouseName, warehouseLocation },
|
|
47
|
+
{ headers }
|
|
48
|
+
);
|
|
49
|
+
setMessage('Warehouse updated successfully');
|
|
50
|
+
} else {
|
|
51
|
+
await axios.post(
|
|
52
|
+
`${API_BASE}/addwarehouse`,
|
|
53
|
+
{ warehouseCode, warehouseName, warehouseLocation },
|
|
54
|
+
{ headers }
|
|
55
|
+
);
|
|
56
|
+
setMessage('Warehouse added successfully');
|
|
57
|
+
}
|
|
32
58
|
clearForm();
|
|
59
|
+
fetchWarehouses();
|
|
33
60
|
} catch (err) {
|
|
34
|
-
|
|
35
|
-
console.
|
|
61
|
+
setError(err.response?.data?.message || 'Failed to save warehouse');
|
|
62
|
+
console.error(err);
|
|
36
63
|
}
|
|
37
64
|
};
|
|
38
65
|
|
|
66
|
+
const handleEdit = (warehouse) => {
|
|
67
|
+
setEditingId(warehouse._id);
|
|
68
|
+
setWarehouseCode(warehouse.warehouseCode || '');
|
|
69
|
+
setWarehouseName(warehouse.warehouseName || '');
|
|
70
|
+
setWarehouseLocation(warehouse.warehouseLocation || '');
|
|
71
|
+
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const handleDelete = async (id) => {
|
|
75
|
+
try {
|
|
76
|
+
await axios.delete(`${API_BASE}/deletewarehouse/${id}`, { headers });
|
|
77
|
+
setMessage('Warehouse deleted successfully');
|
|
78
|
+
fetchWarehouses();
|
|
79
|
+
} catch (err) {
|
|
80
|
+
setError('Failed to delete warehouse');
|
|
81
|
+
console.error(err);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
fetchWarehouses();
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
39
89
|
return (
|
|
40
90
|
<AppLayout title="Warehouse management" subtitle="Locations">
|
|
41
|
-
<div className="mx-auto max-w-
|
|
42
|
-
|
|
43
|
-
<p className=
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
91
|
+
<div className="mx-auto max-w-6xl space-y-6">
|
|
92
|
+
<div className="card space-y-4 p-5">
|
|
93
|
+
{message && <p className="alert-success">{message}</p>}
|
|
94
|
+
{error && <p className="alert-error">{error}</p>}
|
|
95
|
+
|
|
96
|
+
<form onSubmit={handleSubmit} className="space-y-3">
|
|
97
|
+
<h2 className="text-lg font-semibold text-slate-800">
|
|
98
|
+
{editingId ? 'Edit warehouse' : 'Add new warehouse'}
|
|
99
|
+
</h2>
|
|
100
|
+
<div className="grid gap-4 sm:grid-cols-3">
|
|
101
|
+
<input
|
|
102
|
+
type="text"
|
|
103
|
+
placeholder="Warehouse code"
|
|
104
|
+
value={warehouseCode}
|
|
105
|
+
onChange={(e) => setWarehouseCode(e.target.value)}
|
|
106
|
+
className="input-field"
|
|
107
|
+
required
|
|
108
|
+
/>
|
|
109
|
+
<input
|
|
110
|
+
type="text"
|
|
111
|
+
placeholder="Warehouse name"
|
|
112
|
+
value={warehouseName}
|
|
113
|
+
onChange={(e) => setWarehouseName(e.target.value)}
|
|
114
|
+
className="input-field"
|
|
115
|
+
required
|
|
116
|
+
/>
|
|
117
|
+
<input
|
|
118
|
+
type="text"
|
|
119
|
+
placeholder="Warehouse location"
|
|
120
|
+
value={warehouseLocation}
|
|
121
|
+
onChange={(e) => setWarehouseLocation(e.target.value)}
|
|
122
|
+
className="input-field"
|
|
123
|
+
required
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
126
|
+
<div className="flex flex-wrap gap-3">
|
|
127
|
+
<button type="submit" className="btn-primary">
|
|
128
|
+
{editingId ? 'Save changes' : 'Add warehouse'}
|
|
129
|
+
</button>
|
|
130
|
+
{editingId && (
|
|
131
|
+
<button type="button" onClick={clearForm} className="btn-secondary">
|
|
132
|
+
Cancel
|
|
133
|
+
</button>
|
|
134
|
+
)}
|
|
135
|
+
</div>
|
|
136
|
+
</form>
|
|
137
|
+
</div>
|
|
47
138
|
|
|
48
|
-
<
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
139
|
+
<div className="card p-5">
|
|
140
|
+
<h2 className="text-lg font-semibold text-slate-800">Warehouses</h2>
|
|
141
|
+
{warehouses.length === 0 ? (
|
|
142
|
+
<p className="mt-4 text-sm text-slate-500">No warehouses available.</p>
|
|
143
|
+
) : (
|
|
144
|
+
<div className="mt-4 overflow-x-auto">
|
|
145
|
+
<table className="min-w-full divide-y divide-slate-200 text-sm">
|
|
146
|
+
<thead>
|
|
147
|
+
<tr className="bg-slate-50 text-left text-slate-600">
|
|
148
|
+
<th className="px-4 py-3">Code</th>
|
|
149
|
+
<th className="px-4 py-3">Name</th>
|
|
150
|
+
<th className="px-4 py-3">Location</th>
|
|
151
|
+
<th className="px-4 py-3">Actions</th>
|
|
152
|
+
</tr>
|
|
153
|
+
</thead>
|
|
154
|
+
<tbody className="divide-y divide-slate-200">
|
|
155
|
+
{warehouses.map((warehouse) => (
|
|
156
|
+
<tr key={warehouse._id} className="hover:bg-slate-50">
|
|
157
|
+
<td className="px-4 py-3">{warehouse.warehouseCode}</td>
|
|
158
|
+
<td className="px-4 py-3">{warehouse.warehouseName}</td>
|
|
159
|
+
<td className="px-4 py-3">{warehouse.warehouseLocation}</td>
|
|
160
|
+
<td className="px-4 py-3 space-x-2">
|
|
161
|
+
<button
|
|
162
|
+
type="button"
|
|
163
|
+
onClick={() => handleEdit(warehouse)}
|
|
164
|
+
className="btn-secondary"
|
|
165
|
+
>
|
|
166
|
+
Edit
|
|
167
|
+
</button>
|
|
168
|
+
<button
|
|
169
|
+
type="button"
|
|
170
|
+
onClick={() => handleDelete(warehouse._id)}
|
|
171
|
+
className="btn-danger"
|
|
172
|
+
>
|
|
173
|
+
Delete
|
|
174
|
+
</button>
|
|
175
|
+
</td>
|
|
176
|
+
</tr>
|
|
177
|
+
))}
|
|
178
|
+
</tbody>
|
|
179
|
+
</table>
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
182
|
+
</div>
|
|
77
183
|
</div>
|
|
78
184
|
</AppLayout>
|
|
79
185
|
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const { protect } = require('../middleware/auth');
|
|
3
|
+
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.get('/secret', protect, (req, res) => {
|
|
7
|
+
res.json({
|
|
8
|
+
message: 'You have accessed a protected backend route.',
|
|
9
|
+
user: req.user,
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
module.exports = router;
|
|
@@ -8,6 +8,7 @@ const salesRoutes = require('./routes/salesRoutes');
|
|
|
8
8
|
const productRoutes = require('./routes/productRoutes');
|
|
9
9
|
const customerRoutes = require('./routes/customerRoutes');
|
|
10
10
|
const reportsRoutes = require('./routes/reportsRoutes');
|
|
11
|
+
const protectedRoutes = require('./routes/protectedRoutes');
|
|
11
12
|
|
|
12
13
|
const app = express();
|
|
13
14
|
|
|
@@ -20,6 +21,7 @@ app.use('/api/customer', customerRoutes);
|
|
|
20
21
|
app.use('/api/reports', reportsRoutes);
|
|
21
22
|
app.use('/api/auth', authRoutes);
|
|
22
23
|
app.use('/api/sales', salesRoutes);
|
|
24
|
+
app.use('/api/protected', protectedRoutes);
|
|
23
25
|
|
|
24
26
|
const PORT = 5001;
|
|
25
27
|
app.listen(PORT, () => {
|
|
@@ -7,6 +7,7 @@ import Product from './pages/Product';
|
|
|
7
7
|
import Sales from './pages/Sales';
|
|
8
8
|
import Customer from './pages/Customer';
|
|
9
9
|
import Reports from './pages/Reports';
|
|
10
|
+
import ProtectedRoute from './components/ProtectedRoute';
|
|
10
11
|
|
|
11
12
|
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
|
12
13
|
|
|
@@ -16,7 +17,7 @@ function App() {
|
|
|
16
17
|
<Routes>
|
|
17
18
|
<Route path="/login" element={<Login />} />
|
|
18
19
|
<Route path="/register" element={<Register />} />
|
|
19
|
-
<Route path="/" element={<Layout
|
|
20
|
+
<Route path="/" element={<ProtectedRoute><Layout /></ProtectedRoute>}>
|
|
20
21
|
<Route index element={<Dashboard />} />
|
|
21
22
|
<Route path="dashboard" element={<Dashboard />} />
|
|
22
23
|
<Route path="dashboard/customers" element={<Customer />} />
|
package/templates/SRMS(Sales Record Management System)/frontend/src/components/ProtectedRoute.jsx
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
function ProtectedRoute({ children }) {
|
|
5
|
+
const navigate = useNavigate();
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const token = localStorage.getItem('token');
|
|
9
|
+
if (!token) {
|
|
10
|
+
navigate('/login', { replace: true });
|
|
11
|
+
}
|
|
12
|
+
}, [navigate]);
|
|
13
|
+
|
|
14
|
+
const token = localStorage.getItem('token');
|
|
15
|
+
if (!token) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return children;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default ProtectedRoute;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Problems the new system is fixing
|
|
2
|
+
|
|
3
|
+
Data duplication
|
|
4
|
+
Slow manual processes
|
|
5
|
+
Poor record tracking
|
|
6
|
+
Data inconsistency
|
|
7
|
+
Delayed reporting
|
|
8
|
+
Difficulty retrieving information
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
What the new system will do
|
|
12
|
+
|
|
13
|
+
Manage employee records
|
|
14
|
+
Record purchases
|
|
15
|
+
Record sales
|
|
16
|
+
Store data centrally
|
|
17
|
+
Retrieve information quickly
|
|
18
|
+
Generate accurate reports
|
|
19
|
+
Support management decision-making
|
|
20
|
+
Simple summary
|
|
21
|
+
|
|
22
|
+
The web-based system will replace the manual system by centralizing employee, purchase, and sales records, reducing duplication, improving data consistency, speeding up operations, and producing accurate reports.
|
|
23
|
+
|
|
24
|
+
//middleware
|
|
25
|
+
Middleware in the MERN stack is a function that runs between a client's request and the server's response.
|
|
26
|
+
|
|
27
|
+
It is used to:
|
|
28
|
+
|
|
29
|
+
Check authentication (JWT tokens)
|
|
30
|
+
Validate data
|
|
31
|
+
Handle errors
|
|
32
|
+
Log requests
|
|
33
|
+
Modify request/response objects
|
|
34
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const connectDB = async () => {
|
|
4
|
+
try {
|
|
5
|
+
await mongoose.connect('mongodb://localhost:27017/HRMS');
|
|
6
|
+
console.log('MongoDB connected');
|
|
7
|
+
} catch (error) {
|
|
8
|
+
console.error('MongoDB connection error:', error);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports = connectDB;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const bcrypt = require('bcrypt');
|
|
2
|
+
const jwt = require('jsonwebtoken');
|
|
3
|
+
const User = require('../models/User');
|
|
4
|
+
const JWT_SECRET = 'change_this_to_a_long_random_secret';
|
|
5
|
+
|
|
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
|
+
function formatUser(user) {
|
|
11
|
+
return {
|
|
12
|
+
id: user._id,
|
|
13
|
+
name: user.name,
|
|
14
|
+
email: user.email,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.register = async (req, res) => {
|
|
19
|
+
try {
|
|
20
|
+
const { name, email, password } = req.body;
|
|
21
|
+
|
|
22
|
+
if (!name || !email || !password) {
|
|
23
|
+
return res.status(400).json({ message: 'Name, email, and password are required' });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (password.length < 6) {
|
|
27
|
+
return res.status(400).json({ message: 'Password must be at least 6 characters' });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const existing = await User.findOne({ email: email.trim().toLowerCase() });
|
|
31
|
+
if (existing) {
|
|
32
|
+
return res.status(409).json({ message: 'Email already registered' });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const hashedPassword = await bcrypt.hash(password, 10);
|
|
36
|
+
const user = await User.create({
|
|
37
|
+
name: name.trim(),
|
|
38
|
+
email: email.trim().toLowerCase(),
|
|
39
|
+
password: hashedPassword,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const token = createToken(user._id);
|
|
43
|
+
|
|
44
|
+
res.status(201).json({
|
|
45
|
+
token,
|
|
46
|
+
user: formatUser(user),
|
|
47
|
+
});
|
|
48
|
+
} catch (err) {
|
|
49
|
+
res.status(500).json({ message: err.message });
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
exports.login = async (req, res) => {
|
|
54
|
+
try {
|
|
55
|
+
const { email, password } = req.body;
|
|
56
|
+
|
|
57
|
+
if (!email || !password) {
|
|
58
|
+
return res.status(400).json({ message: 'Email and password are required' });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const user = await User.findOne({ email: email.trim().toLowerCase() });
|
|
62
|
+
if (!user) {
|
|
63
|
+
return res.status(401).json({ message: 'Invalid email or password' });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const match = await bcrypt.compare(password, user.password);
|
|
67
|
+
if (!match) {
|
|
68
|
+
return res.status(401).json({ message: 'Invalid email or password' });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const token = createToken(user._id);
|
|
72
|
+
|
|
73
|
+
res.json({
|
|
74
|
+
token,
|
|
75
|
+
user: formatUser(user),
|
|
76
|
+
});
|
|
77
|
+
} catch (err) {
|
|
78
|
+
res.status(500).json({ message: err.message });
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
exports.getMe = async (req, res) => {
|
|
83
|
+
try {
|
|
84
|
+
res.json({ user: formatUser(req.user) });
|
|
85
|
+
} catch (err) {
|
|
86
|
+
res.status(500).json({ message: err.message });
|
|
87
|
+
}
|
|
88
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const Department = require('../models/Department');
|
|
2
|
+
|
|
3
|
+
exports.addDepartment = async (req, res) => {
|
|
4
|
+
try {
|
|
5
|
+
const { departmentName } = req.body;
|
|
6
|
+
|
|
7
|
+
if (!departmentName) {
|
|
8
|
+
return res.status(400).json({ message: 'Department name is required' });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const existing = await Department.findOne({ departmentName: departmentName.trim() });
|
|
12
|
+
if (existing) {
|
|
13
|
+
return res.status(409).json({ message: 'Department already exists' });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const dept = await Department.create({ departmentName: departmentName.trim() });
|
|
17
|
+
res.status(201).json(dept);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
res.status(500).json({ message: err.message });
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
exports.getDepartments = async (req, res) => {
|
|
24
|
+
try {
|
|
25
|
+
const departments = await Department.find();
|
|
26
|
+
res.json(departments);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
res.status(500).json({ message: err.message });
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
exports.updateDepartment = async (req, res) => {
|
|
33
|
+
try {
|
|
34
|
+
const { departmentName } = req.body;
|
|
35
|
+
|
|
36
|
+
if (!departmentName) {
|
|
37
|
+
return res.status(400).json({ message: 'Department name is required' });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const department = await Department.findById(req.params.id);
|
|
41
|
+
if (!department) {
|
|
42
|
+
return res.status(404).json({ message: 'Department not found' });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const existing = await Department.findOne({
|
|
46
|
+
departmentName: departmentName.trim(),
|
|
47
|
+
_id: { $ne: req.params.id },
|
|
48
|
+
});
|
|
49
|
+
if (existing) {
|
|
50
|
+
return res.status(409).json({ message: 'Department already exists' });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
department.departmentName = departmentName.trim();
|
|
54
|
+
await department.save();
|
|
55
|
+
|
|
56
|
+
res.json(department);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
res.status(500).json({ message: err.message });
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
exports.deleteDepartment = async (req, res) => {
|
|
63
|
+
try {
|
|
64
|
+
const department = await Department.findById(req.params.id);
|
|
65
|
+
if (!department) {
|
|
66
|
+
return res.status(404).json({ message: 'Department not found' });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await Department.findByIdAndDelete(req.params.id);
|
|
70
|
+
res.json({ message: 'Department deleted successfully' });
|
|
71
|
+
} catch (err) {
|
|
72
|
+
res.status(500).json({ message: err.message });
|
|
73
|
+
}
|
|
74
|
+
};
|