feat(ParticipantController, ParticipantModel, ParticipantRoutes, DiaryParticipantsPanel, i18n): implement participant status management and UI updates

- Added functionality to update participant attendance status, allowing for 'excused' and 'cancelled' states.
- Enhanced the participant model to include a default attendance status and validation for status values.
- Updated participant routes to support status updates and integrated new status handling in the participant controller.
- Modified the DiaryParticipantsPanel to visually indicate participant status and added a toggle for changing status.
- Expanded localization files to include new keys for participant status, improving accessibility for users in both English and German.
This commit is contained in:
Torsten Schulz (local)
2026-03-17 15:23:35 +01:00
parent 46812a0c14
commit 483d5d2bc7
7 changed files with 262 additions and 25 deletions

View File

@@ -1,13 +1,17 @@
import Participant from '../models/Participant.js';
import DiaryDates from '../models/DiaryDates.js';
import DiaryMemberActivity from '../models/DiaryMemberActivity.js';
import { devLog } from '../utils/logger.js';
import { emitParticipantAdded, emitParticipantRemoved, emitParticipantUpdated } from '../services/socketService.js';
const PARTICIPANT_ATTRIBUTES = ['id', 'diaryDateId', 'memberId', 'attendanceStatus', 'groupId', 'notes', 'createdAt', 'updatedAt'];
export const getParticipants = async (req, res) => {
try {
const { dateId } = req.params;
const participants = await Participant.findAll({
where: { diaryDateId: dateId },
attributes: ['id', 'diaryDateId', 'memberId', 'groupId', 'notes', 'createdAt', 'updatedAt']
attributes: PARTICIPANT_ATTRIBUTES
});
res.status(200).json(participants);
} catch (error) {
@@ -68,12 +72,22 @@ export const updateParticipantGroup = async (req, res) => {
export const addParticipant = async (req, res) => {
try {
const { diaryDateId, memberId } = req.body;
const participant = await Participant.create({ diaryDateId, memberId });
const [participant, created] = await Participant.findOrCreate({
where: { diaryDateId, memberId },
defaults: { diaryDateId, memberId, attendanceStatus: 'present' }
});
participant.attendanceStatus = 'present';
await participant.save();
// Hole DiaryDate für clubId
const diaryDate = await DiaryDates.findByPk(diaryDateId);
if (diaryDate?.clubId) {
emitParticipantAdded(diaryDate.clubId, diaryDateId, participant);
if (created) {
emitParticipantAdded(diaryDate.clubId, diaryDateId, participant);
} else {
emitParticipantUpdated(diaryDate.clubId, diaryDateId, participant);
}
}
res.status(201).json(participant);
@@ -90,6 +104,15 @@ export const removeParticipant = async (req, res) => {
// Hole DiaryDate für clubId vor dem Löschen
const diaryDate = await DiaryDates.findByPk(diaryDateId);
const clubId = diaryDate?.clubId;
const participant = await Participant.findOne({
where: { diaryDateId, memberId },
attributes: ['id']
});
if (participant) {
await DiaryMemberActivity.destroy({ where: { participantId: participant.id } });
}
await Participant.destroy({ where: { diaryDateId, memberId } });
@@ -104,3 +127,53 @@ export const removeParticipant = async (req, res) => {
res.status(500).json({ error: 'Fehler beim Entfernen des Teilnehmers' });
}
};
export const updateParticipantStatus = async (req, res) => {
try {
const { dateId, memberId } = req.params;
const { attendanceStatus } = req.body;
if (!['excused', 'cancelled'].includes(attendanceStatus)) {
return res.status(400).json({ error: 'Ungültiger Teilnehmerstatus' });
}
const diaryDate = await DiaryDates.findByPk(dateId);
if (!diaryDate) {
return res.status(404).json({ error: 'Trainingstag nicht gefunden' });
}
const [participant] = await Participant.findOrCreate({
where: {
diaryDateId: dateId,
memberId
},
defaults: {
diaryDateId: dateId,
memberId,
attendanceStatus
}
});
participant.attendanceStatus = attendanceStatus;
participant.groupId = null;
await participant.save();
await DiaryMemberActivity.destroy({ where: { participantId: participant.id } });
const updatedParticipant = await Participant.findOne({
where: {
diaryDateId: dateId,
memberId
},
attributes: PARTICIPANT_ATTRIBUTES
});
if (diaryDate.clubId && updatedParticipant) {
emitParticipantUpdated(diaryDate.clubId, dateId, updatedParticipant);
}
res.status(200).json(updatedParticipant || participant);
} catch (error) {
devLog(error);
res.status(500).json({ error: 'Fehler beim Aktualisieren des Teilnehmerstatus' });
}
};