create-myexam-app 1.0.19 → 1.0.21

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 (45) hide show
  1. package/package.json +1 -1
  2. package/projects/SCMS/backend/.env +5 -0
  3. package/projects/SCMS/backend/config/db.js +12 -0
  4. package/projects/SCMS/backend/controllers/authController.js +90 -0
  5. package/projects/SCMS/backend/controllers/deliveryController.js +79 -0
  6. package/projects/SCMS/backend/controllers/productController.js +74 -0
  7. package/projects/SCMS/backend/controllers/reportsController.js +77 -0
  8. package/projects/SCMS/backend/controllers/shipmentController.js +80 -0
  9. package/projects/SCMS/backend/controllers/supplierController.js +58 -0
  10. package/projects/SCMS/backend/middleware/auth.js +32 -0
  11. package/projects/SCMS/backend/models/User.js +28 -0
  12. package/projects/SCMS/backend/models/delivery.js +33 -0
  13. package/projects/SCMS/backend/models/product.js +43 -0
  14. package/projects/SCMS/backend/models/shipment.js +34 -0
  15. package/projects/SCMS/backend/models/supplier.js +36 -0
  16. package/projects/SCMS/backend/package-lock.json +2190 -0
  17. package/projects/SCMS/backend/package.json +23 -0
  18. package/projects/SCMS/backend/routes/SupplierRoutes.js +15 -0
  19. package/projects/SCMS/backend/routes/authRoutes.js +11 -0
  20. package/projects/SCMS/backend/routes/deliveryRoutes.js +18 -0
  21. package/projects/SCMS/backend/routes/productRoutes.js +15 -0
  22. package/projects/SCMS/backend/routes/protectedRoutes.js +10 -0
  23. package/projects/SCMS/backend/routes/reportsRoutes.js +8 -0
  24. package/projects/SCMS/backend/routes/shipmentRoutes.js +18 -0
  25. package/projects/SCMS/backend/server.js +35 -0
  26. package/projects/SCMS/frontend/README.md +16 -0
  27. package/projects/SCMS/frontend/eslint.config.js +21 -0
  28. package/projects/SCMS/frontend/index.html +13 -0
  29. package/projects/SCMS/frontend/package-lock.json +3053 -0
  30. package/projects/SCMS/frontend/package.json +31 -0
  31. package/projects/SCMS/frontend/public/favicon.svg +1 -0
  32. package/projects/SCMS/frontend/src/App.jsx +35 -0
  33. package/projects/SCMS/frontend/src/components/DashboardLayout.jsx +103 -0
  34. package/projects/SCMS/frontend/src/components/ProtectedRoute.jsx +30 -0
  35. package/projects/SCMS/frontend/src/index.css +114 -0
  36. package/projects/SCMS/frontend/src/main.jsx +10 -0
  37. package/projects/SCMS/frontend/src/pages/DashboardHome.jsx +34 -0
  38. package/projects/SCMS/frontend/src/pages/Delivery.jsx +183 -0
  39. package/projects/SCMS/frontend/src/pages/Login.jsx +81 -0
  40. package/projects/SCMS/frontend/src/pages/Profile.jsx +62 -0
  41. package/projects/SCMS/frontend/src/pages/Register.jsx +110 -0
  42. package/projects/SCMS/frontend/src/pages/Reports.jsx +94 -0
  43. package/projects/SCMS/frontend/src/pages/Shipment.jsx +182 -0
  44. package/projects/SCMS/frontend/src/pages/Supplier.jsx +165 -0
  45. package/projects/SCMS/frontend/vite.config.js +7 -0
