| 1 | import React, { useState, useEffect } from "react";
|
|---|
| 2 | import axios from "axios";
|
|---|
| 3 | import styles from "../Klasen_RakovoditelDashboard/KlasenRakovoditelDashboardPageStyles.module.css";
|
|---|
| 4 | import NavbarKlasen from "../../../components/navbarKlasen/NavbarKlasen.jsx";
|
|---|
| 5 | import { Link } from "react-router-dom";
|
|---|
| 6 |
|
|---|
| 7 | const KlasenRakovoditelDashboardViewPage = ({ teacherId }) => {
|
|---|
| 8 | const [classId, setClassId] = useState(null);
|
|---|
| 9 | const [classInfo, setClassInfo] = useState(null);
|
|---|
| 10 | const [klasen, setKlasen] = useState(null);
|
|---|
| 11 | const [students, setStudents] = useState([]);
|
|---|
| 12 | const [soopstenija, setSoopstenija] = useState([]);
|
|---|
| 13 | const [loading, setLoading] = useState(true);
|
|---|
| 14 | const [parents, setParents] = useState([]);
|
|---|
| 15 |
|
|---|
| 16 | useEffect(() => {
|
|---|
| 17 | const initializeDashboard = async () => {
|
|---|
| 18 | if (!teacherId) return;
|
|---|
| 19 |
|
|---|
| 20 | try {
|
|---|
| 21 | setLoading(true);
|
|---|
| 22 |
|
|---|
| 23 | const resClassInitial = await axios.get(
|
|---|
| 24 | `http://localhost:8080/api/users/nastavnici/klasniRakovoditeli/${teacherId}/klas`,
|
|---|
| 25 | { withCredentials: true }
|
|---|
| 26 | );
|
|---|
| 27 |
|
|---|
| 28 | const foundClass = resClassInitial.data;
|
|---|
| 29 |
|
|---|
| 30 | if (foundClass?.id) {
|
|---|
| 31 | const cId = foundClass.id;
|
|---|
| 32 | setClassId(cId);
|
|---|
| 33 | const resStudents = await axios.get(
|
|---|
| 34 | `http://localhost:8080/api/klas/${cId}/students`,
|
|---|
| 35 | {
|
|---|
| 36 | withCredentials: true,
|
|---|
| 37 | }
|
|---|
| 38 | );
|
|---|
| 39 | const studentsData = resStudents.data;
|
|---|
| 40 | setStudents(studentsData);
|
|---|
| 41 |
|
|---|
| 42 | const parentIds = [
|
|---|
| 43 | ...new Set(
|
|---|
| 44 | studentsData.map((s) => s.staratelId).filter((id) => id)
|
|---|
| 45 | ),
|
|---|
| 46 | ];
|
|---|
| 47 |
|
|---|
| 48 | const parentRequests = parentIds.map((id) =>
|
|---|
| 49 | axios.get(`http://localhost:8080/api/users/roditeli/${id}`, {
|
|---|
| 50 | withCredentials: true,
|
|---|
| 51 | })
|
|---|
| 52 | );
|
|---|
| 53 |
|
|---|
| 54 | const parentResponses = await Promise.all(parentRequests);
|
|---|
| 55 | const parentsData = parentResponses.map((res) => res.data);
|
|---|
| 56 |
|
|---|
| 57 | setParents(parentsData);
|
|---|
| 58 |
|
|---|
| 59 | const [resClass, resKlasen, resSoopstenija] = await Promise.all([
|
|---|
| 60 | axios.get(`http://localhost:8080/api/klas/${cId}`, {
|
|---|
| 61 | withCredentials: true,
|
|---|
| 62 | }),
|
|---|
| 63 | axios.get(
|
|---|
| 64 | `http://localhost:8080/api/klas/${cId}/klasenRakovoditel`,
|
|---|
| 65 | { withCredentials: true }
|
|---|
| 66 | ),
|
|---|
| 67 |
|
|---|
| 68 | axios.get(`http://localhost:8080/api/klas/${cId}/soopstenija`, {
|
|---|
| 69 | withCredentials: true,
|
|---|
| 70 | }),
|
|---|
| 71 | ]);
|
|---|
| 72 |
|
|---|
| 73 | setClassInfo(resClass.data);
|
|---|
| 74 | setKlasen(resKlasen.data);
|
|---|
| 75 | setStudents(resStudents.data);
|
|---|
| 76 | setSoopstenija(resSoopstenija.data);
|
|---|
| 77 | }
|
|---|
| 78 | } catch (err) {
|
|---|
| 79 | console.error("Грешка при иницијализација:", err);
|
|---|
| 80 | } finally {
|
|---|
| 81 | setLoading(false);
|
|---|
| 82 | }
|
|---|
| 83 | };
|
|---|
| 84 |
|
|---|
| 85 | initializeDashboard();
|
|---|
| 86 | }, [teacherId]);
|
|---|
| 87 |
|
|---|
| 88 | const formatDate = (dateString) => {
|
|---|
| 89 | if (!dateString) return "";
|
|---|
| 90 | return new Date(dateString).toLocaleDateString("mk-MK");
|
|---|
| 91 | };
|
|---|
| 92 |
|
|---|
| 93 | if (loading) return <div className={styles.loader}>Вчитување...</div>;
|
|---|
| 94 |
|
|---|
| 95 | if (!classId) {
|
|---|
| 96 | return (
|
|---|
| 97 | <div className={styles.teacherWrapper}>
|
|---|
| 98 | <NavbarKlasen />
|
|---|
| 99 | <div className={styles.container}>
|
|---|
| 100 | <h2 className={styles.errorMessage}>
|
|---|
| 101 | Не сте доделени на активен клас.
|
|---|
| 102 | </h2>
|
|---|
| 103 | </div>
|
|---|
| 104 | </div>
|
|---|
| 105 | );
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | return (
|
|---|
| 109 | <div className={styles.container}>
|
|---|
| 110 | <NavbarKlasen />
|
|---|
| 111 | <div className="container mt-5 mh-100">
|
|---|
| 112 | <div className="row">
|
|---|
| 113 | <div className="col-8">
|
|---|
| 114 | <nav
|
|---|
| 115 | className="container text-white h-25 d-flex justify-content-center text-center p-3"
|
|---|
| 116 | style={{ backgroundColor: "#147176" }}
|
|---|
| 117 | >
|
|---|
| 118 | <Link
|
|---|
| 119 | className="text-white text-decoration-none m-2 fw-bold fs-md"
|
|---|
| 120 | to={"/dashboard"}
|
|---|
| 121 | >
|
|---|
| 122 | Соопштенија
|
|---|
| 123 | </Link>
|
|---|
| 124 | <Link
|
|---|
| 125 | to={`/klasenRakovoditelDashboard/${classId}/weeklyPlan`}
|
|---|
| 126 | className="text-white text-decoration-none m-2 fw-bold"
|
|---|
| 127 | >
|
|---|
| 128 | Види неделни активности
|
|---|
| 129 | </Link>
|
|---|
| 130 | <Link
|
|---|
| 131 | to={`/klasenRakovoditelDashboard/${classId}/raspored`}
|
|---|
| 132 | className="text-white text-decoration-none m-2 fw-bold"
|
|---|
| 133 | >
|
|---|
| 134 | Види распоред
|
|---|
| 135 | </Link>
|
|---|
| 136 | <Link
|
|---|
| 137 | to={`/klasenRakovoditelDashboard/${classId}/students`}
|
|---|
| 138 | className="text-white text-decoration-none m-2 fw-bold"
|
|---|
| 139 | >
|
|---|
| 140 | Студенти
|
|---|
| 141 | </Link>
|
|---|
| 142 | <Link
|
|---|
| 143 | to={`/klasenRakovoditelDashboard/${classId}/subjects`}
|
|---|
| 144 | className="text-white text-decoration-none m-2 fw-bold"
|
|---|
| 145 | >
|
|---|
| 146 | Види слушани предмети
|
|---|
| 147 | </Link>
|
|---|
| 148 | </nav>
|
|---|
| 149 | <div
|
|---|
| 150 | className="row"
|
|---|
| 151 | style={{ marginTop: 20, marginBottom: 10, marginRight: 0 }}
|
|---|
| 152 | >
|
|---|
| 153 | <div className="col-9 fs-4 fw-bold">
|
|---|
| 154 | Клас {classInfo?.oddelenie}-{classInfo?.paralelka} – Соопштенија
|
|---|
| 155 | </div>
|
|---|
| 156 | <div className="col p-0 m-0">
|
|---|
| 157 | <Link
|
|---|
| 158 | to="/klasenRakovoditelDashboard/createSoopstenie"
|
|---|
| 159 | className=" btn btn-primary text-decoration-none"
|
|---|
| 160 | >
|
|---|
| 161 | Креирај соопштение
|
|---|
| 162 | </Link>
|
|---|
| 163 | </div>
|
|---|
| 164 | </div>
|
|---|
| 165 |
|
|---|
| 166 | <div className="d-flex flex-column gap-3">
|
|---|
| 167 | {soopstenija.length > 0 ? (
|
|---|
| 168 | soopstenija.map((s) => (
|
|---|
| 169 | <div key={s.id} className="card shadow-sm">
|
|---|
| 170 | <div className="card-body">
|
|---|
| 171 | <div className="d-flex align-items-center mb-3">
|
|---|
| 172 | <div
|
|---|
| 173 | className="rounded-circle bg-secondary me-3"
|
|---|
| 174 | style={{
|
|---|
| 175 | width: "50px",
|
|---|
| 176 | height: "50px",
|
|---|
| 177 | flexShrink: 0,
|
|---|
| 178 | }}
|
|---|
| 179 | />
|
|---|
| 180 | <div>
|
|---|
| 181 | <span className="fw-bold d-block">
|
|---|
| 182 | {klasen?.ime} {klasen?.prezime}
|
|---|
| 183 | </span>
|
|---|
| 184 | <small className="text-muted">
|
|---|
| 185 | {formatDate(s.kreiranoNa)}
|
|---|
| 186 | </small>
|
|---|
| 187 | </div>
|
|---|
| 188 | </div>
|
|---|
| 189 | <h5 className="card-title">{s.naslov}</h5>
|
|---|
| 190 | <p className="card-text">{s.sodrzina}</p>
|
|---|
| 191 | <span
|
|---|
| 192 | className="fw-bold"
|
|---|
| 193 | style={{ cursor: "pointer", color: "#147176" }}
|
|---|
| 194 | >
|
|---|
| 195 | Отстрани соопштение
|
|---|
| 196 | </span>
|
|---|
| 197 | </div>
|
|---|
| 198 | </div>
|
|---|
| 199 | ))
|
|---|
| 200 | ) : (
|
|---|
| 201 | <p className="text-muted text-center">
|
|---|
| 202 | Нема активни соопштенија.
|
|---|
| 203 | </p>
|
|---|
| 204 | )}
|
|---|
| 205 | </div>
|
|---|
| 206 | </div>
|
|---|
| 207 |
|
|---|
| 208 | <div className="col">
|
|---|
| 209 | <div className={styles.infoCard}>
|
|---|
| 210 | <h2 className="mt-0 fw-semibold">Информации за класот</h2>
|
|---|
| 211 |
|
|---|
| 212 | <div className={styles.infoSection}>
|
|---|
| 213 | <h4 className={styles.sectionLabel}>Класен раководител</h4>
|
|---|
| 214 | <p className={styles.teacherName}>
|
|---|
| 215 | {klasen ? `${klasen.ime} ${klasen.prezime}` : "Не е назначен"}
|
|---|
| 216 | </p>
|
|---|
| 217 | </div>
|
|---|
| 218 |
|
|---|
| 219 | <div className={styles.infoSection}>
|
|---|
| 220 | <h4 className={styles.sectionLabel}>
|
|---|
| 221 | Ученици ({students.length})
|
|---|
| 222 | </h4>
|
|---|
| 223 | <ul className={styles.participantList}>
|
|---|
| 224 | {students.map((student) => (
|
|---|
| 225 | <li key={student.id} className={styles.participantItem}>
|
|---|
| 226 | {student.ime} {student.prezime}
|
|---|
| 227 | </li>
|
|---|
| 228 | ))}
|
|---|
| 229 | {students.length === 0 && <li>Нема запишани ученици</li>}
|
|---|
| 230 | </ul>
|
|---|
| 231 | </div>
|
|---|
| 232 | <div className={styles.infoSection}>
|
|---|
| 233 | <h4 className={styles.sectionLabel}>
|
|---|
| 234 | Родители ({parents.length})
|
|---|
| 235 | </h4>
|
|---|
| 236 | <ul className={styles.participantList}>
|
|---|
| 237 | {parents.map((parent) => (
|
|---|
| 238 | <li key={parent.id} className={styles.participantItem}>
|
|---|
| 239 | {parent.ime} {parent.prezime}
|
|---|
| 240 | </li>
|
|---|
| 241 | ))}
|
|---|
| 242 | {parents.length === 0 && <li>Нема податоци за родители</li>}
|
|---|
| 243 | </ul>
|
|---|
| 244 | </div>
|
|---|
| 245 | </div>
|
|---|
| 246 | </div>
|
|---|
| 247 | </div>
|
|---|
| 248 | </div>
|
|---|
| 249 | </div>
|
|---|
| 250 | );
|
|---|
| 251 | };
|
|---|
| 252 |
|
|---|
| 253 | export default KlasenRakovoditelDashboardViewPage;
|
|---|