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
|
@@ -5,6 +5,7 @@ import Profile from './pages/Profile';
|
|
|
5
5
|
import Product from './pages/Product';
|
|
6
6
|
import Stock from './pages/Stock';
|
|
7
7
|
import Reports from './pages/Reports';
|
|
8
|
+
import ProtectedRoute from './components/ProtectedRoute';
|
|
8
9
|
|
|
9
10
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
10
11
|
import Supplier from './pages/Supplier';
|
|
@@ -17,15 +18,64 @@ function App() {
|
|
|
17
18
|
<div>
|
|
18
19
|
<BrowserRouter>
|
|
19
20
|
<Routes>
|
|
20
|
-
<Route
|
|
21
|
-
|
|
21
|
+
<Route
|
|
22
|
+
path='/'
|
|
23
|
+
element={
|
|
24
|
+
<ProtectedRoute>
|
|
25
|
+
<Dashboard />
|
|
26
|
+
</ProtectedRoute>
|
|
27
|
+
}
|
|
28
|
+
/>
|
|
29
|
+
<Route
|
|
30
|
+
path='/dashboard'
|
|
31
|
+
element={
|
|
32
|
+
<ProtectedRoute>
|
|
33
|
+
<Dashboard />
|
|
34
|
+
</ProtectedRoute>
|
|
35
|
+
}
|
|
36
|
+
/>
|
|
22
37
|
<Route path='/login' element={<Login />} />
|
|
23
38
|
<Route path='/register' element={<Register />} />
|
|
24
|
-
<Route
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
39
|
+
<Route
|
|
40
|
+
path='/dashboard/spareparts'
|
|
41
|
+
element={
|
|
42
|
+
<ProtectedRoute>
|
|
43
|
+
<Product />
|
|
44
|
+
</ProtectedRoute>
|
|
45
|
+
}
|
|
46
|
+
/>
|
|
47
|
+
<Route
|
|
48
|
+
path='/dashboard/profile'
|
|
49
|
+
element={
|
|
50
|
+
<ProtectedRoute>
|
|
51
|
+
<Profile />
|
|
52
|
+
</ProtectedRoute>
|
|
53
|
+
}
|
|
54
|
+
/>
|
|
55
|
+
<Route
|
|
56
|
+
path='/dashboard/stock'
|
|
57
|
+
element={
|
|
58
|
+
<ProtectedRoute>
|
|
59
|
+
<Stock />
|
|
60
|
+
</ProtectedRoute>
|
|
61
|
+
}
|
|
62
|
+
/>
|
|
63
|
+
<Route
|
|
64
|
+
path='/dashboard/suppliers'
|
|
65
|
+
element={
|
|
66
|
+
<ProtectedRoute>
|
|
67
|
+
<Supplier />
|
|
68
|
+
</ProtectedRoute>
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
71
|
+
<Route
|
|
72
|
+
path='/dashboard/reports'
|
|
73
|
+
element={
|
|
74
|
+
<ProtectedRoute>
|
|
75
|
+
<Reports />
|
|
76
|
+
</ProtectedRoute>
|
|
77
|
+
}
|
|
78
|
+
/>
|
|
29
79
|
</Routes>
|
|
30
80
|
</BrowserRouter>
|
|
31
81
|
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const { protect } = require('../middleware/auth');
|
|
3
|
+
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
// Example protected route: only accessible with a valid token
|
|
7
|
+
router.get('/secret', protect, (req, res) => {
|
|
8
|
+
res.json({
|
|
9
|
+
message: 'This is a protected route. You are authenticated!',
|
|
10
|
+
user: {
|
|
11
|
+
id: req.user._id,
|
|
12
|
+
name: req.user.name,
|
|
13
|
+
email: req.user.email,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
module.exports = router;
|
|
@@ -9,6 +9,7 @@ const productRoutes = require('./routes/productRoutes');
|
|
|
9
9
|
const SupplierRoutes = require('./routes/SupplierRoutes');
|
|
10
10
|
const warehouseRoutes = require('./routes/warehouseRoutes');
|
|
11
11
|
const reportRoutes = require('./routes/reportRoutes');
|
|
12
|
+
const protectedRoutes = require('./routes/protectedRoutes');
|
|
12
13
|
|
|
13
14
|
const app = express();
|
|
14
15
|
|
|
@@ -19,11 +20,12 @@ connectDB();
|
|
|
19
20
|
app.use('/api/product', productRoutes);
|
|
20
21
|
app.use('/api/supplier', SupplierRoutes);
|
|
21
22
|
app.use('/api/auth/', authRoutes);
|
|
23
|
+
app.use('/api/protected', protectedRoutes);
|
|
22
24
|
app.use('/api/sales', salesRoutes);
|
|
23
25
|
app.use('/api/warehouse', warehouseRoutes);
|
|
24
26
|
app.use('/api/reports', reportRoutes);
|
|
25
27
|
|
|
26
|
-
const PORT =
|
|
28
|
+
const PORT = 1000;
|
|
27
29
|
app.listen(PORT, () => {
|
|
28
30
|
console.log(`Server running on http://localhost:${PORT}`);
|
|
29
31
|
});
|
|
@@ -6,6 +6,7 @@ import Product from './pages/Product';
|
|
|
6
6
|
import Warehouse from './pages/Warehouse';
|
|
7
7
|
import Sales from './pages/Sales';
|
|
8
8
|
import Reports from './pages/Reports';
|
|
9
|
+
import ProtectedRoute from './components/ProtectedRoute';
|
|
9
10
|
|
|
10
11
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
11
12
|
|
|
@@ -14,15 +15,43 @@ function App() {
|
|
|
14
15
|
<div>
|
|
15
16
|
<BrowserRouter>
|
|
16
17
|
<Routes>
|
|
17
|
-
<Route path='/' element={
|
|
18
|
-
|
|
18
|
+
<Route path='/' element={
|
|
19
|
+
<ProtectedRoute>
|
|
20
|
+
<Dashboard />
|
|
21
|
+
</ProtectedRoute>
|
|
22
|
+
} />
|
|
23
|
+
<Route path='/dashboard' element={
|
|
24
|
+
<ProtectedRoute>
|
|
25
|
+
<Dashboard />
|
|
26
|
+
</ProtectedRoute>
|
|
27
|
+
} />
|
|
19
28
|
<Route path='/login' element={<Login />} />
|
|
20
29
|
<Route path='/register' element={<Register />} />
|
|
21
|
-
<Route path='/dashboard/products' element={
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
<Route path='/dashboard/products' element={
|
|
31
|
+
<ProtectedRoute>
|
|
32
|
+
<Product />
|
|
33
|
+
</ProtectedRoute>
|
|
34
|
+
} />
|
|
35
|
+
<Route path='/dashboard/warehouse' element={
|
|
36
|
+
<ProtectedRoute>
|
|
37
|
+
<Warehouse />
|
|
38
|
+
</ProtectedRoute>
|
|
39
|
+
} />
|
|
40
|
+
<Route path='/dashboard/transactions' element={
|
|
41
|
+
<ProtectedRoute>
|
|
42
|
+
<Sales />
|
|
43
|
+
</ProtectedRoute>
|
|
44
|
+
} />
|
|
45
|
+
<Route path='/dashboard/reports' element={
|
|
46
|
+
<ProtectedRoute>
|
|
47
|
+
<Reports />
|
|
48
|
+
</ProtectedRoute>
|
|
49
|
+
} />
|
|
50
|
+
<Route path='/dashboard/profile' element={
|
|
51
|
+
<ProtectedRoute>
|
|
52
|
+
<Profile />
|
|
53
|
+
</ProtectedRoute>
|
|
54
|
+
} />
|
|
26
55
|
</Routes>
|
|
27
56
|
</BrowserRouter>
|
|
28
57
|
</div>
|
|
@@ -23,7 +23,7 @@ function AppLayout({ title, subtitle, children }) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
axios
|
|
26
|
-
.get('http://localhost:
|
|
26
|
+
.get('http://localhost:1000/api/auth/me', {
|
|
27
27
|
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
|
|
28
28
|
})
|
|
29
29
|
.then((response) => {
|
package/templates/SMS(Stock Managment System)/frontend-project/src/components/ProtectedRoute.jsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Navigate } from 'react-router-dom';
|
|
2
|
+
|
|
3
|
+
function ProtectedRoute({ children }) {
|
|
4
|
+
const token = localStorage.getItem('token');
|
|
5
|
+
|
|
6
|
+
if (!token) {
|
|
7
|
+
return <Navigate to="/login" replace />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return children;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default ProtectedRoute;
|
|
@@ -17,7 +17,7 @@ function Login() {
|
|
|
17
17
|
setLoading(true);
|
|
18
18
|
|
|
19
19
|
try {
|
|
20
|
-
const response = await axios.post('http://localhost:
|
|
20
|
+
const response = await axios.post('http://localhost:1000/api/auth/login', { email, password });
|
|
21
21
|
localStorage.setItem('token', response.data.token);
|
|
22
22
|
localStorage.setItem('user', JSON.stringify(response.data.user));
|
|
23
23
|
setMessage('Login successful');
|
|
@@ -1,8 +1,11 @@
|
|
|
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/product';
|
|
6
|
+
|
|
5
7
|
function Product() {
|
|
8
|
+
const [products, setProducts] = useState([]);
|
|
6
9
|
const [productCode, setProductCode] = useState('');
|
|
7
10
|
const [productName, setProductName] = useState('');
|
|
8
11
|
const [category, setCategory] = useState('');
|
|
@@ -11,6 +14,8 @@ function Product() {
|
|
|
11
14
|
const [supplierName, setSupplierName] = useState('');
|
|
12
15
|
const [dateReceived, setDateReceived] = useState('');
|
|
13
16
|
const [message, setMessage] = useState('');
|
|
17
|
+
const [error, setError] = useState('');
|
|
18
|
+
const [editingId, setEditingId] = useState(null);
|
|
14
19
|
|
|
15
20
|
const headers = {
|
|
16
21
|
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
|
@@ -24,96 +29,224 @@ function Product() {
|
|
|
24
29
|
setQuantityInStock('');
|
|
25
30
|
setSupplierName('');
|
|
26
31
|
setDateReceived('');
|
|
32
|
+
setEditingId(null);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const fetchProducts = async () => {
|
|
36
|
+
try {
|
|
37
|
+
const response = await axios.get(`${API_BASE}/getproduct`, { headers });
|
|
38
|
+
setProducts(response.data);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
setError('Failed to load products');
|
|
41
|
+
console.error(err);
|
|
42
|
+
}
|
|
27
43
|
};
|
|
28
44
|
|
|
29
45
|
const handleSubmit = async (e) => {
|
|
30
46
|
e.preventDefault();
|
|
47
|
+
setError('');
|
|
48
|
+
setMessage('');
|
|
49
|
+
|
|
31
50
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
if (editingId) {
|
|
52
|
+
await axios.put(
|
|
53
|
+
`${API_BASE}/updateproduct/${editingId}`,
|
|
54
|
+
{
|
|
55
|
+
productCode,
|
|
56
|
+
productName,
|
|
57
|
+
category,
|
|
58
|
+
unitPrice,
|
|
59
|
+
quantityInStock,
|
|
60
|
+
supplierName,
|
|
61
|
+
dateReceived,
|
|
62
|
+
},
|
|
63
|
+
{ headers }
|
|
64
|
+
);
|
|
65
|
+
setMessage('Product updated successfully');
|
|
66
|
+
} else {
|
|
67
|
+
await axios.post(
|
|
68
|
+
`${API_BASE}/addproduct`,
|
|
69
|
+
{
|
|
70
|
+
productCode,
|
|
71
|
+
productName,
|
|
72
|
+
category,
|
|
73
|
+
unitPrice,
|
|
74
|
+
quantityInStock,
|
|
75
|
+
supplierName,
|
|
76
|
+
dateReceived,
|
|
77
|
+
},
|
|
78
|
+
{ headers }
|
|
79
|
+
);
|
|
80
|
+
setMessage('Product added successfully');
|
|
81
|
+
}
|
|
46
82
|
clearForm();
|
|
83
|
+
fetchProducts();
|
|
84
|
+
} catch (err) {
|
|
85
|
+
setError(err.response?.data?.message || 'Failed to save product');
|
|
86
|
+
console.error(err);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const handleEdit = (product) => {
|
|
91
|
+
setEditingId(product._id);
|
|
92
|
+
setProductCode(product.productCode || '');
|
|
93
|
+
setProductName(product.productName || '');
|
|
94
|
+
setCategory(product.category || '');
|
|
95
|
+
setUnitPrice(product.unitPrice || '');
|
|
96
|
+
setQuantityInStock(product.quantityInStock || '');
|
|
97
|
+
setSupplierName(product.supplierName || '');
|
|
98
|
+
setDateReceived(product.dateReceived ? product.dateReceived.split('T')[0] : '');
|
|
99
|
+
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const handleDelete = async (id) => {
|
|
103
|
+
try {
|
|
104
|
+
await axios.delete(`${API_BASE}/deleteproduct/${id}`, { headers });
|
|
105
|
+
setMessage('Product deleted successfully');
|
|
106
|
+
fetchProducts();
|
|
47
107
|
} catch (err) {
|
|
48
|
-
|
|
108
|
+
setError('Failed to delete product');
|
|
109
|
+
console.error(err);
|
|
49
110
|
}
|
|
50
111
|
};
|
|
51
112
|
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
fetchProducts();
|
|
115
|
+
}, []);
|
|
116
|
+
|
|
52
117
|
return (
|
|
53
118
|
<AppLayout title="Product management" subtitle="Inventory">
|
|
54
|
-
<div className="mx-auto max-w-
|
|
55
|
-
|
|
119
|
+
<div className="mx-auto max-w-6xl space-y-6">
|
|
120
|
+
<div className="card space-y-4 p-5">
|
|
121
|
+
{message && <p className="alert-success">{message}</p>}
|
|
122
|
+
{error && <p className="alert-error">{error}</p>}
|
|
123
|
+
|
|
124
|
+
<form onSubmit={handleSubmit} className="space-y-3">
|
|
125
|
+
<h2 className="text-lg font-semibold text-slate-800">
|
|
126
|
+
{editingId ? 'Edit product' : 'Add new product'}
|
|
127
|
+
</h2>
|
|
128
|
+
<div className="grid gap-4 sm:grid-cols-2">
|
|
129
|
+
<input
|
|
130
|
+
type="text"
|
|
131
|
+
placeholder="Product code"
|
|
132
|
+
value={productCode}
|
|
133
|
+
onChange={(e) => setProductCode(e.target.value)}
|
|
134
|
+
className="input-field"
|
|
135
|
+
required
|
|
136
|
+
/>
|
|
137
|
+
<input
|
|
138
|
+
type="text"
|
|
139
|
+
placeholder="Product name"
|
|
140
|
+
value={productName}
|
|
141
|
+
onChange={(e) => setProductName(e.target.value)}
|
|
142
|
+
className="input-field"
|
|
143
|
+
required
|
|
144
|
+
/>
|
|
145
|
+
<input
|
|
146
|
+
type="text"
|
|
147
|
+
placeholder="Category"
|
|
148
|
+
value={category}
|
|
149
|
+
onChange={(e) => setCategory(e.target.value)}
|
|
150
|
+
className="input-field"
|
|
151
|
+
required
|
|
152
|
+
/>
|
|
153
|
+
<input
|
|
154
|
+
type="number"
|
|
155
|
+
placeholder="Unit price"
|
|
156
|
+
value={unitPrice}
|
|
157
|
+
onChange={(e) => setUnitPrice(e.target.value)}
|
|
158
|
+
className="input-field"
|
|
159
|
+
required
|
|
160
|
+
/>
|
|
161
|
+
<input
|
|
162
|
+
type="number"
|
|
163
|
+
placeholder="Quantity in stock"
|
|
164
|
+
value={quantityInStock}
|
|
165
|
+
onChange={(e) => setQuantityInStock(e.target.value)}
|
|
166
|
+
className="input-field"
|
|
167
|
+
required
|
|
168
|
+
/>
|
|
169
|
+
<input
|
|
170
|
+
type="text"
|
|
171
|
+
placeholder="Supplier name"
|
|
172
|
+
value={supplierName}
|
|
173
|
+
onChange={(e) => setSupplierName(e.target.value)}
|
|
174
|
+
className="input-field"
|
|
175
|
+
required
|
|
176
|
+
/>
|
|
177
|
+
<input
|
|
178
|
+
type="date"
|
|
179
|
+
value={dateReceived}
|
|
180
|
+
onChange={(e) => setDateReceived(e.target.value)}
|
|
181
|
+
className="input-field"
|
|
182
|
+
required
|
|
183
|
+
/>
|
|
184
|
+
</div>
|
|
185
|
+
<div className="flex flex-wrap gap-3">
|
|
186
|
+
<button type="submit" className="btn-primary">
|
|
187
|
+
{editingId ? 'Save changes' : 'Add product'}
|
|
188
|
+
</button>
|
|
189
|
+
{editingId && (
|
|
190
|
+
<button type="button" onClick={clearForm} className="btn-secondary">
|
|
191
|
+
Cancel
|
|
192
|
+
</button>
|
|
193
|
+
)}
|
|
194
|
+
</div>
|
|
195
|
+
</form>
|
|
196
|
+
</div>
|
|
56
197
|
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
onChange={(e) => setDateReceived(e.target.value)}
|
|
110
|
-
className="input-field"
|
|
111
|
-
required
|
|
112
|
-
/>
|
|
113
|
-
<button type="submit" className="btn-primary">
|
|
114
|
-
Add product
|
|
115
|
-
</button>
|
|
116
|
-
</form>
|
|
198
|
+
<div className="card p-5">
|
|
199
|
+
<h2 className="text-lg font-semibold text-slate-800">Products</h2>
|
|
200
|
+
{products.length === 0 ? (
|
|
201
|
+
<p className="mt-4 text-sm text-slate-500">No products available yet.</p>
|
|
202
|
+
) : (
|
|
203
|
+
<div className="mt-4 overflow-x-auto">
|
|
204
|
+
<table className="min-w-full divide-y divide-slate-200 text-sm">
|
|
205
|
+
<thead>
|
|
206
|
+
<tr className="bg-slate-50 text-left text-slate-600">
|
|
207
|
+
<th className="px-4 py-3">Code</th>
|
|
208
|
+
<th className="px-4 py-3">Name</th>
|
|
209
|
+
<th className="px-4 py-3">Category</th>
|
|
210
|
+
<th className="px-4 py-3">Price</th>
|
|
211
|
+
<th className="px-4 py-3">Stock</th>
|
|
212
|
+
<th className="px-4 py-3">Supplier</th>
|
|
213
|
+
<th className="px-4 py-3">Received</th>
|
|
214
|
+
<th className="px-4 py-3">Actions</th>
|
|
215
|
+
</tr>
|
|
216
|
+
</thead>
|
|
217
|
+
<tbody className="divide-y divide-slate-200">
|
|
218
|
+
{products.map((product) => (
|
|
219
|
+
<tr key={product._id} className="hover:bg-slate-50">
|
|
220
|
+
<td className="px-4 py-3">{product.productCode}</td>
|
|
221
|
+
<td className="px-4 py-3">{product.productName}</td>
|
|
222
|
+
<td className="px-4 py-3">{product.category}</td>
|
|
223
|
+
<td className="px-4 py-3">{product.unitPrice}</td>
|
|
224
|
+
<td className="px-4 py-3">{product.quantityInStock}</td>
|
|
225
|
+
<td className="px-4 py-3">{product.supplierName}</td>
|
|
226
|
+
<td className="px-4 py-3">{product.dateReceived?.split('T')[0] || '-'}</td>
|
|
227
|
+
<td className="px-4 py-3 space-x-2">
|
|
228
|
+
<button
|
|
229
|
+
type="button"
|
|
230
|
+
onClick={() => handleEdit(product)}
|
|
231
|
+
className="btn-secondary"
|
|
232
|
+
>
|
|
233
|
+
Edit
|
|
234
|
+
</button>
|
|
235
|
+
<button
|
|
236
|
+
type="button"
|
|
237
|
+
onClick={() => handleDelete(product._id)}
|
|
238
|
+
className="btn-danger"
|
|
239
|
+
>
|
|
240
|
+
Delete
|
|
241
|
+
</button>
|
|
242
|
+
</td>
|
|
243
|
+
</tr>
|
|
244
|
+
))}
|
|
245
|
+
</tbody>
|
|
246
|
+
</table>
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
117
250
|
</div>
|
|
118
251
|
</AppLayout>
|
|
119
252
|
);
|
|
@@ -8,7 +8,7 @@ function Profile() {
|
|
|
8
8
|
|
|
9
9
|
const handleRetrieve = async () => {
|
|
10
10
|
try {
|
|
11
|
-
const response = await axios.get('http://localhost:
|
|
11
|
+
const response = await axios.get('http://localhost:1000/api/auth/me', {
|
|
12
12
|
headers: {
|
|
13
13
|
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
|
14
14
|
},
|
|
@@ -12,7 +12,7 @@ function Reports() {
|
|
|
12
12
|
|
|
13
13
|
const fetchReports = async () => {
|
|
14
14
|
try {
|
|
15
|
-
const res = await axios.get('http://localhost:
|
|
15
|
+
const res = await axios.get('http://localhost:1000/api/reports/summary', { headers });
|
|
16
16
|
setReports(res.data);
|
|
17
17
|
} catch (err) {
|
|
18
18
|
setError('Could not load reports');
|
|
@@ -29,7 +29,7 @@ function Sales() {
|
|
|
29
29
|
|
|
30
30
|
const fetchProducts = async () => {
|
|
31
31
|
try {
|
|
32
|
-
const res = await axios.get('http://localhost:
|
|
32
|
+
const res = await axios.get('http://localhost:1000/api/product/getproduct', { headers });
|
|
33
33
|
setProducts(res.data);
|
|
34
34
|
} catch (error) {
|
|
35
35
|
console.log(error);
|
|
@@ -38,7 +38,7 @@ function Sales() {
|
|
|
38
38
|
|
|
39
39
|
const fetchWarehouses = async () => {
|
|
40
40
|
try {
|
|
41
|
-
const res = await axios.get('http://localhost:
|
|
41
|
+
const res = await axios.get('http://localhost:1000/api/warehouse/getwarehouse', { headers });
|
|
42
42
|
setWarehouses(res.data);
|
|
43
43
|
} catch (error) {
|
|
44
44
|
console.log(error);
|
|
@@ -47,7 +47,7 @@ function Sales() {
|
|
|
47
47
|
|
|
48
48
|
const handleGet = async () => {
|
|
49
49
|
try {
|
|
50
|
-
const res = await axios.get('http://localhost:
|
|
50
|
+
const res = await axios.get('http://localhost:1000/api/sales/getsales', { headers });
|
|
51
51
|
setTransactions(res.data);
|
|
52
52
|
} catch (error) {
|
|
53
53
|
console.log(error);
|
|
@@ -65,14 +65,14 @@ function Sales() {
|
|
|
65
65
|
try {
|
|
66
66
|
if (editId) {
|
|
67
67
|
await axios.put(
|
|
68
|
-
`http://localhost:
|
|
68
|
+
`http://localhost:1000/api/sales/updatesales/${editId}`,
|
|
69
69
|
{ transactionDate, quantityMoved, transactionType, productId, warehouseId },
|
|
70
70
|
{ headers }
|
|
71
71
|
);
|
|
72
72
|
setMessage('Transaction updated successfully');
|
|
73
73
|
} else {
|
|
74
74
|
await axios.post(
|
|
75
|
-
'http://localhost:
|
|
75
|
+
'http://localhost:1000/api/sales/addsales',
|
|
76
76
|
{ transactionDate, quantityMoved, transactionType, productId, warehouseId },
|
|
77
77
|
{ headers }
|
|
78
78
|
);
|
|
@@ -87,7 +87,7 @@ function Sales() {
|
|
|
87
87
|
|
|
88
88
|
const handledelete = async (id) => {
|
|
89
89
|
try {
|
|
90
|
-
await axios.delete(`http://localhost:
|
|
90
|
+
await axios.delete(`http://localhost:1000/api/sales/deletesales/${id}`, { headers });
|
|
91
91
|
handleGet();
|
|
92
92
|
} catch (error) {
|
|
93
93
|
console.log(error);
|