sms-tps 1.0.0 → 1.0.1
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/backend-project/.env +1 -1
- package/backend-project/Controller/ProductController.js +43 -0
- package/backend-project/Controller/StockTransactionController.js +89 -0
- package/backend-project/Controller/WarehouseController.js +20 -0
- package/backend-project/Models/ProductModel.js +17 -0
- package/backend-project/Models/StockTransactionModel.js +16 -0
- package/backend-project/Models/WarehouseModel.js +12 -0
- package/backend-project/Router/ProductRouter.js +7 -0
- package/backend-project/Router/StockTransactionRouter.js +10 -0
- package/backend-project/Router/WarehouseRouter.js +8 -0
- package/backend-project/package.json +2 -1
- package/backend-project/server.js +7 -2
- package/frontend-project/package-lock.json +65 -20
- package/frontend-project/package.json +2 -2
- package/frontend-project/src/App.jsx +36 -0
- package/frontend-project/src/Component/Product.jsx +388 -0
- package/frontend-project/src/Component/Report.jsx +162 -0
- package/frontend-project/src/Component/Transfer.jsx +442 -0
- package/frontend-project/src/Component/Warehouse.jsx +238 -0
- package/frontend-project/src/Layout/Pannel.jsx +40 -75
- package/frontend-project/src/index.css +1 -0
- package/frontend-project/src/main.jsx +12 -0
- package/frontend-project/vite.config.js +2 -1
- package/package.json +2 -2
- package/frontend-project/src/App.css +0 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
FaClosedCaptioning,
|
|
4
|
+
FaPlus,
|
|
5
|
+
FaTimes,
|
|
6
|
+
FaTimesCircle,
|
|
7
|
+
} from "react-icons/fa";
|
|
8
|
+
import axios from "axios";
|
|
9
|
+
import toast from "react-hot-toast";
|
|
10
|
+
|
|
11
|
+
const Product = () => {
|
|
12
|
+
const port = 3400;
|
|
13
|
+
const API_URL = `http://localhost:${port}/api/product`;
|
|
14
|
+
const API_URL_W = `http://localhost:${port}/api/warehouse`;
|
|
15
|
+
const [data, setData] = useState([]);
|
|
16
|
+
const [dataW, setDataW] = useState([]);
|
|
17
|
+
const [model, setModel] = useState(false);
|
|
18
|
+
// About Form
|
|
19
|
+
const [formData, setFormData] = useState({
|
|
20
|
+
productCode: "",
|
|
21
|
+
productName: "",
|
|
22
|
+
category: "",
|
|
23
|
+
quantityInStock: "",
|
|
24
|
+
unitPrice: "",
|
|
25
|
+
supplierName: "",
|
|
26
|
+
dateReceived: "",
|
|
27
|
+
warehouse_id: "",
|
|
28
|
+
});
|
|
29
|
+
// About Form
|
|
30
|
+
|
|
31
|
+
// About Table
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const fecthData = async () => {
|
|
35
|
+
try {
|
|
36
|
+
const res = await axios.get(`${API_URL}/get`);
|
|
37
|
+
if (!res.data.success) {
|
|
38
|
+
return toast.error(res.data.message);
|
|
39
|
+
}
|
|
40
|
+
setData(res.data.product);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
alert(error.message);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
fecthData();
|
|
46
|
+
}, [formData]);
|
|
47
|
+
|
|
48
|
+
// About Table
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const fecthData = async () => {
|
|
52
|
+
try {
|
|
53
|
+
const res = await axios.get(`${API_URL_W}/get`);
|
|
54
|
+
if (!res.data.success) {
|
|
55
|
+
return toast.error(res.data.message);
|
|
56
|
+
}
|
|
57
|
+
setDataW(res.data.warehouse);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
alert(error.message);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
fecthData();
|
|
63
|
+
}, [formData]);
|
|
64
|
+
|
|
65
|
+
// About Form
|
|
66
|
+
|
|
67
|
+
const handleFormData = async (e) => {
|
|
68
|
+
const { name, value } = e.target;
|
|
69
|
+
setFormData({ ...formData, [name]: value });
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const handleSubmit = async (e) => {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
try {
|
|
75
|
+
if (
|
|
76
|
+
!formData.productCode ||
|
|
77
|
+
!formData.productName ||
|
|
78
|
+
!formData.quantityInStock ||
|
|
79
|
+
!formData.supplierName ||
|
|
80
|
+
!formData.unitPrice ||
|
|
81
|
+
!formData.category ||
|
|
82
|
+
!formData.dateReceived ||
|
|
83
|
+
!formData.warehouse_id
|
|
84
|
+
) {
|
|
85
|
+
return toast.error("You Must Fill all Field");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const res = await axios.post(`${API_URL}/add`, formData);
|
|
89
|
+
if (!res.data.success) {
|
|
90
|
+
return toast.error(res.data.message);
|
|
91
|
+
}
|
|
92
|
+
toast.success(res.data.message);
|
|
93
|
+
setFormData({
|
|
94
|
+
productCode: "",
|
|
95
|
+
productName: "",
|
|
96
|
+
category: "",
|
|
97
|
+
quantityInStock: "",
|
|
98
|
+
unitPrice: "",
|
|
99
|
+
supplierName: "",
|
|
100
|
+
dateReceived: "",
|
|
101
|
+
warehouse_id: "",
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
toast.error(error.message);
|
|
105
|
+
}
|
|
106
|
+
// About Form
|
|
107
|
+
};
|
|
108
|
+
return (
|
|
109
|
+
<div className="p-1 flex flex-col gap-2 w-full ">
|
|
110
|
+
<div className="bg-white/50 rounded-md px-4 py-2 flex justify-between items-center">
|
|
111
|
+
<h1 className="md:text-xl font-bold text-indigo-500 text-md">
|
|
112
|
+
Product
|
|
113
|
+
</h1>
|
|
114
|
+
<div
|
|
115
|
+
className="p-2 text-white/90 rounded-lg bg-green-500 flex items-center gap-2"
|
|
116
|
+
onClick={() => {
|
|
117
|
+
setModel(true);
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<FaPlus /> <p className="md:block hidden">Add Product</p>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div className="bg-white/50 p-4 rounded-lg block md:hidden">
|
|
125
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
|
126
|
+
{data.map((o, i) => (
|
|
127
|
+
<div className="w-full bg-white p-2 rounded-lg" key={i}>
|
|
128
|
+
<h1 className="text-gray-500">{i + 1}</h1>
|
|
129
|
+
<div className="flex justify-between">
|
|
130
|
+
<h1 className="font-semibold text-indigo-500">Product Code:</h1>
|
|
131
|
+
<p className="text-gray-800">{o.productCode}</p>
|
|
132
|
+
</div>
|
|
133
|
+
<div className="flex justify-between">
|
|
134
|
+
<h1 className="font-semibold text-indigo-500">Product Name:</h1>
|
|
135
|
+
<p className="text-gray-800">{o.productName}</p>
|
|
136
|
+
</div>
|
|
137
|
+
<div className="flex justify-between">
|
|
138
|
+
<h1 className="font-semibold text-indigo-500">Category:</h1>
|
|
139
|
+
<p className="text-gray-800">{o.category}</p>
|
|
140
|
+
</div>
|
|
141
|
+
<div className="flex justify-between">
|
|
142
|
+
<h1 className="font-semibold text-indigo-500">
|
|
143
|
+
Quantity In Stock:
|
|
144
|
+
</h1>
|
|
145
|
+
<p className="text-gray-800">{o.quantityInStock}</p>
|
|
146
|
+
</div>
|
|
147
|
+
<div className="flex justify-between">
|
|
148
|
+
<h1 className="font-semibold text-indigo-500">Unit Price:</h1>
|
|
149
|
+
<p className="text-gray-800">{o.unitPrice}</p>
|
|
150
|
+
</div>
|
|
151
|
+
<div className="flex justify-between gap-2">
|
|
152
|
+
<h1 className="font-semibold text-indigo-500">
|
|
153
|
+
Supplier Name:
|
|
154
|
+
</h1>
|
|
155
|
+
<p className="text-gray-800">{o.supplierName}</p>
|
|
156
|
+
</div>
|
|
157
|
+
<div className="flex justify-between gap-2">
|
|
158
|
+
<h1 className="font-semibold text-indigo-500">
|
|
159
|
+
Date Received:
|
|
160
|
+
</h1>
|
|
161
|
+
<p className="text-gray-800">{o.dateReceived}</p>
|
|
162
|
+
</div>
|
|
163
|
+
<div className="flex justify-between gap-2">
|
|
164
|
+
<h1 className="font-semibold text-indigo-500">
|
|
165
|
+
Warehouse Name:
|
|
166
|
+
</h1>
|
|
167
|
+
<p className="text-gray-800">{o.warehouse_id?.warehouseName}</p>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
))}
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
<div className="bg-white/50 p-4 md:flex flex-col gap-2 rounded-lg hidden ">
|
|
174
|
+
<div className="bg-white p-2 rounded-lg">
|
|
175
|
+
<table className="w-full">
|
|
176
|
+
<thead>
|
|
177
|
+
<tr className="text-sm text-indigo-500">
|
|
178
|
+
<th>No</th>
|
|
179
|
+
<th>Product Code</th>
|
|
180
|
+
<th>Product Name</th>
|
|
181
|
+
<th>Category</th>
|
|
182
|
+
<th>Quantity In Stock</th>
|
|
183
|
+
<th>Unit Price</th>
|
|
184
|
+
<th>Supplier Name</th>
|
|
185
|
+
<th>Date Received</th>
|
|
186
|
+
<th>Warehouse Name</th>
|
|
187
|
+
</tr>
|
|
188
|
+
</thead>
|
|
189
|
+
<tbody>
|
|
190
|
+
{data.map((o, i) => (
|
|
191
|
+
<tr key={i} className="text-sm text-center">
|
|
192
|
+
<td className="px-2 p-2">{i + 1}</td>
|
|
193
|
+
<td className="px-2">{o.productCode} </td>
|
|
194
|
+
<td className="px-2">{o.productName}</td>
|
|
195
|
+
<td className="px-2">{o.category}</td>
|
|
196
|
+
<td className="px-2">{o.quantityInStock}</td>
|
|
197
|
+
<td className="px-2">{o.unitPrice}</td>
|
|
198
|
+
<td className="px-2">{o.supplierName}</td>
|
|
199
|
+
<td className="px-2">{o.dateReceived}</td>
|
|
200
|
+
<td className="px-2">{o.warehouse_id?.warehouseName}</td>
|
|
201
|
+
</tr>
|
|
202
|
+
))}
|
|
203
|
+
</tbody>
|
|
204
|
+
</table>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
{model && (
|
|
208
|
+
<div
|
|
209
|
+
className="fixed flex items-center justify-center bg-indigo-500/35 w-full inset-0"
|
|
210
|
+
onClick={() => {
|
|
211
|
+
setModel(false);
|
|
212
|
+
}}
|
|
213
|
+
>
|
|
214
|
+
<div
|
|
215
|
+
className="bg-white/95 w-120 p-4 rounded-2xl"
|
|
216
|
+
onClick={(e) => {
|
|
217
|
+
e.stopPropagation();
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
<form
|
|
221
|
+
onSubmit={handleSubmit}
|
|
222
|
+
className="flex
|
|
223
|
+
flex-col gap-4 w-full"
|
|
224
|
+
>
|
|
225
|
+
<div className="flex items-center justify-between p-4">
|
|
226
|
+
<h1 className="text-xl font-semibold text-green-500">
|
|
227
|
+
Add Product
|
|
228
|
+
</h1>
|
|
229
|
+
<div
|
|
230
|
+
className=""
|
|
231
|
+
onClick={() => {
|
|
232
|
+
setModel(false);
|
|
233
|
+
}}
|
|
234
|
+
>
|
|
235
|
+
<FaTimesCircle className="text-3xl text-indigo-500" />
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="grid grid-cols-1 gap-2 md:grid-cols-2">
|
|
239
|
+
<div className="flex flex-col gap-1">
|
|
240
|
+
<label
|
|
241
|
+
htmlFor="nationalId"
|
|
242
|
+
className="font-semibold text-md text-blue-400"
|
|
243
|
+
>
|
|
244
|
+
Product Code
|
|
245
|
+
</label>
|
|
246
|
+
<input
|
|
247
|
+
value={formData.productCode}
|
|
248
|
+
name="productCode"
|
|
249
|
+
onChange={handleFormData}
|
|
250
|
+
type="text"
|
|
251
|
+
placeholder="productCode"
|
|
252
|
+
className="px-3 py-1 rounded-md border border-blue-500 focus:outline-blue-300"
|
|
253
|
+
/>
|
|
254
|
+
</div>
|
|
255
|
+
<div className="flex flex-col gap-1">
|
|
256
|
+
<label
|
|
257
|
+
htmlFor="first_name"
|
|
258
|
+
className="font-semibold text-md text-blue-400"
|
|
259
|
+
>
|
|
260
|
+
Product Name
|
|
261
|
+
</label>
|
|
262
|
+
<input
|
|
263
|
+
value={formData.productName}
|
|
264
|
+
onChange={handleFormData}
|
|
265
|
+
type="text"
|
|
266
|
+
name="productName"
|
|
267
|
+
placeholder="productName"
|
|
268
|
+
className="px-3 py-1 rounded-md border border- focus:outline-blue-300"
|
|
269
|
+
/>
|
|
270
|
+
</div>
|
|
271
|
+
<div className="flex flex-col gap-1">
|
|
272
|
+
<label
|
|
273
|
+
htmlFor="last_name"
|
|
274
|
+
className="font-semibold text-md text-blue-400"
|
|
275
|
+
>
|
|
276
|
+
Category
|
|
277
|
+
</label>
|
|
278
|
+
<input
|
|
279
|
+
value={formData.category}
|
|
280
|
+
onChange={handleFormData}
|
|
281
|
+
type="text"
|
|
282
|
+
name="category"
|
|
283
|
+
placeholder="category"
|
|
284
|
+
className="px-3 py-1 rounded-md border border-blue-500 focus:outline-blue-300"
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
<div className="flex flex-col gap-1">
|
|
288
|
+
<label
|
|
289
|
+
htmlFor="email"
|
|
290
|
+
className="font-semibold text-md text-blue-400"
|
|
291
|
+
>
|
|
292
|
+
{" "}
|
|
293
|
+
Quantity In Stock
|
|
294
|
+
</label>
|
|
295
|
+
<input
|
|
296
|
+
value={formData.quantityInStock}
|
|
297
|
+
onChange={handleFormData}
|
|
298
|
+
type="number"
|
|
299
|
+
name="quantityInStock"
|
|
300
|
+
placeholder="quantityInStock"
|
|
301
|
+
className="px-3 py-1 rounded-md border border-blue-500 focus:outline-blue-300"
|
|
302
|
+
/>
|
|
303
|
+
</div>
|
|
304
|
+
<div className="flex flex-col gap-1">
|
|
305
|
+
<label
|
|
306
|
+
htmlFor="telephone"
|
|
307
|
+
className="font-semibold text-md text-blue-400"
|
|
308
|
+
>
|
|
309
|
+
Unit Price
|
|
310
|
+
</label>
|
|
311
|
+
<input
|
|
312
|
+
value={formData.unitPrice}
|
|
313
|
+
type="number"
|
|
314
|
+
onChange={handleFormData}
|
|
315
|
+
name="unitPrice"
|
|
316
|
+
placeholder="unitPrice"
|
|
317
|
+
className="px-3 py-1 rounded-md border border-blue-500 focus:outline-blue-300"
|
|
318
|
+
/>
|
|
319
|
+
</div>
|
|
320
|
+
<div className="flex flex-col gap-1">
|
|
321
|
+
<label
|
|
322
|
+
htmlFor="address"
|
|
323
|
+
className="font-semibold text-md text-blue-400"
|
|
324
|
+
>
|
|
325
|
+
Supplier Name
|
|
326
|
+
</label>
|
|
327
|
+
<input
|
|
328
|
+
value={formData.supplierName}
|
|
329
|
+
onChange={handleFormData}
|
|
330
|
+
type="text"
|
|
331
|
+
name="supplierName"
|
|
332
|
+
placeholder="Kigali / Rwanda - Kicukiro"
|
|
333
|
+
className="px-3 py-1 rounded-md border border-blue-500 focus:outline-blue-300"
|
|
334
|
+
/>
|
|
335
|
+
</div>
|
|
336
|
+
<div className="flex flex-col gap-1">
|
|
337
|
+
<label
|
|
338
|
+
htmlFor="address"
|
|
339
|
+
className="font-semibold text-md text-blue-400"
|
|
340
|
+
>
|
|
341
|
+
Date Received
|
|
342
|
+
</label>
|
|
343
|
+
<input
|
|
344
|
+
value={formData.dateReceived}
|
|
345
|
+
onChange={handleFormData}
|
|
346
|
+
type="datetime-local"
|
|
347
|
+
name="dateReceived"
|
|
348
|
+
placeholder="dateReceived"
|
|
349
|
+
className="px-3 py-1 rounded-md border border-blue-500 focus:outline-blue-300"
|
|
350
|
+
/>
|
|
351
|
+
</div>
|
|
352
|
+
<div className="flex flex-col gap-1">
|
|
353
|
+
<label
|
|
354
|
+
htmlFor="address"
|
|
355
|
+
className="font-semibold text-md text-blue-400"
|
|
356
|
+
>
|
|
357
|
+
Date Received
|
|
358
|
+
</label>
|
|
359
|
+
<select
|
|
360
|
+
name="warehouse_id"
|
|
361
|
+
value={formData.warehouse_id}
|
|
362
|
+
onChange={handleFormData}
|
|
363
|
+
className="px-3 py-1 rounded-md border border-blue-500 focus:outline-blue-300"
|
|
364
|
+
>
|
|
365
|
+
<option value="">Select Warehouse</option>
|
|
366
|
+
{dataW.map((w, i) => (
|
|
367
|
+
<option key={i} value={w._id}>
|
|
368
|
+
{w.warehouseName}
|
|
369
|
+
</option>
|
|
370
|
+
))}
|
|
371
|
+
</select>
|
|
372
|
+
</div>
|
|
373
|
+
</div>
|
|
374
|
+
<button
|
|
375
|
+
type="submit"
|
|
376
|
+
className="bg-green-500 p-2 text-white/90 font-semibold rounded-md hover:rounded-2xl"
|
|
377
|
+
>
|
|
378
|
+
Register Product
|
|
379
|
+
</button>
|
|
380
|
+
</form>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
)}
|
|
384
|
+
</div>
|
|
385
|
+
);
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
export default Product;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
FaClosedCaptioning,
|
|
4
|
+
FaPlus,
|
|
5
|
+
FaTimes,
|
|
6
|
+
FaTimesCircle,
|
|
7
|
+
} from "react-icons/fa";
|
|
8
|
+
import axios from "axios";
|
|
9
|
+
import toast from "react-hot-toast";
|
|
10
|
+
|
|
11
|
+
const Report = () => {
|
|
12
|
+
const port = 3400;
|
|
13
|
+
const API_URL = `http://localhost:${port}/api/warehouse`;
|
|
14
|
+
const API_URL_L = `http://localhost:${port}/api/product`;
|
|
15
|
+
const API_URL_T = `http://localhost:${port}/api/transfer`;
|
|
16
|
+
// End
|
|
17
|
+
// set Data in State From backend
|
|
18
|
+
const [data, setData] = useState([]);
|
|
19
|
+
const [transferData, setTransferData] = useState([]);
|
|
20
|
+
const [landData, setLandData] = useState([]);
|
|
21
|
+
// End
|
|
22
|
+
// About Form
|
|
23
|
+
|
|
24
|
+
const fecthData = async () => {
|
|
25
|
+
try {
|
|
26
|
+
const res = await axios.get(`${API_URL}/get`);
|
|
27
|
+
if (!res.data.success) {
|
|
28
|
+
return toast.error(res.data.message);
|
|
29
|
+
}
|
|
30
|
+
setData(res.data.warehouse);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
alert(error.message);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const fecthDataL = async () => {
|
|
37
|
+
try {
|
|
38
|
+
const res = await axios.get(`${API_URL_L}/get`);
|
|
39
|
+
if (!res.data.success) {
|
|
40
|
+
return toast.error(res.data.message);
|
|
41
|
+
}
|
|
42
|
+
setLandData(res.data.product);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
alert(error.message);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const fecthDataT = async () => {
|
|
49
|
+
try {
|
|
50
|
+
const res = await axios.get(`${API_URL_T}/get`);
|
|
51
|
+
if (!res.data.success) {
|
|
52
|
+
return toast.error(res.data.message);
|
|
53
|
+
}
|
|
54
|
+
setTransferData(res.data.transfer);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
toast.error(error.message);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
fecthDataT();
|
|
62
|
+
fecthData();
|
|
63
|
+
fecthDataL();
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
const dataReport = data.map((w)=>{
|
|
68
|
+
const warehouse = w.warehouseName;
|
|
69
|
+
const totalProduct = landData.filter((p)=>p.warehouse_id?._id === w._id).length
|
|
70
|
+
const totalInStock = landData.filter(
|
|
71
|
+
(pr) => pr.warehouse_id?._id === w._id,
|
|
72
|
+
)[0];
|
|
73
|
+
const totalOutStock = transferData.filter((t) => t.warehouse_id?._id === w._id)[0];
|
|
74
|
+
const warehouseLocation = w.warehouseLocation;
|
|
75
|
+
|
|
76
|
+
return ({
|
|
77
|
+
warehouse,
|
|
78
|
+
totalProduct,
|
|
79
|
+
InStock: totalInStock?.quantityInStock,
|
|
80
|
+
OutStock: totalOutStock?.quantityMoved,
|
|
81
|
+
warehouseLocation
|
|
82
|
+
});
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
console.log(dataReport)
|
|
86
|
+
|
|
87
|
+
// About Table
|
|
88
|
+
return (
|
|
89
|
+
<div className="p-1 flex flex-col gap-2 w-full ">
|
|
90
|
+
<div className="bg-white/50 rounded-md px-4 py-2 flex justify-between items-center">
|
|
91
|
+
<h1 className="md:text-xl font-bold text-indigo-500 text-md">
|
|
92
|
+
Project
|
|
93
|
+
</h1>
|
|
94
|
+
</div>
|
|
95
|
+
<div className="bg-white/50 p-4 rounded-lg block md:hidden">
|
|
96
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
|
97
|
+
{dataReport.map((o, i) => (
|
|
98
|
+
<div className="w-full bg-white p-2 rounded-lg" key={i}>
|
|
99
|
+
<h1 className="text-gray-500">{i + 1}</h1>
|
|
100
|
+
<div className="flex justify-between">
|
|
101
|
+
<h1 className="font-semibold text-indigo-500">Warehouse:</h1>
|
|
102
|
+
<p className="text-gray-800">{o.warehouse}</p>
|
|
103
|
+
</div>
|
|
104
|
+
<div className="flex justify-between">
|
|
105
|
+
<h1 className="font-semibold text-indigo-500">
|
|
106
|
+
Total Product:
|
|
107
|
+
</h1>
|
|
108
|
+
<p className="text-gray-800">{o.totalProduct}</p>
|
|
109
|
+
</div>
|
|
110
|
+
<div className="flex justify-between">
|
|
111
|
+
<h1 className="font-semibold text-indigo-500">In Stock:</h1>
|
|
112
|
+
<p className="text-gray-800">{o.InStock}</p>
|
|
113
|
+
</div>
|
|
114
|
+
<div className="flex justify-between">
|
|
115
|
+
<h1 className="font-semibold text-indigo-500">Out Stock:</h1>
|
|
116
|
+
<p className="text-gray-800">{o.OutStock}</p>
|
|
117
|
+
</div>
|
|
118
|
+
<div className="flex justify-between">
|
|
119
|
+
<h1 className="font-semibold text-indigo-500">
|
|
120
|
+
Warehouse Location:
|
|
121
|
+
</h1>
|
|
122
|
+
<p className="text-gray-800">{o.warehouseLocation}</p>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
))}
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div className="bg-white/50 p-4 md:flex flex-col gap-2 rounded-lg hidden ">
|
|
129
|
+
<div className="bg-white p-2 rounded-lg">
|
|
130
|
+
<table className="w-full">
|
|
131
|
+
<thead>
|
|
132
|
+
<tr className="text-sm text-indigo-500">
|
|
133
|
+
<th>No</th>
|
|
134
|
+
<th>Warehouse</th>
|
|
135
|
+
<th>Total Product</th>
|
|
136
|
+
<th>In Stock</th>
|
|
137
|
+
<th>Out Stock</th>
|
|
138
|
+
<th>Warehouse Location</th>
|
|
139
|
+
</tr>
|
|
140
|
+
</thead>
|
|
141
|
+
<tbody>
|
|
142
|
+
{dataReport.map((o, i) => (
|
|
143
|
+
<tr key={i} className="text-sm text-center">
|
|
144
|
+
<td className="px-2 p-2">{i + 1}</td>
|
|
145
|
+
<td className="px-2">{o.warehouse} </td>
|
|
146
|
+
<td className="px-2">
|
|
147
|
+
{o.totalProduct}
|
|
148
|
+
</td>
|
|
149
|
+
<td className="px-2">{o.InStock}</td>
|
|
150
|
+
<td className="px-2">{o.OutStock}</td>
|
|
151
|
+
<td className="px-2">{o.warehouseLocation}</td>
|
|
152
|
+
</tr>
|
|
153
|
+
))}
|
|
154
|
+
</tbody>
|
|
155
|
+
</table>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export default Report;
|