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.
- package/bin/index.js +32 -18
- package/package.json +1 -1
- package/templates/invoice-service-management-system/client/README.md +16 -0
- package/templates/invoice-service-management-system/client/eslint.config.js +21 -0
- package/templates/invoice-service-management-system/client/index.html +13 -0
- package/templates/invoice-service-management-system/client/package.json +35 -0
- package/templates/invoice-service-management-system/client/public/favicon.svg +1 -0
- package/templates/invoice-service-management-system/client/public/icons.svg +24 -0
- package/templates/invoice-service-management-system/client/src/App.jsx +15 -0
- package/templates/invoice-service-management-system/client/src/assets/hero.png +0 -0
- package/templates/invoice-service-management-system/client/src/assets/react.svg +1 -0
- package/templates/invoice-service-management-system/client/src/assets/vite.svg +1 -0
- package/templates/invoice-service-management-system/client/src/components/AppRoutes.jsx +39 -0
- package/templates/invoice-service-management-system/client/src/components/Customer.jsx +326 -0
- package/templates/invoice-service-management-system/client/src/components/Dashboard.jsx +512 -0
- package/templates/invoice-service-management-system/client/src/components/Invoice.jsx +523 -0
- package/templates/invoice-service-management-system/client/src/components/Login.jsx +170 -0
- package/templates/invoice-service-management-system/client/src/components/PageNotFound.jsx +11 -0
- package/templates/invoice-service-management-system/client/src/components/Register.jsx +171 -0
- package/templates/invoice-service-management-system/client/src/components/Report.jsx +383 -0
- package/templates/invoice-service-management-system/client/src/components/Service.jsx +390 -0
- package/templates/invoice-service-management-system/client/src/index.css +1 -0
- package/templates/invoice-service-management-system/client/src/main.jsx +13 -0
- package/templates/invoice-service-management-system/client/vite.config.js +9 -0
- package/templates/invoice-service-management-system/server/.env +8 -0
- package/templates/invoice-service-management-system/server/Functions/Customer.js +79 -0
- package/templates/invoice-service-management-system/server/Functions/Invoice.js +192 -0
- package/templates/invoice-service-management-system/server/Functions/Service.js +86 -0
- package/templates/invoice-service-management-system/server/Functions/dashboard.js +33 -0
- package/templates/invoice-service-management-system/server/Functions/report.js +50 -0
- package/templates/invoice-service-management-system/server/Functions/users.js +101 -0
- package/templates/invoice-service-management-system/server/db.js +22 -0
- package/templates/invoice-service-management-system/server/package.json +23 -0
- package/templates/invoice-service-management-system/server/server.js +294 -0
- package/templates/slot-car-management-system/client/README.md +16 -0
- package/templates/slot-car-management-system/client/eslint.config.js +21 -0
- package/templates/slot-car-management-system/client/index.html +13 -0
- package/templates/slot-car-management-system/client/package.json +35 -0
- package/templates/slot-car-management-system/client/public/favicon.svg +1 -0
- package/templates/slot-car-management-system/client/public/icons.svg +24 -0
- package/templates/slot-car-management-system/client/src/App.css +184 -0
- package/templates/slot-car-management-system/client/src/App.jsx +49 -0
- package/templates/slot-car-management-system/client/src/assets/hero.png +0 -0
- package/templates/slot-car-management-system/client/src/assets/react.svg +1 -0
- package/templates/slot-car-management-system/client/src/assets/vite.svg +1 -0
- package/templates/slot-car-management-system/client/src/components/Cars.jsx +246 -0
- package/templates/slot-car-management-system/client/src/components/Dashboard.jsx +629 -0
- package/templates/slot-car-management-system/client/src/components/Login.jsx +170 -0
- package/templates/slot-car-management-system/client/src/components/PageNotFound.jsx +11 -0
- package/templates/slot-car-management-system/client/src/components/ParkingRecord.jsx +553 -0
- package/templates/slot-car-management-system/client/src/components/ParkingSlot.jsx +268 -0
- package/templates/slot-car-management-system/client/src/components/Payment.jsx +464 -0
- package/templates/slot-car-management-system/client/src/components/Register.jsx +171 -0
- package/templates/slot-car-management-system/client/src/components/Report.jsx +407 -0
- package/templates/slot-car-management-system/client/src/index.css +1 -0
- package/templates/slot-car-management-system/client/src/main.jsx +10 -0
- package/templates/slot-car-management-system/client/vite.config.js +9 -0
- package/templates/slot-car-management-system/parking_slot.sql +218 -0
- package/templates/slot-car-management-system/server/.env +8 -0
- package/templates/slot-car-management-system/server/Functions/Payment.js +107 -0
- package/templates/slot-car-management-system/server/Functions/car.js +93 -0
- package/templates/slot-car-management-system/server/Functions/dashboard.js +64 -0
- package/templates/slot-car-management-system/server/Functions/parkingRecord.js +220 -0
- package/templates/slot-car-management-system/server/Functions/parkingslot.js +58 -0
- package/templates/slot-car-management-system/server/Functions/report.js +48 -0
- package/templates/slot-car-management-system/server/Functions/users.js +101 -0
- package/templates/slot-car-management-system/server/db.js +22 -0
- package/templates/slot-car-management-system/server/package.json +23 -0
- package/templates/slot-car-management-system/server/server.js +192 -0
|
@@ -0,0 +1,171 @@
|
|
|
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, User, Mail, Lock } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
function Register() {
|
|
9
|
+
|
|
10
|
+
const navigate = useNavigate();
|
|
11
|
+
|
|
12
|
+
const [values, setValues] = useState({
|
|
13
|
+
Name: "",
|
|
14
|
+
Email: "",
|
|
15
|
+
Password: ""
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// =========================
|
|
19
|
+
// REGISTER HANDLER
|
|
20
|
+
// =========================
|
|
21
|
+
const HandleRegister = async (e) => {
|
|
22
|
+
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
|
|
25
|
+
axios.post(
|
|
26
|
+
"http://localhost:3000/register",
|
|
27
|
+
values
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
.then((res)=>{
|
|
31
|
+
toast.success(res.data.Message);
|
|
32
|
+
|
|
33
|
+
navigate("/");
|
|
34
|
+
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
.catch((error)=>{
|
|
39
|
+
toast.error(
|
|
40
|
+
error.response?.data?.Error
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
console.log(error);
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
|
|
53
|
+
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
|
54
|
+
|
|
55
|
+
{/* CARD */}
|
|
56
|
+
<form
|
|
57
|
+
onSubmit={HandleRegister}
|
|
58
|
+
className="w-[420px] bg-white rounded-3xl shadow-2xl p-10 border-t-[6px] border-indigo-600"
|
|
59
|
+
>
|
|
60
|
+
|
|
61
|
+
{/* HEADER */}
|
|
62
|
+
<div className="text-center mb-8">
|
|
63
|
+
|
|
64
|
+
<div className="flex justify-center mb-3">
|
|
65
|
+
<Wrench size={45} className="text-indigo-600" />
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<h2 className="text-3xl font-bold text-gray-800">
|
|
69
|
+
SmartPark Register
|
|
70
|
+
</h2>
|
|
71
|
+
|
|
72
|
+
<p className="text-gray-500 mt-2">
|
|
73
|
+
Create new account for CRPMS system
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
{/* NAME */}
|
|
80
|
+
<div className="mb-4 relative">
|
|
81
|
+
|
|
82
|
+
<User className="absolute top-3 left-3 text-gray-400" />
|
|
83
|
+
|
|
84
|
+
<input
|
|
85
|
+
type="text"
|
|
86
|
+
placeholder="Full Name"
|
|
87
|
+
className="w-full border pl-10 p-3 rounded-xl focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
|
88
|
+
onChange={(e) =>
|
|
89
|
+
setValues({
|
|
90
|
+
...values,
|
|
91
|
+
Name: e.target.value
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
required
|
|
95
|
+
/>
|
|
96
|
+
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
{/* EMAIL */}
|
|
101
|
+
<div className="mb-4 relative">
|
|
102
|
+
|
|
103
|
+
<Mail className="absolute top-3 left-3 text-gray-400" />
|
|
104
|
+
|
|
105
|
+
<input
|
|
106
|
+
type="email"
|
|
107
|
+
placeholder="Email Address"
|
|
108
|
+
className="w-full border pl-10 p-3 rounded-xl focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
|
109
|
+
onChange={(e) =>
|
|
110
|
+
setValues({
|
|
111
|
+
...values,
|
|
112
|
+
Email: e.target.value
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
required
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
{/* PASSWORD */}
|
|
122
|
+
<div className="mb-6 relative">
|
|
123
|
+
|
|
124
|
+
<Lock className="absolute top-3 left-3 text-gray-400" />
|
|
125
|
+
|
|
126
|
+
<input
|
|
127
|
+
type="password"
|
|
128
|
+
placeholder="Password"
|
|
129
|
+
className="w-full border pl-10 p-3 rounded-xl focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
|
130
|
+
onChange={(e) =>
|
|
131
|
+
setValues({
|
|
132
|
+
...values,
|
|
133
|
+
Password: e.target.value
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
required
|
|
137
|
+
/>
|
|
138
|
+
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
{/* BUTTON */}
|
|
143
|
+
<button
|
|
144
|
+
type="submit"
|
|
145
|
+
className="w-full bg-indigo-600 hover:bg-indigo-700 text-white p-3 rounded-xl font-semibold transition"
|
|
146
|
+
>
|
|
147
|
+
Create Account
|
|
148
|
+
</button>
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
{/* LOGIN LINK */}
|
|
152
|
+
<p className="mt-6 text-center text-gray-600">
|
|
153
|
+
|
|
154
|
+
Already have an account?
|
|
155
|
+
|
|
156
|
+
<Link
|
|
157
|
+
to="/"
|
|
158
|
+
className="text-indigo-600 font-semibold ml-2"
|
|
159
|
+
>
|
|
160
|
+
Login
|
|
161
|
+
</Link>
|
|
162
|
+
|
|
163
|
+
</p>
|
|
164
|
+
|
|
165
|
+
</form>
|
|
166
|
+
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default Register;
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import { useNavigate } from "react-router-dom";
|
|
4
|
+
import {
|
|
5
|
+
FileBarChart,
|
|
6
|
+
Car,
|
|
7
|
+
DollarSign,
|
|
8
|
+
Wrench
|
|
9
|
+
} from "lucide-react";
|
|
10
|
+
|
|
11
|
+
import jsPDF from "jspdf";
|
|
12
|
+
import autoTable from "jspdf-autotable";
|
|
13
|
+
|
|
14
|
+
function Report() {
|
|
15
|
+
|
|
16
|
+
const token=localStorage.getItem("token")
|
|
17
|
+
const navigate=useNavigate()
|
|
18
|
+
useEffect(()=>{
|
|
19
|
+
const token=localStorage.getItem("token");
|
|
20
|
+
if(!token) {
|
|
21
|
+
navigate('/')
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// =========================
|
|
26
|
+
// STATE
|
|
27
|
+
// =========================
|
|
28
|
+
const [report, setReport] = useState([]);
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// =========================
|
|
33
|
+
// FETCH REPORT
|
|
34
|
+
// =========================
|
|
35
|
+
const fetchReport = async () => {
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
|
|
39
|
+
const res = await axios.get(
|
|
40
|
+
"http://localhost:3000/report",
|
|
41
|
+
{
|
|
42
|
+
headers:{
|
|
43
|
+
Authorization:`Bearer ${token}`
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// IMPORTANT
|
|
49
|
+
setReport(res.data.data);
|
|
50
|
+
|
|
51
|
+
} catch (error) {
|
|
52
|
+
|
|
53
|
+
console.log(error);
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
|
|
62
|
+
fetchReport();
|
|
63
|
+
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
// =========================
|
|
70
|
+
// TOTAL AMOUNT
|
|
71
|
+
// =========================
|
|
72
|
+
const totalAmount = report.reduce(
|
|
73
|
+
|
|
74
|
+
(total, item) =>
|
|
75
|
+
|
|
76
|
+
total + Number(item.AmountPaid),
|
|
77
|
+
|
|
78
|
+
0
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
// =========================
|
|
84
|
+
// GENERATE PDF
|
|
85
|
+
// =========================
|
|
86
|
+
const generatePDF = () => {
|
|
87
|
+
|
|
88
|
+
const doc = new jsPDF();
|
|
89
|
+
|
|
90
|
+
// TITLE
|
|
91
|
+
doc.setFontSize(18);
|
|
92
|
+
|
|
93
|
+
doc.text(
|
|
94
|
+
"SmartPark Daily Report",
|
|
95
|
+
14,
|
|
96
|
+
20
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
// TABLE
|
|
102
|
+
autoTable(doc, {
|
|
103
|
+
|
|
104
|
+
startY: 30,
|
|
105
|
+
|
|
106
|
+
head: [[
|
|
107
|
+
"Plate Number",
|
|
108
|
+
"Amount Paid",
|
|
109
|
+
"Payment Date"
|
|
110
|
+
]],
|
|
111
|
+
|
|
112
|
+
body: report.map((r) => [
|
|
113
|
+
|
|
114
|
+
r.PlateNumber,
|
|
115
|
+
r.AmountPaid + " RWF",
|
|
116
|
+
r.PaymentDate
|
|
117
|
+
|
|
118
|
+
])
|
|
119
|
+
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// SAVE PDF
|
|
123
|
+
doc.save("Daily_Report.pdf");
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
|
|
131
|
+
<div className="p-6 bg-gray-100 min-h-screen">
|
|
132
|
+
|
|
133
|
+
{/* HEADER */}
|
|
134
|
+
<div className="mb-8">
|
|
135
|
+
|
|
136
|
+
<div className="flex items-center gap-3">
|
|
137
|
+
|
|
138
|
+
<FileBarChart
|
|
139
|
+
className="text-indigo-600"
|
|
140
|
+
size={35}
|
|
141
|
+
/>
|
|
142
|
+
|
|
143
|
+
<div>
|
|
144
|
+
|
|
145
|
+
<h1 className="text-3xl font-bold text-gray-800">
|
|
146
|
+
SmartPark Daily Report
|
|
147
|
+
</h1>
|
|
148
|
+
|
|
149
|
+
<p className="text-gray-500 mt-1">
|
|
150
|
+
Car Slot Payment Summary
|
|
151
|
+
</p>
|
|
152
|
+
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
{/* SUMMARY CARDS */}
|
|
163
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
|
164
|
+
|
|
165
|
+
{/* TOTAL CARS */}
|
|
166
|
+
<div className="bg-white p-6 rounded-2xl shadow-md">
|
|
167
|
+
|
|
168
|
+
<div className="flex items-center justify-between">
|
|
169
|
+
|
|
170
|
+
<div>
|
|
171
|
+
|
|
172
|
+
<p className="text-gray-500">
|
|
173
|
+
Total Cars
|
|
174
|
+
</p>
|
|
175
|
+
|
|
176
|
+
<h1 className="text-4xl font-bold text-indigo-600 mt-2">
|
|
177
|
+
{report.length}
|
|
178
|
+
</h1>
|
|
179
|
+
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<div className="bg-indigo-100 p-4 rounded-full">
|
|
183
|
+
|
|
184
|
+
<Car
|
|
185
|
+
className="text-indigo-600"
|
|
186
|
+
size={30}
|
|
187
|
+
/>
|
|
188
|
+
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
{/* TOTAL PAYMENTS */}
|
|
199
|
+
<div className="bg-white p-6 rounded-2xl shadow-md">
|
|
200
|
+
|
|
201
|
+
<div className="flex items-center justify-between">
|
|
202
|
+
|
|
203
|
+
<div>
|
|
204
|
+
|
|
205
|
+
<p className="text-gray-500">
|
|
206
|
+
Total Payments
|
|
207
|
+
</p>
|
|
208
|
+
|
|
209
|
+
<h1 className="text-3xl font-bold text-green-600 mt-2">
|
|
210
|
+
{totalAmount.toLocaleString()} RWF
|
|
211
|
+
</h1>
|
|
212
|
+
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
<div className="bg-green-100 p-4 rounded-full">
|
|
216
|
+
|
|
217
|
+
<DollarSign
|
|
218
|
+
className="text-green-600"
|
|
219
|
+
size={30}
|
|
220
|
+
/>
|
|
221
|
+
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
{/* SERVICES */}
|
|
232
|
+
<div className="bg-white p-6 rounded-2xl shadow-md">
|
|
233
|
+
|
|
234
|
+
<div className="flex items-center justify-between">
|
|
235
|
+
|
|
236
|
+
<div>
|
|
237
|
+
|
|
238
|
+
<p className="text-gray-500">
|
|
239
|
+
Services Offered
|
|
240
|
+
</p>
|
|
241
|
+
|
|
242
|
+
<h1 className="text-4xl font-bold text-orange-500 mt-2">
|
|
243
|
+
|
|
244
|
+
{
|
|
245
|
+
[...new Set(
|
|
246
|
+
report.map(
|
|
247
|
+
(r) => r.SlotStatus
|
|
248
|
+
)
|
|
249
|
+
)].length
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
</h1>
|
|
253
|
+
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<div className="bg-orange-100 p-4 rounded-full">
|
|
257
|
+
|
|
258
|
+
<Wrench
|
|
259
|
+
className="text-orange-500"
|
|
260
|
+
size={30}
|
|
261
|
+
/>
|
|
262
|
+
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
</div>
|
|
268
|
+
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
{/* REPORT TABLE */}
|
|
276
|
+
<div className="bg-white rounded-3xl shadow-lg overflow-hidden border border-gray-200">
|
|
277
|
+
|
|
278
|
+
{/* HEADER */}
|
|
279
|
+
<div className="p-6 border-b border-gray-200 flex items-center justify-between">
|
|
280
|
+
|
|
281
|
+
<div>
|
|
282
|
+
|
|
283
|
+
<h2 className="text-2xl font-bold text-gray-800">
|
|
284
|
+
Daily Payment Records
|
|
285
|
+
</h2>
|
|
286
|
+
|
|
287
|
+
<p className="text-gray-500 mt-1">
|
|
288
|
+
SmartPark garage report
|
|
289
|
+
</p>
|
|
290
|
+
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
<button
|
|
295
|
+
onClick={generatePDF}
|
|
296
|
+
className="
|
|
297
|
+
bg-indigo-600
|
|
298
|
+
hover:bg-indigo-700
|
|
299
|
+
text-white
|
|
300
|
+
px-5
|
|
301
|
+
py-2
|
|
302
|
+
rounded-xl
|
|
303
|
+
"
|
|
304
|
+
>
|
|
305
|
+
Generate PDF
|
|
306
|
+
</button>
|
|
307
|
+
|
|
308
|
+
</div>
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
{/* TABLE */}
|
|
314
|
+
<div className="overflow-x-auto">
|
|
315
|
+
|
|
316
|
+
<table className="w-full">
|
|
317
|
+
|
|
318
|
+
<thead className="bg-gray-100">
|
|
319
|
+
|
|
320
|
+
<tr>
|
|
321
|
+
|
|
322
|
+
<th className="text-left py-4 px-6">
|
|
323
|
+
Plate Number
|
|
324
|
+
</th>
|
|
325
|
+
|
|
326
|
+
<th className="text-left py-4 px-6">
|
|
327
|
+
Amount Paid
|
|
328
|
+
</th>
|
|
329
|
+
|
|
330
|
+
<th className="text-left py-4 px-6">
|
|
331
|
+
Payment Date
|
|
332
|
+
</th>
|
|
333
|
+
|
|
334
|
+
</tr>
|
|
335
|
+
|
|
336
|
+
</thead>
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
<tbody>
|
|
342
|
+
|
|
343
|
+
{report.length > 0 ? (
|
|
344
|
+
|
|
345
|
+
report.map((r, i) => (
|
|
346
|
+
|
|
347
|
+
<tr
|
|
348
|
+
key={i}
|
|
349
|
+
className="border-b hover:bg-gray-50"
|
|
350
|
+
>
|
|
351
|
+
|
|
352
|
+
<td className="py-4 px-6 font-medium">
|
|
353
|
+
{r.PlateNumber}
|
|
354
|
+
</td>
|
|
355
|
+
|
|
356
|
+
<td className="py-4 px-6 text-green-600 font-bold">
|
|
357
|
+
{Number(
|
|
358
|
+
r.AmountPaid
|
|
359
|
+
).toLocaleString()} RWF
|
|
360
|
+
</td>
|
|
361
|
+
|
|
362
|
+
<td className="py-4 px-6">
|
|
363
|
+
{r.PaymentDate}
|
|
364
|
+
</td>
|
|
365
|
+
|
|
366
|
+
</tr>
|
|
367
|
+
|
|
368
|
+
))
|
|
369
|
+
|
|
370
|
+
) : (
|
|
371
|
+
|
|
372
|
+
<tr>
|
|
373
|
+
|
|
374
|
+
<td
|
|
375
|
+
colSpan="7"
|
|
376
|
+
className="text-center py-8 text-gray-500"
|
|
377
|
+
>
|
|
378
|
+
No report records found
|
|
379
|
+
</td>
|
|
380
|
+
|
|
381
|
+
</tr>
|
|
382
|
+
|
|
383
|
+
)}
|
|
384
|
+
|
|
385
|
+
</tbody>
|
|
386
|
+
|
|
387
|
+
</table>
|
|
388
|
+
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
{/* FOOTER */}
|
|
397
|
+
<div className="mt-6 text-center text-gray-500 text-sm">
|
|
398
|
+
|
|
399
|
+
© 2026 CRPMS - SmartPark Garage System
|
|
400
|
+
|
|
401
|
+
</div>
|
|
402
|
+
|
|
403
|
+
</div>
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export default Report;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss";
|