diff --git a/backend/controllers/diaryDateActivityController.js b/backend/controllers/diaryDateActivityController.js index 38629ec..9f80f51 100644 --- a/backend/controllers/diaryDateActivityController.js +++ b/backend/controllers/diaryDateActivityController.js @@ -137,6 +137,36 @@ export const addGroupActivity = async(req, res) => { } } +export const updateGroupActivity = async(req, res) => { + try { + const { authcode: userToken } = req.headers; + const { clubId, groupActivityId } = req.params; + const { predefinedActivityId } = req.body; + const activityItem = await diaryDateActivityService.updateGroupActivity(userToken, clubId, groupActivityId, predefinedActivityId); + + // Emit Socket-Event + const GroupActivity = (await import('../models/GroupActivity.js')).default; + const DiaryDateActivity = (await import('../models/DiaryDateActivity.js')).default; + const groupActivity = await GroupActivity.findByPk(groupActivityId); + let diaryDateId = null; + if (groupActivity?.diaryDateActivity) { + const activity = await DiaryDateActivity.findByPk(groupActivity.diaryDateActivity); + diaryDateId = activity?.diaryDateId; + } + if (diaryDateId) { + const diaryDate = await DiaryDate.findByPk(diaryDateId); + if (diaryDate?.clubId) { + emitActivityChanged(diaryDate.clubId, diaryDateId); + } + } + + res.status(200).json(activityItem); + } catch (error) { + devLog(error); + res.status(500).json({ error: 'Error updating group activity' }); + } +} + export const deleteGroupActivity = async(req, res) => { try { const { authcode: userToken } = req.headers; diff --git a/backend/routes/diaryDateActivityRoutes.js b/backend/routes/diaryDateActivityRoutes.js index 3f9ecc0..44ac94e 100644 --- a/backend/routes/diaryDateActivityRoutes.js +++ b/backend/routes/diaryDateActivityRoutes.js @@ -6,6 +6,7 @@ import { updateDiaryDateActivityOrder, getDiaryDateActivities, addGroupActivity, + updateGroupActivity, deleteGroupActivity, } from '../controllers/diaryDateActivityController.js'; import { authenticate } from '../middleware/authMiddleware.js'; @@ -15,6 +16,7 @@ const router = express.Router(); router.use(authenticate); router.post('/group', addGroupActivity); +router.put('/group/:clubId/:groupActivityId', updateGroupActivity); router.delete('/group/:clubId/:groupActivityId', deleteGroupActivity); router.post('/:clubId/', createDiaryDateActivity); router.put('/:clubId/:id/order', updateDiaryDateActivityOrder); diff --git a/backend/services/diaryDateActivityService.js b/backend/services/diaryDateActivityService.js index 2c381c0..3a3b072 100644 --- a/backend/services/diaryDateActivityService.js +++ b/backend/services/diaryDateActivityService.js @@ -391,6 +391,24 @@ class DiaryDateActivityService { return await GroupActivity.create(activityData); } + async updateGroupActivity(userToken, clubId, groupActivityId, predefinedActivityId) { + await checkAccess(userToken, clubId); + const groupActivity = await GroupActivity.findByPk(groupActivityId); + if (!groupActivity) { + throw new Error('Group activity not found'); + } + + // Prüfe, ob die PredefinedActivity existiert + const predefinedActivity = await PredefinedActivity.findByPk(predefinedActivityId); + if (!predefinedActivity) { + throw new Error('Predefined activity not found'); + } + + // Aktualisiere die customActivity (die auf die PredefinedActivity verweist) + groupActivity.customActivity = predefinedActivityId; + return await groupActivity.save(); + } + async deleteGroupActivity(userToken, clubId, groupActivityId) { await checkAccess(userToken, clubId); const groupActivity = await GroupActivity.findByPk(groupActivityId); diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 63bb9a6..52b8e55 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -352,7 +352,9 @@ "trainingTimesUpdated": "Trainingszeiten erfolgreich aktualisiert.", "formMarkedAsHandedOver": "Mitgliedsformular als ausgehändigt markiert", "errorMarkingForm": "Fehler beim Markieren des Mitgliedsformulars", - "dateNoLongerCurrent": "Ausgewähltes Datum war nicht mehr aktuell. Bitte erneut versuchen." + "dateNoLongerCurrent": "Ausgewähltes Datum war nicht mehr aktuell. Bitte erneut versuchen.", + "activityRequired": "Bitte geben Sie eine Aktivität ein.", + "activityNotFound": "Aktivität nicht gefunden. Bitte wählen Sie eine aus der Liste aus." }, "home": { "welcome": "Willkommen im TrainingsTagebuch", diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index 337d7eb..4b46616 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -176,6 +176,15 @@
+
-
@@ -290,6 +294,11 @@
+
@@ -303,7 +312,38 @@ - +
+ +
+ + +
+ + +
+
+
- @@ -369,7 +407,7 @@ - +
@@ -425,6 +449,11 @@
+ @@ -675,9 +704,9 @@ 0) return true; + } + // Prüfe auch über predefinedActivity + if (item.predefinedActivity && this.hasActivityVisual(item.predefinedActivity)) return true; + } catch (e) { } + return false; + }, + hasActivityVisual(pa) { if (!pa) return false; try { @@ -2483,28 +2528,60 @@ export default { try { const code = result.code.trim(); - // Wenn eine Gruppenaktivität bearbeitet wird + // Wenn eine Gruppenaktivität oder normale Aktivität bearbeitet wird if (this.editingGroupActivity && this.editingGroupActivity.groupPredefinedActivity) { const predefinedActivityId = this.editingGroupActivity.groupPredefinedActivity.id; - // Aktualisiere die PredefinedActivity - const updateData = { - name: result.name || (result.fields && result.fields.name) || this.editingGroupActivity.groupPredefinedActivity.name || '', - code: code, - description: result.description || (result.fields && result.fields.description) || this.editingGroupActivity.groupPredefinedActivity.description || '', - durationText: this.editingGroupActivity.groupPredefinedActivity.durationText || '', - duration: this.editingGroupActivity.groupPredefinedActivity.duration || null, - imageLink: this.editingGroupActivity.groupPredefinedActivity.imageLink || '', - drawingData: result.drawingData || null - }; + let finalPredefinedActivityId = predefinedActivityId; - await apiClient.put(`/predefined-activities/${predefinedActivityId}`, updateData); + // Wenn keine predefinedActivityId vorhanden ist, erstelle eine neue + if (!predefinedActivityId) { + const newActivityData = { + name: result.name || (result.fields && result.fields.name) || this.editingGroupActivity.groupPredefinedActivity.name || '', + code: code, + description: result.description || (result.fields && result.fields.description) || this.editingGroupActivity.groupPredefinedActivity.description || '', + drawingData: result.drawingData || null + }; + + const createResponse = await apiClient.post('/predefined-activities', newActivityData); + finalPredefinedActivityId = createResponse.data.id; + + // Wenn es eine normale Aktivität war, verknüpfe die DiaryDateActivity mit der neuen PredefinedActivity + if (this.editingGroupActivity.isNormalActivity && this.editingGroupActivity.activityItem) { + const activityItem = this.editingGroupActivity.activityItem; + if (activityItem.id && this.currentClub) { + // currentClub ist die Club-ID (Zahl), nicht ein Objekt + await apiClient.put(`/diary-date-activities/${this.currentClub}/${activityItem.id}`, { + predefinedActivityId: finalPredefinedActivityId + }); + } + } + } else { + // Aktualisiere die existierende PredefinedActivity + const updateData = { + name: result.name || (result.fields && result.fields.name) || this.editingGroupActivity.groupPredefinedActivity.name || '', + code: code, + description: result.description || (result.fields && result.fields.description) || this.editingGroupActivity.groupPredefinedActivity.description || '', + durationText: this.editingGroupActivity.groupPredefinedActivity.durationText || '', + duration: this.editingGroupActivity.groupPredefinedActivity.duration || null, + imageLink: this.editingGroupActivity.groupPredefinedActivity.imageLink || '', + drawingData: result.drawingData || null + }; + + await apiClient.put(`/predefined-activities/${predefinedActivityId}`, updateData); + } // Lade den Trainingsplan neu if (this.date && this.date.id) { await this.loadTrainingPlan(); } + // Wenn es eine normale Aktivität war, beende auch den Inline-Edit-Modus + if (this.editingGroupActivity.isNormalActivity && this.editingGroupActivity.activityItem) { + this.editingActivityId = null; + this.editingActivityText = ''; + } + this.editingGroupActivity = null; return; } @@ -2570,6 +2647,39 @@ export default { } }, + editActivity(item) { + if (!item) { + this.showInfo('Fehler', 'Keine Aktivität zum Bearbeiten gefunden', '', 'error'); + return; + } + + // Wenn keine predefinedActivity vorhanden ist, aber drawingData, erstelle eine temporäre Struktur + let predefinedActivity = item.predefinedActivity; + if (!predefinedActivity && item.drawingData) { + // Erstelle eine temporäre Struktur für die Bearbeitung + predefinedActivity = { + id: null, + name: item.activity || '', + code: item.activity || '', + description: '', + drawingData: item.drawingData + }; + } + + if (!predefinedActivity) { + this.showInfo('Fehler', 'Keine Aktivität zum Bearbeiten gefunden', '', 'error'); + return; + } + + // Verwende editingGroupActivity auch für normale Aktivitäten, da die Struktur ähnlich ist + this.editingGroupActivity = { + groupPredefinedActivity: predefinedActivity, + isNormalActivity: true, + activityItem: item + }; + this.showDrawingDialog = true; + }, + editGroupActivity(groupItem) { if (!groupItem || !groupItem.groupPredefinedActivity) { this.showInfo('Fehler', 'Keine Aktivität zum Bearbeiten gefunden', '', 'error'); @@ -2578,6 +2688,89 @@ export default { this.editingGroupActivity = groupItem; this.showDrawingDialog = true; }, + + startGroupActivityEdit(groupItem) { + console.log('[startGroupActivityEdit] groupItem.id:', groupItem.id, 'type:', typeof groupItem.id); + this.editingGroupActivityId = Number(groupItem.id); + this.editSearchForId = Number(groupItem.id); + console.log('[startGroupActivityEdit] editingGroupActivityId set to:', this.editingGroupActivityId); + this.$nextTick(() => { + const inputs = this.$el.querySelectorAll('input[type="text"]'); + const lastInput = inputs[inputs.length - 1]; + if (lastInput) { + lastInput.focus(); + } + }); + this.editingGroupActivityText = groupItem.groupPredefinedActivity + ? (groupItem.groupPredefinedActivity.code && groupItem.groupPredefinedActivity.code.trim() !== '' + ? groupItem.groupPredefinedActivity.code + : groupItem.groupPredefinedActivity.name) + : ''; + }, + + async onEditGroupActivityInputChange(groupItem) { + const term = this.editingGroupActivityText; + this.editSearchForId = groupItem.id; + if (!term || term.trim().length < 2) { + this.editShowDropdown = false; + this.editSearchResults = []; + return; + } + const results = await this.searchPredefinedActivities(term); + this.editSearchResults = results; + this.editShowDropdown = results.length > 0; + }, + + chooseEditGroupActivitySuggestion(s, groupItem) { + this.editingGroupActivityText = (s.code && s.code.trim() !== '') ? s.code : s.name; + this.editShowDropdown = false; + this.editSearchResults = []; + }, + + async saveGroupActivityEdit(groupItem) { + try { + if (!this.editingGroupActivityText || !this.editingGroupActivityText.trim()) { + this.showInfo(this.$t('messages.note'), this.$t('diary.activityRequired'), '', 'warning'); + return; + } + + // Suche nach der PredefinedActivity + const searchResults = await this.searchPredefinedActivities(this.editingGroupActivityText.trim()); + const existing = searchResults.find(a => { + const searchTerm = this.editingGroupActivityText.trim().toLowerCase(); + return (a.code && a.code.trim().toLowerCase() === searchTerm) || + (a.name && a.name.trim().toLowerCase() === searchTerm); + }); + + if (!existing) { + this.showInfo(this.$t('messages.note'), this.$t('diary.activityNotFound'), '', 'warning'); + return; + } + + // Aktualisiere die Gruppenaktivität mit der neuen PredefinedActivity + await apiClient.put(`/diary-date-activities/group/${this.currentClub}/${groupItem.id}`, { + predefinedActivityId: existing.id + }); + + // Lade den Trainingsplan neu + await this.loadTrainingPlan(); + + this.editingGroupActivityId = null; + this.editingGroupActivityText = ''; + this.editShowDropdown = false; + this.editSearchResults = []; + } catch (error) { + const msg = getSafeErrorMessage(error, 'Fehler beim Speichern der Gruppenaktivität'); + this.showInfo('Fehler', msg, '', 'error'); + } + }, + + cancelGroupActivityEdit() { + this.editingGroupActivityId = null; + this.editingGroupActivityText = ''; + this.editShowDropdown = false; + this.editSearchResults = []; + }, async loadTrainingPlan() { try {