Add training times management and enhance diary view with group selection dialog
This commit introduces the `TrainingTime` model and related functionality, allowing for the management of training times associated with training groups. The backend is updated to include new routes for training times, while the frontend is enhanced with a new dialog in the `DiaryView` for selecting training groups and suggesting available training times. This improves user experience by streamlining the process of scheduling training sessions and managing associated data.
This commit is contained in:
142
backend/services/trainingTimeService.js
Normal file
142
backend/services/trainingTimeService.js
Normal file
@@ -0,0 +1,142 @@
|
||||
import { checkAccess } from '../utils/userUtils.js';
|
||||
import TrainingTime from '../models/TrainingTime.js';
|
||||
import TrainingGroup from '../models/TrainingGroup.js';
|
||||
import HttpError from '../exceptions/HttpError.js';
|
||||
|
||||
class TrainingTimeService {
|
||||
async getTrainingTimes(userToken, clubId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
|
||||
const groups = await TrainingGroup.findAll({
|
||||
where: { clubId },
|
||||
include: [{
|
||||
model: TrainingTime,
|
||||
as: 'trainingTimes',
|
||||
required: false,
|
||||
separate: true,
|
||||
order: [['weekday', 'ASC'], ['sortOrder', 'ASC'], ['startTime', 'ASC']]
|
||||
}],
|
||||
order: [['isPreset', 'DESC'], ['sortOrder', 'ASC'], ['name', 'ASC']]
|
||||
});
|
||||
|
||||
return groups.map(group => {
|
||||
const groupData = group.toJSON ? group.toJSON() : group;
|
||||
return {
|
||||
...groupData,
|
||||
trainingTimes: Array.isArray(groupData.trainingTimes)
|
||||
? groupData.trainingTimes.sort((a, b) => {
|
||||
if (a.weekday !== b.weekday) return a.weekday - b.weekday;
|
||||
if (a.sortOrder !== b.sortOrder) return a.sortOrder - b.sortOrder;
|
||||
return a.startTime.localeCompare(b.startTime);
|
||||
})
|
||||
: []
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async createTrainingTime(userToken, clubId, trainingGroupId, weekday, startTime, endTime) {
|
||||
await checkAccess(userToken, clubId);
|
||||
|
||||
// Validate that the training group belongs to the club
|
||||
const group = await TrainingGroup.findOne({
|
||||
where: { id: trainingGroupId, clubId }
|
||||
});
|
||||
|
||||
if (!group) {
|
||||
throw new HttpError('Trainingsgruppe nicht gefunden', 404);
|
||||
}
|
||||
|
||||
// Validate weekday (0-6)
|
||||
if (weekday < 0 || weekday > 6) {
|
||||
throw new HttpError('Ungültiger Wochentag (0-6)', 400);
|
||||
}
|
||||
|
||||
// Validate times
|
||||
if (!startTime || !endTime) {
|
||||
throw new HttpError('Start- und Endzeit müssen angegeben werden', 400);
|
||||
}
|
||||
|
||||
if (startTime >= endTime) {
|
||||
throw new HttpError('Startzeit muss vor Endzeit liegen', 400);
|
||||
}
|
||||
|
||||
// Get max sortOrder for this weekday and group
|
||||
const maxSortOrder = await TrainingTime.max('sortOrder', {
|
||||
where: {
|
||||
trainingGroupId,
|
||||
weekday
|
||||
}
|
||||
}) || 0;
|
||||
|
||||
const trainingTime = await TrainingTime.create({
|
||||
trainingGroupId,
|
||||
weekday,
|
||||
startTime,
|
||||
endTime,
|
||||
sortOrder: maxSortOrder + 1
|
||||
});
|
||||
|
||||
return trainingTime;
|
||||
}
|
||||
|
||||
async updateTrainingTime(userToken, clubId, timeId, weekday, startTime, endTime) {
|
||||
await checkAccess(userToken, clubId);
|
||||
|
||||
const trainingTime = await TrainingTime.findByPk(timeId, {
|
||||
include: [{
|
||||
model: TrainingGroup,
|
||||
as: 'trainingGroup'
|
||||
}]
|
||||
});
|
||||
|
||||
if (!trainingTime || !trainingTime.trainingGroup) {
|
||||
throw new HttpError('Trainingszeit nicht gefunden', 404);
|
||||
}
|
||||
|
||||
if (trainingTime.trainingGroup.clubId !== parseInt(clubId)) {
|
||||
throw new HttpError('Keine Berechtigung', 403);
|
||||
}
|
||||
|
||||
// Validate weekday (0-6)
|
||||
if (weekday !== undefined && (weekday < 0 || weekday > 6)) {
|
||||
throw new HttpError('Ungültiger Wochentag (0-6)', 400);
|
||||
}
|
||||
|
||||
// Validate times
|
||||
if (startTime && endTime && startTime >= endTime) {
|
||||
throw new HttpError('Startzeit muss vor Endzeit liegen', 400);
|
||||
}
|
||||
|
||||
if (weekday !== undefined) trainingTime.weekday = weekday;
|
||||
if (startTime !== undefined) trainingTime.startTime = startTime;
|
||||
if (endTime !== undefined) trainingTime.endTime = endTime;
|
||||
|
||||
await trainingTime.save();
|
||||
return trainingTime;
|
||||
}
|
||||
|
||||
async deleteTrainingTime(userToken, clubId, timeId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
|
||||
const trainingTime = await TrainingTime.findByPk(timeId, {
|
||||
include: [{
|
||||
model: TrainingGroup,
|
||||
as: 'trainingGroup'
|
||||
}]
|
||||
});
|
||||
|
||||
if (!trainingTime || !trainingTime.trainingGroup) {
|
||||
throw new HttpError('Trainingszeit nicht gefunden', 404);
|
||||
}
|
||||
|
||||
if (trainingTime.trainingGroup.clubId !== parseInt(clubId)) {
|
||||
throw new HttpError('Keine Berechtigung', 403);
|
||||
}
|
||||
|
||||
await trainingTime.destroy();
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
export default new TrainingTimeService();
|
||||
|
||||
Reference in New Issue
Block a user