source: frontend/web3-eDnevnik_Frontend/src/pages/DirektorAdmin_Pages/AdminPanelClassPage/AdminPanelClassPage.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: 19.3 KB
Line 
1import React, { useState, useEffect } from "react";
2import axios from "axios";
3import styles from "./AdminPanelClassPageStyles.module.css";
4import Navbar from "../../../components/nav/Navbar.jsx";
5import { Link, useNavigate } from "react-router-dom";
6
7const ClassCard = ({ klas }) => {
8 const navigate = useNavigate();
9 const [studentsInClass, setStudentsInClass] = useState([]);
10 const [students, setStudents] = useState([]);
11 const [rakovoditel, setRakovoditel] = useState(null);
12 const [loading, setLoading] = useState(true);
13 const [showAddStudentToClassModal, setShowAddStudentToClassModal] =
14 useState(false);
15
16 useEffect(() => {
17 const fetchData = async () => {
18 try {
19 setLoading(true);
20
21 const [resStudentsInClass, resRakovoditel, resAllStudents] =
22 await Promise.all([
23 axios.get(`http://localhost:8080/api/klas/${klas.id}/students`, {
24 withCredentials: true,
25 }),
26 axios.get(
27 `http://localhost:8080/api/klas/${klas.id}/klasenRakovoditel`,
28 { withCredentials: true }
29 ),
30 axios.get("http://localhost:8080/api/users/ucenici", {
31 withCredentials: true,
32 }),
33 ]);
34
35 setStudentsInClass(resStudentsInClass.data);
36 setRakovoditel(resRakovoditel.data);
37 setStudents(resAllStudents.data);
38 } catch (err) {
39 console.error("Грешка при вчитување клас:", err);
40 } finally {
41 setLoading(false);
42 }
43 };
44
45 if (klas.id) fetchData();
46 }, [klas.id]);
47
48 const handleViewWeeklyPlan = () => {
49 navigate(`/adminDashboard/classes/${klas.id}/weeklyPlan`);
50 };
51
52 const handleAddingStudentToClass = () => {
53 setShowAddStudentToClassModal(true);
54 };
55
56 const handleRasporedChangeView = () => {
57 navigate(`/adminDashboard/classes/${klas.id}/schedule`);
58 };
59 const handleSubmitAddStudentToClass = async (e) => {
60 e.preventDefault();
61 try {
62 await axios.post(
63 `http://localhost:8080/api/klas/${klas.id}/addStudent`,
64 addStudentToClassForm,
65 {
66 withCredentials: true,
67 }
68 );
69 setShowAddStudentToClassModal(false);
70 setAddStudentToClassForm({
71 ucenikId: "",
72 });
73 } catch (err) {
74 console.log(err);
75 }
76 };
77 const handleAssignTeacher = () => {
78 navigate(`/adminDashboard/classes/${klas.id}/addKlasenRakovoditel`);
79 };
80 const handleAssignSubjects = () => {
81 navigate(`/adminDashboard/classes/${klas.id}/addSubjects`);
82 };
83
84 const [addStudentToClassForm, setAddStudentToClassForm] = useState({
85 ucenikId: "",
86 });
87 const handleSoopstenijaViewPageChange = () => {
88 navigate(`/adminDashboard/classes/${klas.id}/soopstenija`);
89 };
90
91 const handleViewSubjects = () => {
92 navigate(`/adminDashboard/classes/${klas.id}/viewSubjects`);
93 };
94
95 if (loading)
96 return (
97 <div className={styles.classCard}>Вчитување податоци за класот...</div>
98 );
99
100 return (
101 <div className={styles.classCard}>
102 <div className={styles.classHeader}>
103 <div className={styles.classInfo}>
104 <span>
105 <strong>Клас:</strong> {klas.oddelenie}-{klas.paralelka}
106 </span>
107 <span>
108 <strong>Година/Одделение:</strong> {klas.oddelenie}-то одд.
109 </span>
110 </div>
111
112 <div className={styles.linkGroup}>
113 <span onClick={handleViewWeeklyPlan} style={{ cursor: "pointer" }}>
114 Види неделен план
115 </span>
116
117 <span
118 onClick={handleRasporedChangeView}
119 style={{ cursor: "pointer" }}
120 >
121 Види распоред
122 </span>
123
124 <span
125 onClick={handleSoopstenijaViewPageChange}
126 style={{ cursor: "pointer" }}
127 >
128 Види соопштенија
129 </span>
130 <span onClick={handleViewSubjects} style={{ cursor: "pointer" }}>
131 Види предмети
132 </span>
133 <span onClick={handleAddingStudentToClass}>
134 Додади ученик во клас
135 </span>
136 </div>
137 </div>
138 {showAddStudentToClassModal && (
139 <div
140 className="modal d-block"
141 tabIndex="-1"
142 role="dialog"
143 style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
144 >
145 <div className="modal-dialog modal-dialog-centered" role="document">
146 <div className="modal-content">
147 <div className="modal-header">
148 <h5 className="modal-title">Додади ученик во клас</h5>
149 <button
150 type="button"
151 className="btn-close"
152 onClick={() => setShowAddStudentToClassModal(false)}
153 />
154 </div>
155 <div className="modal-body">
156 <form onSubmit={handleSubmitAddStudentToClass}>
157 <div className="mb-3">
158 <label className="form-label">Одберете студент</label>
159 <select
160 className="form-select"
161 name="ucenikId"
162 value={addStudentToClassForm.ucenikId}
163 required
164 onChange={(e) =>
165 setAddStudentToClassForm({
166 ...addStudentToClassForm,
167 ucenikId: e.target.value,
168 })
169 }
170 >
171 <option value="">-- Изберете ученик --</option>
172 {students.map((u) => (
173 <option key={u.id} value={u.id}>
174 {u.ime} {u.prezime} ({u.e_posta})
175 </option>
176 ))}
177 </select>
178 </div>
179 <div className="modal-footer px-0 pb-0">
180 <button
181 type="button"
182 className="btn btn-secondary"
183 onClick={() => setShowAddStudentToClassModal(false)}
184 >
185 Откажи
186 </button>
187 <button
188 type="submit"
189 className="btn text-white"
190 style={{ backgroundColor: "#147176" }}
191 >
192 Додај
193 </button>
194 </div>
195 </form>
196 </div>
197 </div>
198 </div>
199 </div>
200 )}
201 <div className={styles.sectionTitle}>
202 Класен раководител:{" "}
203 {rakovoditel
204 ? `${rakovoditel.ime} ${rakovoditel.prezime}`
205 : "Не е доделен"}
206 </div>
207
208 {rakovoditel ? (
209 <div className={styles.infoGrid}>
210 <div className={styles.gridHeader}>Име</div>
211 <div className={styles.gridHeader}>Презиме</div>
212 <div className={styles.gridHeader}>Е-пошта</div>
213 <div className={styles.buttons}>
214 <div
215 className={styles.changeTeacherBtn}
216 onClick={handleAssignTeacher}
217 style={{ cursor: "pointer" }}
218 >
219 Промени Класен Раководител
220 </div>
221 <div
222 className={styles.addSubjects}
223 onClick={handleAssignSubjects}
224 style={{ cursor: "pointer" }}
225 >
226 Додели предмет
227 </div>
228 </div>
229
230 <p>{rakovoditel.ime}</p>
231 <p>{rakovoditel.prezime}</p>
232 <p>{rakovoditel.e_posta}</p>
233 </div>
234 ) : (
235 <div className={styles.infoGrid}>
236 <div
237 style={{ gridColumn: "span 6", color: "#666", fontStyle: "italic" }}
238 >
239 Нема доделено раководител за овој клас.
240 <span
241 className={styles.changeTeacherBtn}
242 onClick={handleAssignTeacher}
243 style={{
244 marginLeft: "15px",
245 cursor: "pointer",
246 textDecoration: "underline",
247 }}
248 >
249 Додади сега
250 </span>
251 </div>
252 </div>
253 )}
254
255 <div className={styles.sectionTitle}>Ученици</div>
256
257 <div className={styles.infoGrid}>
258 <div className={styles.gridHeader}>Име</div>
259 <div className={styles.gridHeader}>Презиме</div>
260 <div className={styles.gridHeader}>Е-пошта</div>
261 <div className={styles.gridHeader}>Пол</div>
262 <div className={styles.gridHeader}>Телефон</div>
263 <div className={styles.gridHeader}>Адреса</div>
264 <div className={styles.gridHeader}>Акции</div>
265 </div>
266
267 {studentsInClass.length > 0 ? (
268 studentsInClass.map((u) => (
269 <div key={u.id} className={styles.infoGrid}>
270 <div>{u.ime}</div>
271 <div>{u.prezime}</div>
272 <div>{u.e_posta}</div>
273 <div>{u.pol}</div>
274 <div>{u.mobilenTelefon}</div>
275 <div>{u.adresa || "N/A"}</div>
276 <div>
277 <Link
278 to={`/adminDashboard/classes/${klas.id}/students/${u.id}/attendancies`}
279 >
280 Види присуства
281 </Link>
282 </div>
283 <div>
284 <Link
285 to={`/adminDashboard/classes/${klas.id}/students/${u.id}/info`}
286 >
287 Види повеќе информации
288 </Link>
289 </div>
290 </div>
291 ))
292 ) : (
293 <div className={styles.noData}>Нема додадено ученици во овој клас.</div>
294 )}
295 </div>
296 );
297};
298
299const AdminPanelClassPage = () => {
300 const [klasovi, setKlasovi] = useState([]);
301 const [loading, setLoading] = useState(true);
302 const [showCreateClassModal, setShowCreateClassModal] = useState(false);
303
304 const [klasniRakovoditeli, setKlasniRakovoditeli] = useState([]);
305
306 const [createClassForm, setCreateClassForm] = useState({
307 godinaNaSlusanje: "",
308 paralelka: "",
309 oddelenie: "",
310 klasenRakovoditelId: "",
311 });
312
313 const fetchKlasovi = async () => {
314 try {
315 const [resKlasovi, resKlasniRakovoditeli] = await Promise.all([
316 axios.get("http://localhost:8080/api/klas", {
317 withCredentials: true,
318 }),
319
320 axios.get(
321 "http://localhost:8080/api/users/nastavnici/klasniRakovoditeli",
322 { withCredentials: true }
323 ),
324 ]);
325
326 setKlasovi(resKlasovi.data);
327 setKlasniRakovoditeli(resKlasniRakovoditeli.data);
328 } catch (err) {
329 console.error("Грешка при вчитување класови", err);
330 } finally {
331 setLoading(false);
332 }
333 };
334
335 useEffect(() => {
336 fetchKlasovi();
337 }, []);
338
339 const handleCreateClass = () => {
340 setShowCreateClassModal(true);
341 };
342
343 const handleSubmitClass = async (e) => {
344 e.preventDefault();
345
346 try {
347 await axios.post("http://localhost:8080/api/klas", createClassForm, {
348 withCredentials: true,
349 });
350
351 setShowCreateClassModal(false);
352
353 setCreateClassForm({
354 godinaNaSlusanje: "",
355 paralelka: "",
356 oddelenie: "",
357 klasenRakovoditelId: "",
358 });
359
360 fetchKlasovi();
361 alert("Klasot e uspesno kreiran");
362 } catch (err) {
363 alert("Грешка при креирање клас.");
364 }
365 };
366
367 return (
368 <div className={styles.adminWrapper}>
369 <Navbar />
370
371 <h1 className={styles.headerTitle}>Директор админ - Класови</h1>
372
373 <div className={styles.wrapper}>
374 <div
375 className="d-flex flex-row justify-content-center align-items-center p-2"
376 style={{ backgroundColor: "#147176" }}
377 >
378 <Link
379 to="/adminDashboard/users"
380 className="mx-3 text-white text-decoration-none fs-6 opacity-100-hover"
381 >
382 Корисници
383 </Link>
384
385 <Link
386 to="/adminDashboard/classes"
387 className="mx-3 text-white text-decoration-none fs-6"
388 >
389 Класови
390 </Link>
391
392 <Link
393 to="/adminDashboard/subjects"
394 className="mx-3 text-white text-decoration-none fs-6"
395 >
396 Предмети
397 </Link>
398
399 <Link
400 to="/adminDashboard/schedules"
401 className="mx-3 text-white text-decoration-none fs-6"
402 >
403 Распореди
404 </Link>
405
406 <Link
407 to="/adminDashboard/weeklyPlans"
408 className="mx-3 text-white text-decoration-none fs-6"
409 >
410 Неделни планови
411 </Link>
412 <Link
413 to="/adminDashboard/paymentAnnoucements"
414 className="mx-3 text-white text-decoration-none fs-6"
415 >
416 Соопштенија за плаќање
417 </Link>
418 </div>
419
420 {showCreateClassModal && (
421 <div
422 className="modal d-block"
423 tabIndex="-1"
424 role="dialog"
425 style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
426 >
427 <div className="modal-dialog modal-dialog-centered" role="document">
428 <div className="modal-content">
429 <div className="modal-header">
430 <h5 className="modal-title">Креирај нов клас</h5>
431 <button
432 type="button"
433 className="btn-close"
434 onClick={() => setShowCreateClassModal(false)}
435 />
436 </div>
437
438 <div className="modal-body">
439 <form onSubmit={handleSubmitClass}>
440 <div className="mb-3">
441 <label className="form-label">
442 Одбери година на слушање
443 </label>
444 <select
445 className="form-select"
446 name="godinaNaSlusanje"
447 value={createClassForm.godinaNaSlusanje}
448 onChange={(e) =>
449 setCreateClassForm({
450 ...createClassForm,
451 godinaNaSlusanje: e.target.value,
452 })
453 }
454 >
455 <option value="2019/2020">2019/2020</option>
456 <option value="2020/2021">2020/2021</option>
457 <option value="2021/2022">2021/2022</option>
458 <option value="2022/2023">2022/2023</option>
459 <option value="2023/2024">2023/2024</option>
460 <option value="2024/2025">2024/2025</option>
461 <option value="2025/2026">2025/2026</option>
462 </select>
463 </div>
464
465 <div className="mb-3">
466 <label className="form-label">Одбери паралелка</label>
467 <select
468 className="form-select"
469 name="paralelka"
470 value={createClassForm.paralelka}
471 onChange={(e) =>
472 setCreateClassForm({
473 ...createClassForm,
474 paralelka: e.target.value,
475 })
476 }
477 >
478 <option value="А">А</option>
479 <option value="Б">Б</option>
480 <option value="В">В</option>
481 <option value="Г">Г</option>
482 <option value="Д">Д</option>
483 <option value="Ѓ">Ѓ</option>
484 <option value="Е">Е</option>
485 </select>
486 </div>
487
488 <div className="mb-3">
489 <label className="form-label">Одбери одделение</label>
490 <select
491 className="form-select"
492 name="oddelenie"
493 value={createClassForm.oddelenie}
494 onChange={(e) =>
495 setCreateClassForm({
496 ...createClassForm,
497 oddelenie: e.target.value,
498 })
499 }
500 >
501 {[1, 2, 3, 4, 5, 6, 7, 8, 9].map((n) => (
502 <option key={n} value={n}>
503 {n}
504 </option>
505 ))}
506 </select>
507 </div>
508
509 <div className="mb-3">
510 <label className="form-label">
511 Одбери Класен раководител
512 </label>
513 <select
514 className="form-select"
515 name="klasenRakovoditelId"
516 value={createClassForm.klasenRakovoditelId}
517 required
518 onChange={(e) =>
519 setCreateClassForm({
520 ...createClassForm,
521 klasenRakovoditelId: e.target.value,
522 })
523 }
524 >
525 <option value="">
526 -- Избери класен раководител --
527 </option>
528 {klasniRakovoditeli.map((n) => (
529 <option key={n.id} value={n.id}>
530 {n.ime} {n.prezime} ({n.e_posta})
531 </option>
532 ))}
533 </select>
534 </div>
535
536 <div className="modal-footer px-0 pb-0">
537 <button
538 type="button"
539 className="btn btn-secondary"
540 onClick={() => setShowCreateClassModal(false)}
541 >
542 Откажи
543 </button>
544 <button
545 type="submit"
546 className="btn text-white"
547 style={{ backgroundColor: "#147176" }}
548 >
549 Креирај
550 </button>
551 </div>
552 </form>
553 </div>
554 </div>
555 </div>
556 </div>
557 )}
558 <div className={styles.mainContainer}>
559 <div className={styles.toolbar}>
560 <div className={styles.actionButtons}>
561 <button className={styles.mainBtn} onClick={handleCreateClass}>
562 Креирај клас
563 </button>
564 </div>
565 </div>
566
567 {loading ? (
568 <h2 style={{ textAlign: "center" }}>Вчитување на класовите...</h2>
569 ) : (
570 <div className={styles.classesList}>
571 {klasovi.map((k) => (
572 <ClassCard key={k.id} klas={k} />
573 ))}
574 </div>
575 )}
576 </div>
577 </div>
578 </div>
579 );
580};
581
582export default AdminPanelClassPage;
Note: See TracBrowser for help on using the repository browser.