@@ -0,0 +1,62 @@
1
+ import { useEffect, useState } from 'react';
2
+ import axios from 'axios';
3
+
4
+ function Profile() {
5
+ const [user, setUser] = useState(null);
6
+ const [error, setError] = useState('');
7
+
8
+ useEffect(() => {
9
+ axios
10
+ .get('http://localhost:5001/api/auth/me', {
11
+ headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
12
+ })
13
+ .then((response) => {
14
+ setUser(response.data.user);
15
+ localStorage.setItem('user', JSON.stringify(response.data.user));
16
+ })
17
+ .catch((err) => {
18
+ const storedUser = localStorage.getItem('user');
19
+ if (storedUser) {
20
+ setUser(JSON.parse(storedUser));
21
+ } else {
22
+ setError(err.response?.data?.message || 'Failed to load profile');
23
+ }
24
+ });
25
+ }, []);
26
+
27
+ if (!user) {
28
+ return (
29
+ <div className="page-content">
30
+ <p className="text-muted">{error || 'No profile data found. Try signing in again.'}</p>
31
+ </div>
32
+ );
33
+ }
34
+
35
+ return (
36
+ <div className="page-content max-w-lg">
37
+ <h1 className="page-title">Profile</h1>
38
+ <p className="page-subtitle">Your account details</p>
39
+
40
+ {error && <p className="alert-error">{error}</p>}
41
+
42
+ <div className="card divide-y divide-slate-100">
43
+ <div className="px-5 py-3.5 flex justify-between gap-4">
44
+ <span className="text-sm text-muted">Name</span>
45
+ <span className="text-sm text-brand-900">{user.name}</span>
46
+ </div>
47
+ <div className="px-5 py-3.5 flex justify-between gap-4">
48
+ <span className="text-sm text-muted">Email</span>
49
+ <span className="text-sm text-brand-900">{user.email}</span>
50
+ </div>
51
+ {user.id && (
52
+ <div className="px-5 py-3.5 flex justify-between gap-4">
53
+ <span className="text-sm text-muted">User ID</span>
54
+ <span className="text-sm text-brand-900 font-mono truncate">{user.id}</span>
55
+ </div>
56
+ )}
57
+ </div>
58
+ </div>
59
+ );
60
+ }
61
+
62
+ export default Profile;
@@ -0,0 +1,110 @@
1
+ import { useState } from 'react';
2
+ import axios from 'axios';
3
+ import { Link, useNavigate } from 'react-router-dom';
4
+
5
+ function Register() {
6
+ const navigate = useNavigate();
7
+ const [name, setName] = useState('');
8
+ const [email, setEmail] = useState('');
9
+ const [password, setPassword] = useState('');
10
+ const [error, setError] = useState('');
11
+ const [message, setMessage] = useState('');
12
+ const [loading, setLoading] = useState(false);
13
+
14
+ const handleSubmit = async (e) => {
15
+ e.preventDefault();
16
+ setError('');
17
+ setMessage('');
18
+ setLoading(true);
19
+
20
+ try {
21
+ const response = await axios.post('http://localhost:5001/api/auth/register', {
22
+ name,
23
+ email,
24
+ password,
25
+ });
26
+ localStorage.setItem('token', response.data.token);
27
+ localStorage.setItem('user', JSON.stringify(response.data.user));
28
+ setMessage('Account created successfully');
29
+ navigate('/dashboard');
30
+ } catch (err) {
31
+ setError(err.response?.data?.message || 'Registration failed');
32
+ console.error('Server Error:', err.response?.data || err.message);
33
+ } finally {
34
+ setLoading(false);
35
+ }
36
+ };
37
+
38
+ return (
39
+ <div className="auth-page">
40
+ <div className="auth-card">
41
+ <p className="text-xs font-semibold uppercase tracking-wider text-brand-600 mb-1">SCMS</p>
42
+ <h1 className="text-xl font-semibold text-brand-900 mb-6">Create account</h1>
43
+
44
+ {message && <p className="alert-success">{message}</p>}
45
+ {error && <p className="alert-error">{error}</p>}
46
+
47
+ <form onSubmit={handleSubmit} className="space-y-4">
48
+ <div>
49
+ <label htmlFor="name" className="block text-sm font-medium text-slate-700 mb-1">
50
+ Name
51
+ </label>
52
+ <input
53
+ id="name"
54
+ name="name"
55
+ type="text"
56
+ required
57
+ value={name}
58
+ onChange={(e) => setName(e.target.value)}
59
+ className="input"
60
+ />
61
+ </div>
62
+
63
+ <div>
64
+ <label htmlFor="email" className="block text-sm font-medium text-slate-700 mb-1">
65
+ Email
66
+ </label>
67
+ <input
68
+ id="email"
69
+ name="email"
70
+ type="email"
71
+ required
72
+ value={email}
73
+ onChange={(e) => setEmail(e.target.value)}
74
+ className="input"
75
+ />
76
+ </div>
77
+
78
+ <div>
79
+ <label htmlFor="password" className="block text-sm font-medium text-slate-700 mb-1">
80
+ Password
81
+ </label>
82
+ <input
83
+ id="password"
84
+ name="password"
85
+ type="password"
86
+ required
87
+ minLength={6}
88
+ value={password}
89
+ onChange={(e) => setPassword(e.target.value)}
90
+ className="input"
91
+ />
92
+ </div>
93
+
94
+ <button type="submit" disabled={loading} className="btn-primary-full">
95
+ {loading ? 'Creating account...' : 'Register'}
96
+ </button>
97
+ </form>
98
+
99
+ <p className="mt-5 text-sm text-muted text-center">
100
+ Already have an account?{' '}
101
+ <Link to="/login" className="text-brand-700 font-medium hover:text-brand-800">
102
+ Sign in
103
+ </Link>
104
+ </p>
105
+ </div>
106
+ </div>
107
+ );
108
+ }
109
+
110
+ export default Register;
@@ -0,0 +1,94 @@
1
+ import { useEffect, useState } from 'react';
2
+ import axios from 'axios';
3
+
4
+ function Reports() {
5
+ const [report, setReport] = useState(null);
6
+ const [error, setError] = useState('');
7
+
8
+ const headers = {
9
+ Authorization: `Bearer ${localStorage.getItem('token')}`,
10
+ };
11
+
12
+ useEffect(() => {
13
+ axios
14
+ .get('http://localhost:5001/api/reports/summary', { headers })
15
+ .then((res) => setReport(res.data))
16
+ .catch((err) => {
17
+ console.error(err);
18
+ setError('Failed to load reports');
19
+ });
20
+ }, []);
21
+
22
+ return (
23
+ <div className="page-content">
24
+ <h1 className="page-title">Reports</h1>
25
+ <p className="page-subtitle">Summary of your supply chain activity</p>
26
+
27
+ {error && <p className="alert-error">{error}</p>}
28
+
29
+ {!report ? (
30
+ <p className="text-sm text-muted">Loading report summary...</p>
31
+ ) : (
32
+ <>
33
+ <div className="grid gap-4 md:grid-cols-3 mb-6">
34
+ <div className="stat-card">
35
+ <h2>Suppliers</h2>
36
+ <p>Total: {report.suppliers.total}</p>
37
+ <p>Daily: {report.suppliers.daily}</p>
38
+ <p>Weekly: {report.suppliers.weekly}</p>
39
+ <p>Monthly: {report.suppliers.monthly}</p>
40
+ </div>
41
+ <div className="stat-card">
42
+ <h2>Shipments</h2>
43
+ <p>Total: {report.shipments.total}</p>
44
+ <p>Daily: {report.shipments.daily}</p>
45
+ <p>Weekly: {report.shipments.weekly}</p>
46
+ <p>Monthly: {report.shipments.monthly}</p>
47
+ </div>
48
+ <div className="stat-card">
49
+ <h2>Deliveries</h2>
50
+ <p>Total: {report.deliveries.total}</p>
51
+ <p>Daily: {report.deliveries.daily}</p>
52
+ <p>Weekly: {report.deliveries.weekly}</p>
53
+ <p>Monthly: {report.deliveries.monthly}</p>
54
+ </div>
55
+ </div>
56
+
57
+ <div className="grid gap-4 md:grid-cols-2">
58
+ <div className="stat-card">
59
+ <h2>Recent Shipments</h2>
60
+ {report.recentShipments.length === 0 ? (
61
+ <p className="text-sm text-muted">No recent shipments.</p>
62
+ ) : (
63
+ report.recentShipments.map((shipment) => (
64
+ <div key={shipment._id} className="mb-3 pb-3 border-b border-slate-100 last:border-0 last:mb-0 last:pb-0">
65
+ <p className="text-sm font-medium text-brand-800">{shipment.shipmentNumber}</p>
66
+ <p className="text-sm text-muted">Destination: {shipment.destination}</p>
67
+ <p className="text-sm text-muted">Status: {shipment.shipmentStatus}</p>
68
+ </div>
69
+ ))
70
+ )}
71
+ </div>
72
+
73
+ <div className="stat-card">
74
+ <h2>Recent Deliveries</h2>
75
+ {report.recentDeliveries.length === 0 ? (
76
+ <p className="text-sm text-muted">No recent deliveries.</p>
77
+ ) : (
78
+ report.recentDeliveries.map((delivery) => (
79
+ <div key={delivery._id} className="mb-3 pb-3 border-b border-slate-100 last:border-0 last:mb-0 last:pb-0">
80
+ <p className="text-sm font-medium text-brand-800">{delivery.deliveryCode}</p>
81
+ <p className="text-sm text-muted">Quantity: {delivery.quantityDelivered}</p>
82
+ <p className="text-sm text-muted">Status: {delivery.deliveryStatus}</p>
83
+ </div>
84
+ ))
85
+ )}
86
+ </div>
87
+ </div>
88
+ </>
89
+ )}
90
+ </div>
91
+ );
92
+ }
93
+
94
+ export default Reports;
@@ -0,0 +1,182 @@
1
+ import { useEffect, useState } from 'react';
2
+ import axios from 'axios';
3
+
4
+ function Shipment() {
5
+ const [shipments, setShipments] = useState([]);
6
+ const [suppliers, setSuppliers] = useState([]);
7
+ const [shipmentNumber, setShipmentNumber] = useState('');
8
+ const [shipmentDate, setShipmentDate] = useState('');
9
+ const [shipmentStatus, setShipmentStatus] = useState('Pending');
10
+ const [destination, setDestination] = useState('');
11
+ const [supplierId, setSupplierId] = useState('');
12
+ const [editId, setEditId] = useState(null);
13
+ const [message, setMessage] = useState('');
14
+
15
+ const headers = {
16
+ Authorization: `Bearer ${localStorage.getItem('token')}`,
17
+ };
18
+
19
+ const clearForm = () => {
20
+ setShipmentNumber('');
21
+ setShipmentDate('');
22
+ setShipmentStatus('Pending');
23
+ setDestination('');
24
+ setSupplierId('');
25
+ setEditId(null);
26
+ };
27
+
28
+ const loadSuppliers = async () => {
29
+ try {
30
+ const res = await axios.get('http://localhost:5001/api/supplier/getsupplier', { headers });
31
+ setSuppliers(res.data);
32
+ } catch (error) {
33
+ console.error(error);
34
+ }
35
+ };
36
+
37
+ const loadShipments = async () => {
38
+ try {
39
+ const res = await axios.get('http://localhost:5001/api/shipment/getshipments', { headers });
40
+ setShipments(res.data);
41
+ } catch (error) {
42
+ console.error(error);
43
+ }
44
+ };
45
+
46
+ useEffect(() => {
47
+ loadSuppliers();
48
+ loadShipments();
49
+ }, []);
50
+
51
+ const handleSubmit = async (e) => {
52
+ e.preventDefault();
53
+ try {
54
+ if (editId) {
55
+ await axios.put(
56
+ `http://localhost:5001/api/shipment/updateshipment/${editId}`,
57
+ { shipmentNumber, shipmentDate, shipmentStatus, destination, supplierId },
58
+ { headers }
59
+ );
60
+ setMessage('Shipment updated successfully');
61
+ } else {
62
+ await axios.post(
63
+ 'http://localhost:5001/api/shipment/addshipment',
64
+ { shipmentNumber, shipmentDate, shipmentStatus, destination, supplierId },
65
+ { headers }
66
+ );
67
+ setMessage('Shipment added successfully');
68
+ }
69
+ clearForm();
70
+ loadShipments();
71
+ } catch (error) {
72
+ console.error(error);
73
+ setMessage('Failed to save shipment');
74
+ }
75
+ };
76
+
77
+ const handleEdit = (shipment) => {
78
+ setShipmentNumber(shipment.shipmentNumber);
79
+ setShipmentDate(shipment.shipmentDate?.split('T')[0] || '');
80
+ setShipmentStatus(shipment.shipmentStatus);
81
+ setDestination(shipment.destination);
82
+ setSupplierId(shipment.supplier?._id || '');
83
+ setEditId(shipment._id);
84
+ };
85
+
86
+ const handleDelete = async (id) => {
87
+ try {
88
+ await axios.delete(`http://localhost:5001/api/shipment/deleteshipment/${id}`, { headers });
89
+ loadShipments();
90
+ } catch (error) {
91
+ console.error(error);
92
+ }
93
+ };
94
+
95
+ return (
96
+ <div className="page-content">
97
+ <h1 className="page-title">Shipment Management</h1>
98
+ <p className="page-subtitle">Track and manage shipments</p>
99
+
100
+ {message && <p className="alert-success">{message}</p>}
101
+
102
+ <form onSubmit={handleSubmit} className="form-card">
103
+ <input
104
+ type="text"
105
+ placeholder="Shipment Number"
106
+ value={shipmentNumber}
107
+ onChange={(e) => setShipmentNumber(e.target.value)}
108
+ className="input"
109
+ required
110
+ />
111
+ <input
112
+ type="date"
113
+ value={shipmentDate}
114
+ onChange={(e) => setShipmentDate(e.target.value)}
115
+ className="input"
116
+ required
117
+ />
118
+ <input
119
+ type="text"
120
+ placeholder="Destination"
121
+ value={destination}
122
+ onChange={(e) => setDestination(e.target.value)}
123
+ className="input"
124
+ required
125
+ />
126
+ <select
127
+ value={shipmentStatus}
128
+ onChange={(e) => setShipmentStatus(e.target.value)}
129
+ className="input"
130
+ required
131
+ >
132
+ <option value="Pending">Pending</option>
133
+ <option value="In Transit">In Transit</option>
134
+ <option value="Delivered">Delivered</option>
135
+ </select>
136
+ <select
137
+ value={supplierId}
138
+ onChange={(e) => setSupplierId(e.target.value)}
139
+ className="input"
140
+ >
141
+ <option value="">Select supplier (optional)</option>
142
+ {suppliers.map((supplier) => (
143
+ <option key={supplier._id} value={supplier._id}>
144
+ {supplier.supplierCode} - {supplier.supplierName}
145
+ </option>
146
+ ))}
147
+ </select>
148
+ <button type="submit" className="btn-primary">
149
+ {editId ? 'Update Shipment' : 'Add Shipment'}
150
+ </button>
151
+ </form>
152
+
153
+ <div className="space-y-3">
154
+ {shipments.length === 0 ? (
155
+ <p className="text-sm text-muted">No shipment records available.</p>
156
+ ) : (
157
+ shipments.map((shipment) => (
158
+ <div key={shipment._id} className="list-card">
159
+ <p className="text-sm font-medium text-brand-800">{shipment.shipmentNumber}</p>
160
+ <p className="text-sm text-muted">Date: {shipment.shipmentDate?.split('T')[0]}</p>
161
+ <p className="text-sm text-muted">Destination: {shipment.destination}</p>
162
+ <p className="text-sm text-muted">Status: {shipment.shipmentStatus}</p>
163
+ <p className="text-sm text-muted">
164
+ Supplier: {shipment.supplier ? shipment.supplier.supplierName : 'Not assigned'}
165
+ </p>
166
+ <div className="flex gap-4 pt-2">
167
+ <button type="button" onClick={() => handleEdit(shipment)} className="btn-ghost">
168
+ Edit
169
+ </button>
170
+ <button type="button" onClick={() => handleDelete(shipment._id)} className="btn-danger">
171
+ Delete
172
+ </button>
173
+ </div>
174
+ </div>
175
+ ))
176
+ )}
177
+ </div>
178
+ </div>
179
+ );
180
+ }
181
+
182
+ export default Shipment;
@@ -0,0 +1,165 @@
1
+ import { useEffect, useState } from 'react';
2
+ import axios from 'axios';
3
+
4
+ function Supplier() {
5
+ const [suppliers, setSuppliers] = useState([]);
6
+ const [supplierCode, setSupplierCode] = useState('');
7
+ const [supplierName, setSupplierName] = useState('');
8
+ const [address, setAddress] = useState('');
9
+ const [telephone, setTelephone] = useState('');
10
+ const [email, setEmail] = useState('');
11
+ const [editId, setEditId] = useState(null);
12
+ const [message, setMessage] = useState('');
13
+
14
+ const headers = {
15
+ Authorization: `Bearer ${localStorage.getItem('token')}`,
16
+ };
17
+
18
+ const clearForm = () => {
19
+ setSupplierCode('');
20
+ setSupplierName('');
21
+ setAddress('');
22
+ setTelephone('');
23
+ setEmail('');
24
+ setEditId(null);
25
+ };
26
+
27
+ const handleGet = async () => {
28
+ try {
29
+ const res = await axios.get('http://localhost:5001/api/supplier/getsupplier', { headers });
30
+ setSuppliers(res.data);
31
+ } catch (error) {
32
+ console.log(error);
33
+ }
34
+ };
35
+
36
+ useEffect(() => {
37
+ handleGet();
38
+ }, []);
39
+
40
+ const handleSubmit = async (e) => {
41
+ e.preventDefault();
42
+
43
+ try {
44
+ if (editId) {
45
+ await axios.put(
46
+ `http://localhost:5001/api/supplier/updatesupplier/${editId}`,
47
+ { supplierCode, supplierName, address, telephone, email },
48
+ { headers }
49
+ );
50
+ setMessage('Updated successfully');
51
+ } else {
52
+ await axios.post(
53
+ 'http://localhost:5001/api/supplier/addsupplier',
54
+ { supplierCode, supplierName, address, telephone, email },
55
+ { headers }
56
+ );
57
+ setMessage('Added successfully');
58
+ }
59
+
60
+ clearForm();
61
+ handleGet();
62
+ } catch (error) {
63
+ console.log(error);
64
+ setMessage('Something went wrong');
65
+ }
66
+ };
67
+
68
+ const handleDelete = async (id) => {
69
+ try {
70
+ await axios.delete(`http://localhost:5001/api/supplier/deletesupplier/${id}`, { headers });
71
+ handleGet();
72
+ } catch (error) {
73
+ console.log(error);
74
+ }
75
+ };
76
+
77
+ const handleEdit = (supplier) => {
78
+ setSupplierCode(supplier.supplierCode);
79
+ setSupplierName(supplier.supplierName);
80
+ setAddress(supplier.address);
81
+ setTelephone(supplier.telephone);
82
+ setEmail(supplier.email);
83
+ setEditId(supplier._id);
84
+ };
85
+
86
+ return (
87
+ <div className="page-content">
88
+ <h1 className="page-title">Supplier Management</h1>
89
+ <p className="page-subtitle">Add and manage supplier records</p>
90
+
91
+ {message && <p className="alert-success">{message}</p>}
92
+
93
+ <form onSubmit={handleSubmit} className="form-card">
94
+ <input
95
+ type="text"
96
+ placeholder="Supplier Code"
97
+ value={supplierCode}
98
+ onChange={(e) => setSupplierCode(e.target.value)}
99
+ className="input"
100
+ required
101
+ />
102
+ <input
103
+ type="text"
104
+ placeholder="Supplier Name"
105
+ value={supplierName}
106
+ onChange={(e) => setSupplierName(e.target.value)}
107
+ className="input"
108
+ required
109
+ />
110
+ <input
111
+ type="text"
112
+ placeholder="Address"
113
+ value={address}
114
+ onChange={(e) => setAddress(e.target.value)}
115
+ className="input"
116
+ required
117
+ />
118
+ <input
119
+ type="text"
120
+ placeholder="Telephone"
121
+ value={telephone}
122
+ onChange={(e) => setTelephone(e.target.value)}
123
+ className="input"
124
+ required
125
+ />
126
+ <input
127
+ type="email"
128
+ placeholder="Email"
129
+ value={email}
130
+ onChange={(e) => setEmail(e.target.value)}
131
+ className="input"
132
+ required
133
+ />
134
+ <button type="submit" className="btn-primary">
135
+ {editId ? 'Update' : 'Add Supplier'}
136
+ </button>
137
+ </form>
138
+
139
+ <div className="space-y-3">
140
+ {suppliers.length === 0 ? (
141
+ <p className="text-sm text-muted">No suppliers yet.</p>
142
+ ) : (
143
+ suppliers.map((supplier) => (
144
+ <div key={supplier._id} className="list-card">
145
+ <p className="text-sm font-medium text-brand-800">{supplier.supplierName}</p>
146
+ <p className="text-sm text-muted">Code: {supplier.supplierCode}</p>
147
+ <p className="text-sm text-muted">{supplier.address}</p>
148
+ <p className="text-sm text-muted">{supplier.telephone} · {supplier.email}</p>
149
+ <div className="flex gap-4 pt-2">
150
+ <button type="button" onClick={() => handleEdit(supplier)} className="btn-ghost">
151
+ Edit
152
+ </button>
153
+ <button type="button" onClick={() => handleDelete(supplier._id)} className="btn-danger">
154
+ Delete
155
+ </button>
156
+ </div>
157
+ </div>
158
+ ))
159
+ )}
160
+ </div>
161
+ </div>
162
+ );
163
+ }
164
+
165
+ export default Supplier;
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import tailwindcss from '@tailwindcss/vite'
4
+ // https://vite.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react(),tailwindcss()],
7
+ })