Improved style of several classes
This commit is contained in:
parent
c5a98435b3
commit
e5cc695fd9
|
|
@ -20,6 +20,7 @@ import org.springframework.http.HttpStatus;
|
|||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -89,27 +90,30 @@ public class TrainingGroupController {
|
|||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Operation(summary = "Update an existing training group", description = "Update an existing training group with the specified ID")
|
||||
@Operation(summary = "Actualizar un grupo de entrenamiento existente", description = "Actualiza un grupo de entrenamiento por su ID")
|
||||
@Transactional
|
||||
@PutMapping("/update/{id}")
|
||||
public ResponseEntity<TrainingGroupDTO> update(@PathVariable Integer id, @RequestBody TrainingGroupDTO dto) {
|
||||
dto.setId(id);
|
||||
|
||||
Teacher teacher = teacherService.findById(dto.getTeacherId());
|
||||
Set<Student> students = dto.getStudentIds().stream()
|
||||
|
||||
Set<Integer> studentIds = dto.getStudentIds() != null ? dto.getStudentIds() : Collections.emptySet();
|
||||
|
||||
Set<Student> students = studentIds.stream()
|
||||
.map(studentService::findById)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
TrainingGroup updated = trainingGroupService.update(dto.toEntity(teacher, students));
|
||||
TrainingGroup updatedGroup = trainingGroupService.update(dto.toEntity(teacher, students));
|
||||
|
||||
List<TrainingSession> sessions = updated.getTrainingSessions().stream().toList();
|
||||
if (!sessions.isEmpty()) {
|
||||
TrainingSession session = sessions.get(0);
|
||||
session.setDate(updated.getSchedule());
|
||||
updatedGroup.getTrainingSessions().stream().findFirst().ifPresent(session -> {
|
||||
session.setDate(updatedGroup.getSchedule());
|
||||
trainingSessionService.save(session);
|
||||
});
|
||||
|
||||
return ResponseEntity.ok(new TrainingGroupDTO(updatedGroup));
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(new TrainingGroupDTO(updated));
|
||||
}
|
||||
|
||||
@Operation(summary = "Find a training group by ID", description = "Retrieve a training group with the specified ID")
|
||||
@GetMapping("findById/{id}")
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
|||
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ public class TrainingGroupDTO {
|
|||
private String level;
|
||||
private LocalDateTime schedule;
|
||||
private Integer teacherId;
|
||||
private Set<Integer> studentIds;
|
||||
private Set<Integer> studentIds = new HashSet<>();
|
||||
|
||||
public TrainingGroupDTO() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const TrainingGroupForm = () => {
|
|||
useEffect(() => {
|
||||
api.get("/teachers/getAll")
|
||||
.then((res) => setTeachers(res.data))
|
||||
.catch((err) => console.error("Error loading teachers", err));
|
||||
.catch((err) => console.error("Error al cargar profesores", err));
|
||||
}, []);
|
||||
|
||||
const handleChange = (e) => {
|
||||
|
|
@ -37,7 +37,7 @@ const TrainingGroupForm = () => {
|
|||
schedule: formData.schedule,
|
||||
teacherId: parseInt(formData.teacherId),
|
||||
});
|
||||
setSuccessMsg("Training group created successfully.");
|
||||
setSuccessMsg("✅ Grupo de entrenamiento creado correctamente.");
|
||||
setFormData({ name: "", level: "", schedule: "", teacherId: "" });
|
||||
} catch (err) {
|
||||
console.error("Error al crear grupo", err);
|
||||
|
|
@ -47,25 +47,46 @@ const TrainingGroupForm = () => {
|
|||
"❌ Error al crear el grupo. Verifica los datos.";
|
||||
setErrorMsg(backendMsg);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<h2>Create Training Group</h2>
|
||||
<form onSubmit={handleSubmit} className="form">
|
||||
<label>Name:</label>
|
||||
<input type="text" name="name" value={formData.name} onChange={handleChange} required />
|
||||
<h2>Crear Grupo de Entrenamiento</h2>
|
||||
<form onSubmit={handleSubmit} className="form-column">
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Nombre del grupo"
|
||||
value={formData.name}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
|
||||
<label>Level:</label>
|
||||
<input type="text" name="level" value={formData.level} onChange={handleChange} required />
|
||||
<input
|
||||
type="text"
|
||||
name="level"
|
||||
placeholder="Nivel"
|
||||
value={formData.level}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
|
||||
<label>Schedule:</label>
|
||||
<input type="datetime-local" name="schedule" value={formData.schedule} onChange={handleChange} required />
|
||||
<label>Horario del grupo:</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
name="schedule"
|
||||
value={formData.schedule}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
|
||||
<label>Teacher:</label>
|
||||
<select name="teacherId" value={formData.teacherId} onChange={handleChange} required>
|
||||
<option value="">-- Select Teacher --</option>
|
||||
<select
|
||||
name="teacherId"
|
||||
value={formData.teacherId}
|
||||
onChange={handleChange}
|
||||
required
|
||||
>
|
||||
<option value="">-- Selecciona un profesor responsable del grupo --</option>
|
||||
{teachers.map((teacher) => (
|
||||
<option key={teacher.id} value={teacher.id}>
|
||||
{teacher.user?.name} {teacher.user?.surname}
|
||||
|
|
@ -73,12 +94,11 @@ const TrainingGroupForm = () => {
|
|||
))}
|
||||
</select>
|
||||
|
||||
<button type="submit">Create Group</button>
|
||||
<button type="submit">Crear grupo</button>
|
||||
</form>
|
||||
|
||||
<ErrorMessage message={errorMsg} type="error" />
|
||||
<ErrorMessage message={successMsg} type="success" />
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ const TrainingGroupStudentManager = () => {
|
|||
const group = await api.get(`/training-groups/findById/${groupId}`);
|
||||
setGroupStudents(group.data.studentIds || []);
|
||||
} catch (err) {
|
||||
console.error("Error fetching group students", err);
|
||||
console.error("Error al cargar alumnos del grupo", err);
|
||||
const msg =
|
||||
err.response?.data?.message || "❌ Error al cargar datos del grupo.";
|
||||
err.response?.data?.message || "❌ Error al cargar alumnos del grupo.";
|
||||
setErrorMsg(msg);
|
||||
setGroupStudents([]);
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ const TrainingGroupStudentManager = () => {
|
|||
await api.put(`/training-groups/assign-student`, null, {
|
||||
params: {
|
||||
groupId: selectedGroupId,
|
||||
studentId: studentId,
|
||||
studentId,
|
||||
},
|
||||
});
|
||||
setSuccessMsg("✅ Alumno asignado correctamente.");
|
||||
|
|
@ -60,15 +60,16 @@ const TrainingGroupStudentManager = () => {
|
|||
await api.put(`/training-groups/remove-student`, null, {
|
||||
params: {
|
||||
groupId: selectedGroupId,
|
||||
studentId: studentId,
|
||||
studentId,
|
||||
},
|
||||
});
|
||||
setSuccessMsg("Alumno eliminado del grupo.");
|
||||
setSuccessMsg("✅ Alumno eliminado del grupo.");
|
||||
setErrorMsg("");
|
||||
loadGroupStudents(selectedGroupId);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const msg = err.response?.data?.message || "❌ Error al eliminar alumno.";
|
||||
const msg =
|
||||
err.response?.data?.message || "❌ Error al eliminar el alumno.";
|
||||
setErrorMsg(msg);
|
||||
setSuccessMsg("");
|
||||
}
|
||||
|
|
@ -77,11 +78,9 @@ const TrainingGroupStudentManager = () => {
|
|||
return (
|
||||
<div className="content-area">
|
||||
<div className="card">
|
||||
<h2>Asignar Alumnos al Grupo de Entrenamiento</h2>
|
||||
<h2>👥 Gestión de Alumnos por Grupo</h2>
|
||||
|
||||
<label htmlFor="groupSelect" style={{ fontWeight: "bold" }}>
|
||||
🏷️ Selecciona un grupo:
|
||||
</label>
|
||||
<label htmlFor="groupSelect">🏷️ Selecciona un grupo:</label>
|
||||
<select
|
||||
id="groupSelect"
|
||||
value={selectedGroupId}
|
||||
|
|
@ -100,34 +99,42 @@ const TrainingGroupStudentManager = () => {
|
|||
|
||||
{selectedGroupId && (
|
||||
<>
|
||||
<hr style={{ margin: "20px 0" }} />
|
||||
<h3>📋 Alumnos Asignados</h3>
|
||||
<ul>
|
||||
{groupStudents.length === 0 && <li>No hay alumnos asignados.</li>}
|
||||
{groupStudents.length === 0 ? (
|
||||
<p>No hay alumnos asignados a este grupo.</p>
|
||||
) : (
|
||||
<ul className="group-student-list">
|
||||
{groupStudents.map((id) => {
|
||||
const student = students.find((s) => s.id === id);
|
||||
return (
|
||||
<li key={id}>
|
||||
{student?.user?.name} {student?.user?.surname}
|
||||
<button onClick={() => handleRemove(id)}>
|
||||
Eliminar del grupo
|
||||
🎓 {student?.user?.name} {student?.user?.surname}
|
||||
<button
|
||||
className="delete-button"
|
||||
onClick={() => handleRemove(id)}
|
||||
>
|
||||
Eliminar
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
<h3>➕ Añadir Alumno</h3>
|
||||
<ul>
|
||||
<hr style={{ margin: "20px 0" }} />
|
||||
<h3>➕ Añadir Alumnos Disponibles</h3>
|
||||
<ul className="group-student-list">
|
||||
{students
|
||||
.filter((s) => !groupStudents.includes(s.id))
|
||||
.map((s) => (
|
||||
<li key={s.id}>
|
||||
{s.user?.name} {s.user?.surname}
|
||||
👤 {s.user?.name} {s.user?.surname}
|
||||
<button
|
||||
className="add-button"
|
||||
onClick={() => handleAssign(s.id)}
|
||||
>
|
||||
Añadir al grupo
|
||||
Añadir
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import api from "../../api/axiosConfig";
|
||||
import "../styles/ContentArea.css";
|
||||
import "../styles/Timetable.css";
|
||||
|
||||
const ViewTimetable = () => {
|
||||
const [groups, setGroups] = useState([]);
|
||||
|
|
@ -9,7 +10,7 @@ const ViewTimetable = () => {
|
|||
api.get("/training-groups/getAll").then((res) => setGroups(res.data));
|
||||
}, []);
|
||||
|
||||
const days = ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"];
|
||||
const days = ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"];
|
||||
const hours = [
|
||||
"07:00", "08:00", "09:00", "10:00", "11:00",
|
||||
"12:00", "13:00", "14:00", "15:00", "16:00",
|
||||
|
|
@ -19,7 +20,8 @@ const ViewTimetable = () => {
|
|||
return (
|
||||
<div className="card">
|
||||
<h2>Horario Semanal</h2>
|
||||
<table className="styled-table" style={{ marginTop: "20px" }}>
|
||||
<div className="timetable-wrapper">
|
||||
<table className="styled-table timetable-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hora</th>
|
||||
|
|
@ -31,9 +33,9 @@ const ViewTimetable = () => {
|
|||
<tbody>
|
||||
{hours.map((h) => (
|
||||
<tr key={h}>
|
||||
<td>{h}</td>
|
||||
<td className="hour-label">{h}</td>
|
||||
{days.map((_, dayIndex) => (
|
||||
<td key={h + dayIndex}>
|
||||
<td key={h + dayIndex} className="day-cell">
|
||||
{groups
|
||||
.filter((g) => {
|
||||
const date = new Date(g.schedule);
|
||||
|
|
@ -43,7 +45,10 @@ const ViewTimetable = () => {
|
|||
);
|
||||
})
|
||||
.map((g) => (
|
||||
<div key={g.id}>{g.name} ({g.level})</div>
|
||||
<div key={g.id} className="timetable-block">
|
||||
<strong>{g.name}</strong>
|
||||
<div className="level-label">{g.level}</div>
|
||||
</div>
|
||||
))}
|
||||
</td>
|
||||
))}
|
||||
|
|
@ -52,6 +57,7 @@ const ViewTimetable = () => {
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import api from "../../api/axiosConfig";
|
||||
import ErrorMessage from "../common/ErrorMessage";
|
||||
import "../styles/ContentArea.css";
|
||||
|
||||
const StudentHistoryList = () => {
|
||||
const [histories, setHistories] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
const [editingId, setEditingId] = useState(null);
|
||||
const [editedData, setEditedData] = useState({});
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
const [successMsg, setSuccessMsg] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
fetchHistories();
|
||||
|
|
@ -15,27 +19,55 @@ const StudentHistoryList = () => {
|
|||
try {
|
||||
const res = await api.get("/student-history/getAll");
|
||||
setHistories(res.data);
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
console.error("Error al cargar historial de estudiantes", err);
|
||||
setError("Error al cargar historial");
|
||||
setErrorMsg("❌ Error al cargar historial.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditClick = (h) => {
|
||||
setEditingId(h.id);
|
||||
setEditedData({
|
||||
eventDate: h.eventDate,
|
||||
eventType: h.eventType || "",
|
||||
description: h.description || "",
|
||||
studentId: h.studentId,
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setEditedData((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleUpdate = async () => {
|
||||
try {
|
||||
await api.put(`/student-history/update/${editingId}`, editedData);
|
||||
setSuccessMsg("✅ Evento actualizado correctamente.");
|
||||
setErrorMsg("");
|
||||
setEditingId(null);
|
||||
fetchHistories();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setErrorMsg("❌ Error al actualizar el evento.");
|
||||
setSuccessMsg("");
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (id) => {
|
||||
if (
|
||||
!window.confirm("¿Seguro que quieres eliminar este evento del historial?")
|
||||
)
|
||||
return;
|
||||
if (!window.confirm("¿Seguro que quieres eliminar este evento del historial?")) return;
|
||||
|
||||
try {
|
||||
await api.delete(`/student-history/delete/${id}`);
|
||||
setHistories(histories.filter((h) => h.id !== id));
|
||||
alert("Evento eliminado correctamente");
|
||||
setHistories((prev) => prev.filter((h) => h.id !== id));
|
||||
setSuccessMsg("✅ Evento eliminado correctamente.");
|
||||
setErrorMsg("");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert("Error al eliminar el evento");
|
||||
setErrorMsg("❌ Error al eliminar el evento.");
|
||||
setSuccessMsg("");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -45,17 +77,14 @@ const StudentHistoryList = () => {
|
|||
<p>Cargando historial...</p>
|
||||
</div>
|
||||
);
|
||||
if (error)
|
||||
return (
|
||||
<div className="card">
|
||||
<p style={{ color: "red" }}>{error}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<h2>Historial de Estudiantes</h2>
|
||||
|
||||
<ErrorMessage message={errorMsg} type="error" />
|
||||
<ErrorMessage message={successMsg} type="success" />
|
||||
|
||||
{histories.length === 0 ? (
|
||||
<p>No hay eventos registrados.</p>
|
||||
) : (
|
||||
|
|
@ -73,6 +102,40 @@ const StudentHistoryList = () => {
|
|||
<tbody>
|
||||
{histories.map((h) => (
|
||||
<tr key={h.id}>
|
||||
{editingId === h.id ? (
|
||||
<>
|
||||
<td>
|
||||
{h.student?.user?.name} {h.student?.user?.surname}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="date"
|
||||
name="eventDate"
|
||||
value={editedData.eventDate}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
name="eventType"
|
||||
value={editedData.eventType}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
name="description"
|
||||
value={editedData.description}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button className="edit-btn" onClick={handleUpdate}>✅</button>
|
||||
<button className="delete-btn" onClick={() => setEditingId(null)}>❌</button>
|
||||
</td>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<td>
|
||||
{h.student?.user?.name} {h.student?.user?.surname}
|
||||
{(!h.student || !h.student.user) && `(ID: ${h.studentId})`}
|
||||
|
|
@ -81,19 +144,11 @@ const StudentHistoryList = () => {
|
|||
<td>{h.eventType}</td>
|
||||
<td>{h.description}</td>
|
||||
<td>
|
||||
<button
|
||||
className="edit-button"
|
||||
onClick={() => alert("Editar aún no implementado")}
|
||||
>
|
||||
✏️
|
||||
</button>
|
||||
<button
|
||||
className="delete-button"
|
||||
onClick={() => handleDelete(h.id)}
|
||||
>
|
||||
🗑️
|
||||
</button>
|
||||
<button className="edit-btn" onClick={() => handleEditClick(h)}>✏️</button>
|
||||
<button className="delete-btn" onClick={() => handleDelete(h.id)}>🗑️</button>
|
||||
</td>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -7,49 +7,93 @@ const TrainingGroupList = () => {
|
|||
const [groups, setGroups] = useState([]);
|
||||
const [teachers, setTeachers] = useState([]);
|
||||
const [editingGroupId, setEditingGroupId] = useState(null);
|
||||
const [newTeacherId, setNewTeacherId] = useState("");
|
||||
const [editedGroup, setEditedGroup] = useState({});
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
const [successMsg, setSuccessMsg] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const groupRes = await api.get("/training-groups/getAll");
|
||||
const teacherRes = await api.get("/teachers/getAll");
|
||||
setGroups(groupRes.data);
|
||||
setTeachers(teacherRes.data);
|
||||
} catch (err) {
|
||||
setErrorMsg("❌ Error al cargar los grupos o profesores.");
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateTeacher = async (groupId) => {
|
||||
const group = groups.find((g) => g.id === groupId);
|
||||
const updatedGroup = {
|
||||
...group,
|
||||
teacherId: parseInt(newTeacherId),
|
||||
const handleEditClick = (group) => {
|
||||
setEditingGroupId(group.id);
|
||||
setEditedGroup({
|
||||
name: group.name,
|
||||
level: group.level,
|
||||
schedule: group.schedule.slice(0, 16),
|
||||
teacherId: group.teacherId,
|
||||
});
|
||||
};
|
||||
|
||||
await api.put(`/training-groups/update/${groupId}`, updatedGroup);
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setEditedGroup((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleUpdate = async (id) => {
|
||||
try {
|
||||
await api.put(`/training-groups/update/${id}`, {
|
||||
...editedGroup,
|
||||
schedule: new Date(editedGroup.schedule).toISOString(),
|
||||
teacherId: parseInt(editedGroup.teacherId),
|
||||
studentIds: []
|
||||
});
|
||||
setSuccessMsg("✅ Grupo actualizado correctamente.");
|
||||
setErrorMsg("");
|
||||
setEditingGroupId(null);
|
||||
fetchData();
|
||||
} catch (err) {
|
||||
setErrorMsg("❌ Error al actualizar el grupo.");
|
||||
setSuccessMsg("");
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (groupId) => {
|
||||
if (window.confirm("Are you sure you want to delete this group?")) {
|
||||
await api.delete(`/training-groups/delete/${groupId}`);
|
||||
const handleDelete = async (id) => {
|
||||
if (!window.confirm("¿Estás seguro de que deseas eliminar este grupo?")) return;
|
||||
|
||||
try {
|
||||
await api.delete(`/training-groups/delete/${id}`);
|
||||
setSuccessMsg("✅ Grupo eliminado correctamente.");
|
||||
fetchData();
|
||||
} catch (err) {
|
||||
setErrorMsg("❌ Error al eliminar el grupo.");
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
const getTeacherName = (id) => {
|
||||
const teacher = teachers.find((t) => t.id === id);
|
||||
return teacher ? `${teacher.user?.name} ${teacher.user?.surname}` : `(ID ${id})`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<h2>Grupos de entrenamiento</h2>
|
||||
<h2>Grupos de Entrenamiento</h2>
|
||||
|
||||
<ErrorMessage message={errorMsg} type="error" />
|
||||
<ErrorMessage message={successMsg} type="success" />
|
||||
|
||||
<div className="table-wrapper">
|
||||
<table className="styled-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID Grupo</th>
|
||||
<th>ID</th>
|
||||
<th>Nombre</th>
|
||||
<th>Nivel</th>
|
||||
<th>Fecha / Hora</th>
|
||||
<th>Horario</th>
|
||||
<th>Profesor</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
|
|
@ -57,44 +101,63 @@ const TrainingGroupList = () => {
|
|||
<tbody>
|
||||
{groups.map((group) => (
|
||||
<tr key={group.id}>
|
||||
{editingGroupId === group.id ? (
|
||||
<>
|
||||
<td>{group.id}</td>
|
||||
<td>
|
||||
<input
|
||||
name="name"
|
||||
value={editedGroup.name}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
name="level"
|
||||
value={editedGroup.level}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="datetime-local"
|
||||
name="schedule"
|
||||
value={editedGroup.schedule}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
name="teacherId"
|
||||
value={editedGroup.teacherId}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<option value="">-- Selecciona profesor --</option>
|
||||
{teachers.map((t) => (
|
||||
<option key={t.id} value={t.id}>
|
||||
{t.user?.name} {t.user?.surname}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button className="edit-btn" onClick={() => handleUpdate(group.id)}>✅</button>
|
||||
<button className="delete-btn" onClick={() => setEditingGroupId(null)}>❌</button>
|
||||
</td>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<td>{group.id}</td>
|
||||
<td>{group.name}</td>
|
||||
<td>{group.level}</td>
|
||||
<td>{new Date(group.schedule).toLocaleString()}</td>
|
||||
<td>{getTeacherName(group.teacherId)}</td>
|
||||
<td>
|
||||
{editingGroupId === group.id ? (
|
||||
<select
|
||||
value={newTeacherId}
|
||||
onChange={(e) => setNewTeacherId(e.target.value)}
|
||||
>
|
||||
<option value="">-- Select --</option>
|
||||
{teachers.map((teacher) => (
|
||||
<option key={teacher.id} value={teacher.id}>
|
||||
{teacher.user?.name} {teacher.user?.surname}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
`${group.teacherId}`
|
||||
)}
|
||||
<button className="edit-btn" onClick={() => handleEditClick(group)}>✏️</button>
|
||||
<button className="delete-btn" onClick={() => handleDelete(group.id)}>🗑️</button>
|
||||
</td>
|
||||
<td>
|
||||
{editingGroupId === group.id ? (
|
||||
<button onClick={() => handleUpdateTeacher(group.id)}>
|
||||
Save
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditingGroupId(group.id);
|
||||
setNewTeacherId(group.teacherId || "");
|
||||
}}
|
||||
>
|
||||
Edit Teacher
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<button onClick={() => handleDelete(group.id)}>Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -264,6 +264,28 @@ form textarea:focus {
|
|||
outline: none;
|
||||
}
|
||||
|
||||
.group-student-list li {
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 6px;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #dcdde1;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.group-student-list li:hover {
|
||||
background-color: #f0f4f8;
|
||||
}
|
||||
|
||||
.group-student-list li .delete-button,
|
||||
.group-student-list li .add-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
/* Ajuste general de la tabla */
|
||||
.timetable-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.timetable-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed; /* fuerza a que todas las celdas tengan el mismo ancho */
|
||||
}
|
||||
|
||||
.timetable-table th,
|
||||
.timetable-table td {
|
||||
padding: 6px;
|
||||
text-align: center;
|
||||
border: 1px solid #dcdde1;
|
||||
height: 60px; /* ajusta esto si lo quieres más compacto */
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Hora a la izquierda */
|
||||
.hour-label {
|
||||
font-weight: bold;
|
||||
background-color: #f0f0f0;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
/* Celda del día */
|
||||
.day-cell {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Tarjeta dentro de la celda */
|
||||
.timetable-block {
|
||||
background-color: #2ecc71;
|
||||
color: white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
padding: 4px;
|
||||
border-radius: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
Loading…
Reference in New Issue