create-cedro-app 1.0.2 → 1.0.3

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 (69) hide show
  1. package/bin/index.js +32 -18
  2. package/package.json +1 -1
  3. package/templates/invoice-service-management-system/client/README.md +16 -0
  4. package/templates/invoice-service-management-system/client/eslint.config.js +21 -0
  5. package/templates/invoice-service-management-system/client/index.html +13 -0
  6. package/templates/invoice-service-management-system/client/package.json +35 -0
  7. package/templates/invoice-service-management-system/client/public/favicon.svg +1 -0
  8. package/templates/invoice-service-management-system/client/public/icons.svg +24 -0
  9. package/templates/invoice-service-management-system/client/src/App.jsx +15 -0
  10. package/templates/invoice-service-management-system/client/src/assets/hero.png +0 -0
  11. package/templates/invoice-service-management-system/client/src/assets/react.svg +1 -0
  12. package/templates/invoice-service-management-system/client/src/assets/vite.svg +1 -0
  13. package/templates/invoice-service-management-system/client/src/components/AppRoutes.jsx +39 -0
  14. package/templates/invoice-service-management-system/client/src/components/Customer.jsx +326 -0
  15. package/templates/invoice-service-management-system/client/src/components/Dashboard.jsx +512 -0
  16. package/templates/invoice-service-management-system/client/src/components/Invoice.jsx +523 -0
  17. package/templates/invoice-service-management-system/client/src/components/Login.jsx +170 -0
  18. package/templates/invoice-service-management-system/client/src/components/PageNotFound.jsx +11 -0
  19. package/templates/invoice-service-management-system/client/src/components/Register.jsx +171 -0
  20. package/templates/invoice-service-management-system/client/src/components/Report.jsx +383 -0
  21. package/templates/invoice-service-management-system/client/src/components/Service.jsx +390 -0
  22. package/templates/invoice-service-management-system/client/src/index.css +1 -0
  23. package/templates/invoice-service-management-system/client/src/main.jsx +13 -0
  24. package/templates/invoice-service-management-system/client/vite.config.js +9 -0
  25. package/templates/invoice-service-management-system/server/.env +8 -0
  26. package/templates/invoice-service-management-system/server/Functions/Customer.js +79 -0
  27. package/templates/invoice-service-management-system/server/Functions/Invoice.js +192 -0
  28. package/templates/invoice-service-management-system/server/Functions/Service.js +86 -0
  29. package/templates/invoice-service-management-system/server/Functions/dashboard.js +33 -0
  30. package/templates/invoice-service-management-system/server/Functions/report.js +50 -0
  31. package/templates/invoice-service-management-system/server/Functions/users.js +101 -0
  32. package/templates/invoice-service-management-system/server/db.js +22 -0
  33. package/templates/invoice-service-management-system/server/package.json +23 -0
  34. package/templates/invoice-service-management-system/server/server.js +294 -0
  35. package/templates/slot-car-management-system/client/README.md +16 -0
  36. package/templates/slot-car-management-system/client/eslint.config.js +21 -0
  37. package/templates/slot-car-management-system/client/index.html +13 -0
  38. package/templates/slot-car-management-system/client/package.json +35 -0
  39. package/templates/slot-car-management-system/client/public/favicon.svg +1 -0
  40. package/templates/slot-car-management-system/client/public/icons.svg +24 -0
  41. package/templates/slot-car-management-system/client/src/App.css +184 -0
  42. package/templates/slot-car-management-system/client/src/App.jsx +49 -0
  43. package/templates/slot-car-management-system/client/src/assets/hero.png +0 -0
  44. package/templates/slot-car-management-system/client/src/assets/react.svg +1 -0
  45. package/templates/slot-car-management-system/client/src/assets/vite.svg +1 -0
  46. package/templates/slot-car-management-system/client/src/components/Cars.jsx +246 -0
  47. package/templates/slot-car-management-system/client/src/components/Dashboard.jsx +629 -0
  48. package/templates/slot-car-management-system/client/src/components/Login.jsx +170 -0
  49. package/templates/slot-car-management-system/client/src/components/PageNotFound.jsx +11 -0
  50. package/templates/slot-car-management-system/client/src/components/ParkingRecord.jsx +553 -0
  51. package/templates/slot-car-management-system/client/src/components/ParkingSlot.jsx +268 -0
  52. package/templates/slot-car-management-system/client/src/components/Payment.jsx +464 -0
  53. package/templates/slot-car-management-system/client/src/components/Register.jsx +171 -0
  54. package/templates/slot-car-management-system/client/src/components/Report.jsx +407 -0
  55. package/templates/slot-car-management-system/client/src/index.css +1 -0
  56. package/templates/slot-car-management-system/client/src/main.jsx +10 -0
  57. package/templates/slot-car-management-system/client/vite.config.js +9 -0
  58. package/templates/slot-car-management-system/parking_slot.sql +218 -0
  59. package/templates/slot-car-management-system/server/.env +8 -0
  60. package/templates/slot-car-management-system/server/Functions/Payment.js +107 -0
  61. package/templates/slot-car-management-system/server/Functions/car.js +93 -0
  62. package/templates/slot-car-management-system/server/Functions/dashboard.js +64 -0
  63. package/templates/slot-car-management-system/server/Functions/parkingRecord.js +220 -0
  64. package/templates/slot-car-management-system/server/Functions/parkingslot.js +58 -0
  65. package/templates/slot-car-management-system/server/Functions/report.js +48 -0
  66. package/templates/slot-car-management-system/server/Functions/users.js +101 -0
  67. package/templates/slot-car-management-system/server/db.js +22 -0
  68. package/templates/slot-car-management-system/server/package.json +23 -0
  69. package/templates/slot-car-management-system/server/server.js +192 -0
