diff --git a/backend/controllers/memberController.js b/backend/controllers/memberController.js index d22f085..04759b3 100644 --- a/backend/controllers/memberController.js +++ b/backend/controllers/memberController.js @@ -80,4 +80,25 @@ const updateRatingsFromMyTischtennis = async (req, res) => { } }; -export { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis }; \ No newline at end of file +const rotateMemberImage = async (req, res) => { + try { + const { clubId, memberId } = req.params; + const { direction } = req.body; + const { authcode: userToken } = req.headers; + + if (!direction || !['left', 'right'].includes(direction)) { + return res.status(400).json({ + success: false, + error: 'Ungültige Drehrichtung. Verwenden Sie "left" oder "right".' + }); + } + + const result = await MemberService.rotateMemberImage(userToken, clubId, memberId, direction); + res.status(result.status).json(result.response); + } catch (error) { + console.error('[rotateMemberImage] - Error:', error); + res.status(500).json({ success: false, error: 'Failed to rotate image' }); + } +}; + +export { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis, rotateMemberImage }; \ No newline at end of file diff --git a/backend/routes/memberRoutes.js b/backend/routes/memberRoutes.js index 3b3b8ab..ecbab85 100644 --- a/backend/routes/memberRoutes.js +++ b/backend/routes/memberRoutes.js @@ -1,4 +1,4 @@ -import { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis } from '../controllers/memberController.js'; +import { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis, rotateMemberImage } from '../controllers/memberController.js'; import express from 'express'; import { authenticate } from '../middleware/authMiddleware.js'; import multer from 'multer'; @@ -14,5 +14,6 @@ router.get('/get/:id/:showAll', authenticate, getClubMembers); router.post('/set/:id', authenticate, setClubMembers); router.get('/notapproved/:id', authenticate, getWaitingApprovals); router.post('/update-ratings/:id', authenticate, updateRatingsFromMyTischtennis); +router.post('/rotate-image/:clubId/:memberId', authenticate, rotateMemberImage); export default router; diff --git a/backend/services/memberService.js b/backend/services/memberService.js index 834b934..cc1fe1a 100644 --- a/backend/services/memberService.js +++ b/backend/services/memberService.js @@ -320,6 +320,56 @@ class MemberService { }; } } + + async rotateMemberImage(userToken, clubId, memberId, direction) { + try { + await checkAccess(userToken, clubId); + const member = await Member.findOne({ where: { id: memberId, clubId: clubId } }); + + if (!member) { + return { status: 404, response: { success: false, error: 'Member not found in this club' } }; + } + + const imagePath = path.join('images', 'members', `${memberId}.jpg`); + if (!fs.existsSync(imagePath)) { + return { status: 404, response: { success: false, error: 'Image not found' } }; + } + + // Read the image + const imageBuffer = await fs.promises.readFile(imagePath); + + // Calculate rotation angle (-90 for left, +90 for right) + const rotationAngle = direction === 'left' ? -90 : 90; + + // Rotate the image + const rotatedBuffer = await sharp(imageBuffer) + .rotate(rotationAngle) + .jpeg({ quality: 80 }) + .toBuffer(); + + // Save the rotated image + await fs.promises.writeFile(imagePath, rotatedBuffer); + + return { + status: 200, + response: { + success: true, + message: `Bild um ${rotationAngle}° gedreht`, + direction: direction, + rotation: rotationAngle + } + }; + } catch (error) { + console.error('[rotateMemberImage] - Error:', error); + return { + status: 500, + response: { + success: false, + error: 'Fehler beim Drehen des Bildes: ' + error.message + } + }; + } + } } export default new MemberService(); \ No newline at end of file diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index fb8cc55..6e714e9 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -571,12 +571,61 @@ export default { if (this.isAuthenticated && this.currentClub) { const response = await apiClient.get(`/diary/${this.currentClub}`); this.dates = response.data.map(entry => ({ id: entry.id, date: entry.date })); + + // Automatisch das Datum mit den meisten Einträgen auswählen + await this.autoSelectDateWithEntries(); + await this.loadTags(); await this.loadPredefinedActivities(); } }, - + async autoSelectDateWithEntries() { + if (this.dates.length === 0) { + this.date = 'new'; + return; + } + + const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD Format + + // 1. Zuerst prüfe das heutige Datum + const todayEntry = this.dates.find(date => date.date === today); + if (todayEntry) { + const todayEntries = await this.countEntriesForDate(todayEntry.id); + if (todayEntries > 0) { + this.date = todayEntry; + await this.handleDateChange(); + return; + } + } + + // 2. Falls heutiges Datum nicht gefunden oder keine Einträge vorhanden + // → Bleibe bei "Neu anlegen" + this.date = 'new'; + this.showForm = true; + }, + + async countEntriesForDate(dateId) { + try { + // Lade Teilnehmer + const participantsResponse = await apiClient.get(`/participants/${dateId}`); + const participantCount = participantsResponse.data.length; + + // Lade Aktivitäten + const activitiesResponse = await apiClient.get(`/activities/${dateId}`); + const activityCount = activitiesResponse.data.length; + + // Lade Trainingplan + const trainingPlanResponse = await apiClient.get(`/diary-date-activities/${this.currentClub}/${dateId}`); + const trainingPlanCount = trainingPlanResponse.data.length; + + // Gesamtanzahl der Einträge + return participantCount + activityCount + trainingPlanCount; + } catch (error) { + console.warn(`Fehler beim Laden der Einträge für Datum ${dateId}:`, error); + return 0; + } + }, async refreshDates(selectId) { const response = await apiClient.get(`/diary/${this.currentClub}`); diff --git a/frontend/src/views/MembersView.vue b/frontend/src/views/MembersView.vue index 56bf013..cd3fdce 100644 --- a/frontend/src/views/MembersView.vue +++ b/frontend/src/views/MembersView.vue @@ -74,7 +74,7 @@ Mitgliedsbild + @click.stop="openImageModal(member.imageUrl, member.id)"> {{ member.picsInInternetAllowed ? '✓' : '' }} {{ member.testMembership ? '*' : '' }} @@ -107,9 +107,20 @@