source: frontend/web3-eDnevnik_Frontend/src/pages/dashboards/DirektorAdminDashboard/AdminPanelDashboard.jsx

Last change on this file was 81cdf2d, checked in by Nikola Janev <nikolajanev57@…>, 9 days ago

initial commit

  • Property mode set to 100644
File size: 13.6 KB
Line 
1import React, { useState, useEffect } from "react";
2import axios from "axios";
3import AdminPanelStyleSheet from "./AdminPanelStyleSheet.module.css";
4import Navbar from "../../../components/nav/Navbar.jsx";
5import { Link, useNavigate } from "react-router-dom";
6
7const DataCard = ({
8 title,
9 columns,
10 data,
11 isLoading,
12 type,
13 onDelete,
14 onRefresh,
15}) => {
16 const [localData, setLocalData] = useState(data);
17 const navigate = useNavigate();
18 const [filter, setFilter] = useState("all");
19
20 useEffect(() => {
21 if (filter === "active") {
22 setLocalData(data.filter((item) => item.active === true));
23 } else {
24 setLocalData(data);
25 }
26 }, [filter, data]);
27
28 const createLinks = {
29 ucenik: "/korisnici/createUcenik",
30 roditel: "/korisnici/createRoditel",
31 blagajnik: "/korisnici/createBlagajnik",
32 klasenRakovoditel: "/korisnici/nastavnici/createKlasenRakovoditel",
33 predmetenNastavnik: "/korisnici/nastavnici/createPredmetenNastavnik",
34 nastavnik: "/korisnici/nastavnici/createNastavnik",
35 };
36 const infoLinks = {
37 ucenik: (id) => `/adminDashboard/students/${id}/info`,
38 roditel: (id) => `/adminDashboard/parents/${id}/info`,
39 blagajnik: (id) => `/adminDashboard/treasurers/${id}/info`,
40 klasenRakovoditel: (id) => `/adminDashboard/classTeacher/${id}/info`,
41 predmetenNastavnik: (id) => `/adminDashboard/teacher/${id}/info`,
42 };
43
44 const activationEndpoints = {
45 ucenik: "ucenici",
46 roditel: "roditeli",
47 blagajnik: "blagajnici",
48 nastavnik: "nastavnici",
49 klasenRakovoditel: "nastavnici/klasniRakovoditeli",
50 predmetenNastavnik: "nastavnici/predmetniNastavnici",
51 };
52
53 const toggleActivation = async (id) => {
54 try {
55 const endpoint = activationEndpoints[type];
56 await axios.put(
57 `http://localhost:8080/api/users/${endpoint}/${id}/toggleActivation`,
58 {},
59 { withCredentials: true }
60 );
61 onRefresh();
62 } catch (err) {
63 console.error(err);
64 alert("Грешка при менување статус.");
65 }
66 };
67
68 return (
69 <div className={AdminPanelStyleSheet.card}>
70 <div
71 className={AdminPanelStyleSheet.cardHeader}
72 style={{
73 display: "flex",
74 justifyContent: "space-between",
75 alignItems: "center",
76 marginBottom: "15px",
77 }}
78 >
79 <h3 className={AdminPanelStyleSheet.cardTitle} style={{ margin: 0 }}>
80 {title}
81 </h3>
82
83 <div style={{ display: "flex", gap: "15px", alignItems: "center" }}>
84 <div className={AdminPanelStyleSheet.selectWrapper}>
85 <span className={AdminPanelStyleSheet.selectText}>Прикажи: </span>
86 <select
87 className={AdminPanelStyleSheet.selectElement}
88 value={filter}
89 onChange={(e) => setFilter(e.target.value)}
90 >
91 <option value="all">Сите</option>
92 <option value="active">Активни</option>
93 </select>
94 </div>
95
96 {createLinks[type] && (
97 <Link
98 to={createLinks[type]}
99 className={AdminPanelStyleSheet.addLink}
100 >
101 + Додади
102 </Link>
103 )}
104 </div>
105 </div>
106
107 <table className={AdminPanelStyleSheet.dataTable}>
108 <thead>
109 <tr>
110 <th>Р.Бр</th>
111 {columns.map((col, index) => (
112 <th key={index}>{col}</th>
113 ))}
114 <th style={{ textAlign: "right" }}>Акции</th>
115 </tr>
116 </thead>
117
118 <tbody>
119 {isLoading ? (
120 <tr>
121 <td colSpan={columns.length + 2}>Вчитување...</td>
122 </tr>
123 ) : localData.length > 0 ? (
124 localData.map((item, index) => (
125 <tr key={item.id || index}>
126 <td>{index + 1}</td>
127 <td>
128 {item.ime} {item.prezime}
129 </td>
130
131 {type === "ucenik" && (
132 <>
133 <td>{item.e_posta}</td>
134 <td>{item.klasDisplay}</td>
135 <td>{item.roditelDisplay}</td>
136 </>
137 )}
138
139 {(type === "roditel" ||
140 type === "nastavnik" ||
141 type === "klasenRakovoditel" ||
142 type === "predmetenNastavnik") && (
143 <>
144 <td>{item.e_posta}</td>
145 <td>{item.pol}</td>
146 </>
147 )}
148
149 {type === "blagajnik" && (
150 <>
151 <td>{item.e_posta}</td>
152 <td style={{ fontSize: "0.8rem", fontFamily: "monospace" }}>
153 {item.metamusk_adresa}
154 </td>
155 </>
156 )}
157
158 <td>{item.active ? "Активен" : "Неактивен"}</td>
159
160 <td style={{ textAlign: "right" }}>
161 <button
162 className={AdminPanelStyleSheet.toggleActivation}
163 onClick={() => toggleActivation(item.id)}
164 >
165 {item.active ? "Деактивирај" : "Активирај"}
166 </button>
167 <button
168 className={`${AdminPanelStyleSheet.actionBtn} ${AdminPanelStyleSheet.deleteBtn}`}
169 onClick={() => onDelete(type, item.id)}
170 >
171 Избриши
172 </button>
173 {type !== "nastavnik" && (
174 <button
175 className={`${AdminPanelStyleSheet.actionBtn} ${AdminPanelStyleSheet.deleteBtn}`}
176 onClick={() => navigate(infoLinks[type](item.id))}
177 >
178 Види повеќе информации
179 </button>
180 )}
181 </td>
182 </tr>
183 ))
184 ) : (
185 <tr>
186 <td colSpan={columns.length + 2}>Нема податоци...</td>
187 </tr>
188 )}
189 </tbody>
190 </table>
191 </div>
192 );
193};
194
195const AdminPanel = () => {
196 const [ucenici, setUcenici] = useState([]);
197 const [blagajnici, setBlagajnici] = useState([]);
198 const [klasni, setKlasni] = useState([]);
199 const [roditeli, setRoditeli] = useState([]);
200 const [predmetni, setPredmetni] = useState([]);
201 const [nastavnici, setNastavnici] = useState([]);
202 const [loading, setLoading] = useState(true);
203
204 const fetchData = async () => {
205 try {
206 setLoading(true);
207 const [resU, resB, resK, resR, resP, resN] = await Promise.all([
208 axios.get("http://localhost:8080/api/users/ucenici/all", {
209 withCredentials: true,
210 }),
211 axios.get("http://localhost:8080/api/users/blagajnici/all", {
212 withCredentials: true,
213 }),
214 axios.get(
215 "http://localhost:8080/api/users/nastavnici/klasniRakovoditeli/all",
216 { withCredentials: true }
217 ),
218 axios.get("http://localhost:8080/api/users/roditeli/all", {
219 withCredentials: true,
220 }),
221 axios.get(
222 "http://localhost:8080/api/users/nastavnici/predmetniNastavnici/all",
223 { withCredentials: true }
224 ),
225 axios.get("http://localhost:8080/api/users/nastavnici/all", {
226 withCredentials: true,
227 }),
228 ]);
229
230 const extendedUcenici = await Promise.all(
231 resU.data.map(async (u) => {
232 try {
233 const [kRes, rRes] = await Promise.all([
234 u.uciVoKlasId != null
235 ? axios.get(`http://localhost:8080/api/klas/${u.uciVoKlasId}`, {
236 withCredentials: true,
237 })
238 : null,
239 axios.get(
240 `http://localhost:8080/api/users/roditeli/${u.staratelId}`,
241 { withCredentials: true }
242 ),
243 ]);
244 return {
245 ...u,
246 klasDisplay: kRes
247 ? `${kRes.data.oddelenie}-${kRes.data.paralelka}`
248 : "Нема клас",
249
250 roditelDisplay: `${rRes.data.ime} ${rRes.data.prezime}`,
251 };
252 } catch {
253 return { ...u, klasDisplay: "N/A", roditelDisplay: "N/A" };
254 }
255 })
256 );
257
258 setUcenici(extendedUcenici);
259 setBlagajnici(resB.data);
260 setKlasni(resK.data);
261 setRoditeli(resR.data);
262 setPredmetni(resP.data);
263 setNastavnici(resN.data);
264 } catch (err) {
265 console.error("Грешка при вчитување:", err);
266 } finally {
267 setLoading(false);
268 }
269 };
270
271 useEffect(() => {
272 fetchData();
273 }, []);
274
275 const handleDelete = async (type, id) => {
276 try {
277 const endpoints = {
278 ucenik: "ucenici",
279 roditel: "roditeli",
280 blagajnik: "blagajnici",
281 nastavnik: "nastavnici",
282 klasenRakovoditel: "nastavnici/klasniRakovoditeli",
283 predmetenNastavnik: "nastavnici/predmetniNastavnici",
284 };
285
286 await axios.delete(
287 `http://localhost:8080/api/users/${endpoints[type]}/${id}`,
288 { withCredentials: true }
289 );
290
291 const filterData = (prev) => prev.filter((item) => item.id !== id);
292
293 switch (type) {
294 case "ucenik":
295 setUcenici(filterData);
296 break;
297 case "roditel":
298 setRoditeli(filterData);
299 break;
300 case "blagajnik":
301 setBlagajnici(filterData);
302 break;
303 case "nastavnik":
304 setNastavnici(filterData);
305 break;
306 case "klasenRakovoditel":
307 setKlasni(filterData);
308 break;
309 case "predmetenNastavnik":
310 setPredmetni(filterData);
311 break;
312 default:
313 break;
314 }
315 <div class="alert alert-success" role="alert">
316 Успешно избришано
317 </div>;
318 } catch (err) {
319 console.error("Грешка при бришење:", err);
320 <div class="alert alert-warning" role="alert">
321 Успешно избришано
322 </div>;
323 }
324 };
325
326 return (
327 <>
328 <Navbar />
329 <div className={AdminPanelStyleSheet.adminWrapper}>
330 <h1 className={AdminPanelStyleSheet.headerTitle}>
331 Админ контролен панел
332 </h1>
333
334 <div className={AdminPanelStyleSheet.inlineLinks}>
335 <Link
336 to="/adminDashboard/users"
337 className={AdminPanelStyleSheet.inlineLink}
338 >
339 Корисници
340 </Link>
341 <Link
342 to="/adminDashboard/classes"
343 className={AdminPanelStyleSheet.inlineLink}
344 >
345 Класови
346 </Link>
347 <Link
348 to="/adminDashboard/subjects"
349 className={AdminPanelStyleSheet.inlineLink}
350 >
351 Предмети
352 </Link>
353 <Link
354 to="/adminDashboard/schedules"
355 className={AdminPanelStyleSheet.inlineLink}
356 >
357 Распореди
358 </Link>
359 <Link
360 to="/adminDashboard/weeklyPlans"
361 className={AdminPanelStyleSheet.inlineLink}
362 >
363 Неделни планови
364 </Link>
365 <Link
366 to="/adminDashboard/paymentAnnoucements"
367 className={AdminPanelStyleSheet.inlineLink}
368 >
369 Соопштенија за плаќање
370 </Link>
371 <Link
372 to="/adminDashboard/statistics"
373 className={AdminPanelStyleSheet.inlineLink}
374 >
375 Статистика
376 </Link>
377 </div>
378
379 <div className={AdminPanelStyleSheet.dashboardGrid}>
380 <DataCard
381 title="Ученици"
382 type="ucenik"
383 data={ucenici}
384 isLoading={loading}
385 onDelete={handleDelete}
386 onRefresh={fetchData}
387 columns={["Име и презиме", "Е-пошта", "Клас", "Родител", "Статус"]}
388 />
389 <DataCard
390 title="Родители"
391 type="roditel"
392 data={roditeli}
393 isLoading={loading}
394 onDelete={handleDelete}
395 onRefresh={fetchData}
396 columns={["Име и презиме", "Е-пошта", "Пол", "Статус"]}
397 />
398 <DataCard
399 title="Благајници"
400 type="blagajnik"
401 data={blagajnici}
402 isLoading={loading}
403 onDelete={handleDelete}
404 onRefresh={fetchData}
405 columns={["Име и презиме", "Е-пошта", "Metamask Адреса", "Статус"]}
406 />
407 <DataCard
408 title="Наставници"
409 type="nastavnik"
410 data={nastavnici}
411 isLoading={loading}
412 onDelete={handleDelete}
413 onRefresh={fetchData}
414 columns={["Име и презиме", "Е-пошта", "Пол", "Статус"]}
415 />
416 <DataCard
417 title="Класни раководители"
418 type="klasenRakovoditel"
419 data={klasni}
420 isLoading={loading}
421 onDelete={handleDelete}
422 onRefresh={fetchData}
423 columns={["Име и презиме", "Е-пошта", "Пол", "Статус"]}
424 />
425 <DataCard
426 title="Предметни наставници"
427 type="predmetenNastavnik"
428 data={predmetni}
429 isLoading={loading}
430 onDelete={handleDelete}
431 onRefresh={fetchData}
432 columns={["Име и презиме", "Е-пошта", "Пол", "Статус"]}
433 />
434 </div>
435 </div>
436 </>
437 );
438};
439
440export default AdminPanel;
Note: See TracBrowser for help on using the repository browser.