@@ -0,0 +1,170 @@
1
+ import axios from "axios";
2
+ import { useState } from "react";
3
+ import { useNavigate, Link } from "react-router-dom";
4
+ import { toast } from "react-toastify";
5
+
6
+ import { Wrench, Mail, Lock } from "lucide-react";
7
+
8
+ function Login() {
9
+
10
+ const navigate = useNavigate();
11
+
12
+ const [error, setError] = useState("");
13
+
14
+ const [values, setValues] = useState({
15
+ Email: "",
16
+ Password: ""
17
+ });
18
+
19
+ // =========================
20
+ // LOGIN HANDLER
21
+ // =========================
22
+ const HandleLogin = async (e) => {
23
+
24
+ e.preventDefault();
25
+
26
+
27
+
28
+ await axios.post(
29
+ "http://localhost:3000/login",
30
+ values
31
+ )
32
+ .then((res)=>{
33
+ // SAVE TOKEN
34
+ localStorage.setItem(
35
+ "token",
36
+ res.data.token
37
+ );
38
+
39
+ console.log(res.data);
40
+
41
+ toast.success(res.data.Message);
42
+
43
+ navigate("/dashboard");
44
+ })
45
+
46
+
47
+
48
+ .catch((error)=>{
49
+ setError(error.response?.data?.Error);
50
+
51
+ toast.error(
52
+ error.response?.data?.Error
53
+ );
54
+ })
55
+
56
+
57
+ }
58
+
59
+
60
+
61
+ return (
62
+
63
+ <div className="min-h-screen flex items-center justify-center bg-gray-100">
64
+
65
+ <form
66
+ onSubmit={HandleLogin}
67
+ className="w-[420px] bg-white rounded-3xl shadow-2xl p-10 border-t-[6px] border-indigo-600"
68
+ >
69
+
70
+ <div className="text-center mb-8">
71
+
72
+ <div className="flex justify-center mb-3">
73
+ <Wrench
74
+ size={45}
75
+ className="text-indigo-600"
76
+ />
77
+ </div>
78
+
79
+ <h2 className="text-3xl font-bold text-gray-800">
80
+ SmartPark Login
81
+ </h2>
82
+
83
+ <p className="text-gray-500 mt-2">
84
+ Car Repair Payment Management System
85
+ </p>
86
+
87
+ </div>
88
+
89
+
90
+ {/* ERROR */}
91
+ {
92
+ error &&
93
+ <p className="text-red-500 mb-4">
94
+ {error}
95
+ </p>
96
+ }
97
+
98
+
99
+ {/* EMAIL */}
100
+ <div className="mb-4 relative">
101
+
102
+ <Mail className="absolute top-3 left-3 text-gray-400" />
103
+
104
+ <input
105
+ type="email"
106
+ placeholder="Enter Email"
107
+ className="w-full border pl-10 p-3 rounded-xl"
108
+ onChange={(e) =>
109
+ setValues({
110
+ ...values,
111
+ Email: e.target.value
112
+ })
113
+ }
114
+ required
115
+ />
116
+
117
+ </div>
118
+
119
+
120
+ {/* PASSWORD */}
121
+ <div className="mb-6 relative">
122
+
123
+ <Lock className="absolute top-3 left-3 text-gray-400" />
124
+
125
+ <input
126
+ type="password"
127
+ placeholder="Enter Password"
128
+ className="w-full border pl-10 p-3 rounded-xl"
129
+ onChange={(e) =>
130
+ setValues({
131
+ ...values,
132
+ Password: e.target.value
133
+ })
134
+ }
135
+ required
136
+ />
137
+
138
+ </div>
139
+
140
+
141
+ {/* BUTTON */}
142
+ <button
143
+ type="submit"
144
+ className="w-full bg-indigo-600 text-white p-3 rounded-xl"
145
+ >
146
+ Login to System
147
+ </button>
148
+
149
+
150
+ {/* REGISTER */}
151
+ <p className="mt-6 text-center text-gray-600">
152
+
153
+ No account?
154
+
155
+ <Link
156
+ to="/register"
157
+ className="text-indigo-600 font-semibold ml-2"
158
+ >
159
+ Register
160
+ </Link>
161
+
162
+ </p>
163
+
164
+ </form>
165
+
166
+ </div>
167
+ );
168
+ }
169
+
170
+ export default Login;
@@ -0,0 +1,11 @@
1
+ import React from 'react'
2
+
3
+ function PageNotFound() {
4
+ return (
5
+ <div className='flex items-center justify-center min-h-screen bg-gray-200'>
6
+ <h2 className='text-red-700 text-[90px]'>Page Not Found <span>404</span></h2>
7
+ </div>
8
+ )
9
+ }
10
+
11
+ export default PageNotFound
@@ -0,0 +1,553 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import axios from "axios";
3
+ import { toast } from "react-toastify";
4
+ import {
5
+ Trash2,
6
+ Pencil,
7
+ CarFront,
8
+ } from "lucide-react";
9
+ import { useNavigate } from "react-router-dom";
10
+
11
+ function ParkingRecord() {
12
+
13
+ const token = localStorage.getItem("token");
14
+
15
+ const navigate = useNavigate();
16
+
17
+ // =========================
18
+ // CHECK TOKEN
19
+ // =========================
20
+ useEffect(() => {
21
+
22
+ const token = localStorage.getItem("token");
23
+
24
+ if (!token) {
25
+ navigate("/");
26
+ }
27
+
28
+ }, [navigate]);
29
+
30
+
31
+
32
+ // =========================
33
+ // STATES
34
+ // =========================
35
+ const [cars, setCars] = useState([]);
36
+
37
+ const [slots, setSlots] = useState([]);
38
+
39
+ const [records, setRecords] = useState([]);
40
+
41
+ const [editId, setEditId] = useState(null);
42
+
43
+ const [values, setValues] = useState({
44
+ PlateNumber: "",
45
+ SlotNumber: "",
46
+ EntryTime: "",
47
+ ExitTime: ""
48
+ });
49
+
50
+
51
+
52
+ // =========================
53
+ // FETCH CARS
54
+ // =========================
55
+ const fetchCars = async () => {
56
+
57
+ try {
58
+
59
+ const res = await axios.get(
60
+ "http://localhost:3000/selectcars",
61
+ {
62
+ headers: {
63
+ Authorization: `Bearer ${token}`
64
+ }
65
+ }
66
+ );
67
+
68
+ setCars(res.data || []);
69
+
70
+ } catch (error) {
71
+
72
+ toast.error("Failed to load cars");
73
+ }
74
+ };
75
+
76
+
77
+
78
+ // =========================
79
+ // FETCH SLOTS
80
+ // =========================
81
+ const fetchSlots = async () => {
82
+
83
+ try {
84
+
85
+ const res = await axios.get(
86
+ "http://localhost:3000/selectservices",
87
+ {
88
+ headers: {
89
+ Authorization: `Bearer ${token}`
90
+ }
91
+ }
92
+ );
93
+
94
+ setSlots(res.data || []);
95
+
96
+ } catch (error) {
97
+
98
+ toast.error("Failed to load parking slots");
99
+ }
100
+ };
101
+
102
+
103
+
104
+ // =========================
105
+ // FETCH RECORDS
106
+ // =========================
107
+ const fetchRecords = async () => {
108
+
109
+ try {
110
+
111
+ const res = await axios.get(
112
+ "http://localhost:3000/selectparkingrecords",
113
+ {
114
+ headers: {
115
+ Authorization: `Bearer ${token}`
116
+ }
117
+ }
118
+ );
119
+
120
+ setRecords(res.data || []);
121
+
122
+ } catch (error) {
123
+
124
+ toast.error("Failed to load parking records");
125
+ }
126
+ };
127
+
128
+
129
+
130
+ // =========================
131
+ // LOAD DATA
132
+ // =========================
133
+ useEffect(() => {
134
+
135
+ fetchCars();
136
+
137
+ fetchSlots();
138
+
139
+ fetchRecords();
140
+
141
+ }, []);
142
+
143
+
144
+
145
+ // =========================
146
+ // INSERT / UPDATE
147
+ // =========================
148
+ const handleSubmit = async (e) => {
149
+
150
+ e.preventDefault();
151
+
152
+ try {
153
+
154
+ // UPDATE
155
+ if (editId) {
156
+
157
+ await axios.put(
158
+ `http://localhost:3000/updateparkingrecords/${editId}`,
159
+ values,
160
+ {
161
+ headers: {
162
+ Authorization: `Bearer ${token}`
163
+ }
164
+ }
165
+ );
166
+
167
+ toast.success("Parking record updated");
168
+
169
+ setEditId(null);
170
+
171
+ } else {
172
+
173
+ // INSERT
174
+ await axios.post(
175
+ "http://localhost:3000/insertparkingrecords",
176
+ values,
177
+ {
178
+ headers: {
179
+ Authorization: `Bearer ${token}`
180
+ }
181
+ }
182
+ );
183
+
184
+ toast.success("Parking record created");
185
+ }
186
+
187
+ // RESET FORM
188
+ setValues({
189
+ PlateNumber: "",
190
+ SlotNumber: "",
191
+ EntryTime: "",
192
+ ExitTime: ""
193
+ });
194
+
195
+ fetchRecords();
196
+
197
+ } catch (error) {
198
+
199
+ toast.error(
200
+ error.response?.data?.Error ||
201
+ "Error saving parking record"
202
+ );
203
+ }
204
+ };
205
+
206
+
207
+
208
+ // =========================
209
+ // DELETE
210
+ // =========================
211
+ const deleteRecord = async (id) => {
212
+
213
+ try {
214
+
215
+ await axios.delete(
216
+ `http://localhost:3000/deleteparkingrecords/${id}`,
217
+ {
218
+ headers: {
219
+ Authorization: `Bearer ${token}`
220
+ }
221
+ }
222
+ );
223
+
224
+ toast.success("Parking record deleted");
225
+
226
+ fetchRecords();
227
+
228
+ } catch (error) {
229
+
230
+ toast.error("Delete failed");
231
+ }
232
+ };
233
+
234
+
235
+
236
+ // =========================
237
+ // EDIT
238
+ // =========================
239
+ const editRecord = (rec) => {
240
+
241
+ setValues({
242
+ PlateNumber: rec.PlateNumber,
243
+ SlotNumber: rec.SlotNumber,
244
+ EntryTime: rec.EntryTime,
245
+ ExitTime: rec.ExitTime
246
+ });
247
+
248
+ setEditId(rec.recordNumber);
249
+ };
250
+
251
+
252
+
253
+ return (
254
+
255
+ <div className="p-6">
256
+
257
+ {/* HEADER */}
258
+ <div className="mb-6">
259
+
260
+ <h1 className="text-3xl font-bold text-gray-800">
261
+ Parking Records
262
+ </h1>
263
+
264
+ <p className="text-gray-500 mt-1">
265
+ Manage car parking entry and exit records
266
+ </p>
267
+
268
+ </div>
269
+
270
+
271
+
272
+ {/* FORM */}
273
+ <div className="bg-white p-8 rounded-2xl shadow-lg mb-8 border">
274
+
275
+ <div className="flex items-center gap-3 mb-6">
276
+
277
+ <CarFront
278
+ className="text-indigo-600"
279
+ size={30}
280
+ />
281
+
282
+ <h2 className="text-2xl font-bold text-indigo-600">
283
+
284
+ {editId
285
+ ? "Update Parking Record"
286
+ : "Add Parking Record"}
287
+
288
+ </h2>
289
+
290
+ </div>
291
+
292
+
293
+
294
+ <form
295
+ onSubmit={handleSubmit}
296
+ className="grid grid-cols-1 md:grid-cols-2 gap-5"
297
+ >
298
+
299
+ {/* CAR */}
300
+ <select
301
+ className="border p-3 rounded-xl"
302
+ value={values.PlateNumber}
303
+ onChange={(e) =>
304
+ setValues({
305
+ ...values,
306
+ PlateNumber: e.target.value
307
+ })
308
+ }
309
+ required
310
+ >
311
+
312
+ <option value="">
313
+ Select Car
314
+ </option>
315
+
316
+ {cars.map((car) => (
317
+
318
+ <option
319
+ key={car.PlateNumber}
320
+ value={car.PlateNumber}
321
+ >
322
+
323
+ {car.PlateNumber}
324
+
325
+ </option>
326
+
327
+ ))}
328
+
329
+ </select>
330
+
331
+
332
+
333
+ {/* SLOT */}
334
+ <select
335
+ className="border p-3 rounded-xl"
336
+ value={values.SlotNumber}
337
+ onChange={(e) =>
338
+ setValues({
339
+ ...values,
340
+ SlotNumber: e.target.value
341
+ })
342
+ }
343
+ required
344
+ >
345
+
346
+ <option value="">
347
+ Select Parking Slot
348
+ </option>
349
+
350
+ {slots.map((slot) => (
351
+
352
+ <option
353
+ key={slot.SlotNumber}
354
+ value={slot.SlotNumber}
355
+ >
356
+
357
+ {slot.SlotNumber}
358
+
359
+ </option>
360
+
361
+ ))}
362
+
363
+ </select>
364
+
365
+
366
+
367
+ {/* ENTRY TIME */}
368
+ <input
369
+ type="datetime-local"
370
+ className="border p-3 rounded-xl"
371
+ value={values.EntryTime}
372
+ onChange={(e) =>
373
+ setValues({
374
+ ...values,
375
+ EntryTime: e.target.value
376
+ })
377
+ }
378
+ required
379
+ />
380
+
381
+
382
+
383
+ {/* EXIT TIME */}
384
+ <input
385
+ type="datetime-local"
386
+ className="border p-3 rounded-xl"
387
+ value={values.ExitTime}
388
+ onChange={(e) =>
389
+ setValues({
390
+ ...values,
391
+ ExitTime: e.target.value
392
+ })
393
+ }
394
+ required
395
+ />
396
+
397
+
398
+
399
+ {/* BUTTON */}
400
+ <button
401
+ className={`text-white p-3 rounded-xl font-semibold ${
402
+ editId
403
+ ? "bg-green-600 hover:bg-green-700"
404
+ : "bg-indigo-600 hover:bg-indigo-700"
405
+ }`}
406
+ >
407
+
408
+ {editId
409
+ ? "Update Record"
410
+ : "Save Record"}
411
+
412
+ </button>
413
+
414
+ </form>
415
+
416
+ </div>
417
+
418
+
419
+
420
+ {/* TABLE */}
421
+ <div className="bg-white rounded-2xl shadow-lg overflow-hidden border">
422
+
423
+ <div className="p-6 border-b">
424
+
425
+ <h2 className="text-2xl font-bold">
426
+ Parking Records List
427
+ </h2>
428
+
429
+ </div>
430
+
431
+
432
+
433
+ <table className="w-full">
434
+
435
+ <thead className="bg-gray-100">
436
+
437
+ <tr>
438
+
439
+ <th className="p-3">
440
+ Plate Number
441
+ </th>
442
+
443
+ <th className="p-3">
444
+ Slot Number
445
+ </th>
446
+
447
+ <th className="p-3">
448
+ Entry Time
449
+ </th>
450
+
451
+ <th className="p-3">
452
+ Exit Time
453
+ </th>
454
+
455
+ <th className="p-3">
456
+ Duration
457
+ </th>
458
+
459
+ <th className="p-3 text-center">
460
+ Actions
461
+ </th>
462
+
463
+ </tr>
464
+
465
+ </thead>
466
+
467
+
468
+
469
+ <tbody>
470
+
471
+ {records.length > 0 ? (
472
+
473
+ records.map((rec) => (
474
+
475
+ <tr
476
+ key={rec.recordNumber}
477
+ className="text-center border-t"
478
+ >
479
+
480
+ <td className="p-3">
481
+ {rec.PlateNumber}
482
+ </td>
483
+
484
+ <td className="p-3">
485
+ {rec.SlotNumber}
486
+ </td>
487
+
488
+ <td className="p-3">
489
+ {rec.EntryTime}
490
+ </td>
491
+
492
+ <td className="p-3">
493
+ {rec.ExitTime}
494
+ </td>
495
+
496
+ <td className="p-3">
497
+ {rec.Duration} Hours
498
+ </td>
499
+
500
+ <td className="p-3">
501
+
502
+ <div className="flex justify-center gap-3">
503
+
504
+ <button
505
+ onClick={() => editRecord(rec)}
506
+ className="bg-blue-500 text-white p-2 rounded"
507
+ >
508
+ <Pencil size={18} />
509
+ </button>
510
+
511
+ <button
512
+ onClick={() =>
513
+ deleteRecord(rec.recordNumber)
514
+ }
515
+ className="bg-red-500 text-white p-2 rounded"
516
+ >
517
+ <Trash2 size={18} />
518
+ </button>
519
+
520
+ </div>
521
+
522
+ </td>
523
+
524
+ </tr>
525
+
526
+ ))
527
+
528
+ ) : (
529
+
530
+ <tr>
531
+
532
+ <td
533
+ colSpan="6"
534
+ className="text-center p-4 text-gray-500"
535
+ >
536
+ No parking records found
537
+ </td>
538
+
539
+ </tr>
540
+
541
+ )}
542
+
543
+ </tbody>
544
+
545
+ </table>
546
+
547
+ </div>
548
+
549
+ </div>
550
+ );
551
+ }
552
+
553
+ export default ParkingRecord;