diff --git a/backend/controllers/diaryMemberController.js b/backend/controllers/diaryMemberController.js
index 337bba0..ba9886f 100644
--- a/backend/controllers/diaryMemberController.js
+++ b/backend/controllers/diaryMemberController.js
@@ -5,6 +5,7 @@ const getMemberTags = async (req, res) => {
const { diaryDateId, memberId } = req.query;
const { clubId } = req.params;
const { authcode: userToken } = req.headers;
+ console.log(diaryDateId, memberId, clubId);
const tags = await DiaryMemberService.getTagsForMemberAndDate(userToken, clubId, diaryDateId, memberId);
res.status(200).json(tags);
} catch (error) {
diff --git a/backend/controllers/diaryTagController.js b/backend/controllers/diaryTagController.js
index a5b3763..49ddf9c 100644
--- a/backend/controllers/diaryTagController.js
+++ b/backend/controllers/diaryTagController.js
@@ -12,9 +12,11 @@ export const getTags = async (req, res) => {
export const createTag = async (req, res) => {
try {
const { name } = req.body;
- const newTag = await DiaryTag.create({ name });
+ console.log(name);
+ const newTag = await DiaryTag.findOrCreate({ where: { name }, defaults: { name } });
res.status(201).json(newTag);
} catch (error) {
+ console.log('[createTag] - Error:', error);
res.status(500).json({ error: 'Error creating tag' });
}
};
diff --git a/backend/models/index.js b/backend/models/index.js
index a0fda39..d3bdfad 100644
--- a/backend/models/index.js
+++ b/backend/models/index.js
@@ -108,6 +108,9 @@ GroupActivity.belongsTo(Group, { foreignKey: 'groupId', as: 'groupsGroupActivity
GroupActivity.belongsTo(PredefinedActivity, { foreignKey: 'customActivity', as: 'groupPredefinedActivity' });
PredefinedActivity.hasMany(GroupActivity, { foreignKey: 'predefinedActivityId', as: 'groupPredefinedActivities' });
+DiaryTag.hasMany(DiaryDateTag, { foreignKey: 'tagId', as: 'diaryDateTags' });
+DiaryDateTag.belongsTo(DiaryTag, { foreignKey: 'tagId', as: 'tag' });
+
export {
User,
Log,
diff --git a/backend/routes/diaryTagRoutes.js b/backend/routes/diaryTagRoutes.js
index 25f4ff5..b2ed8fa 100644
--- a/backend/routes/diaryTagRoutes.js
+++ b/backend/routes/diaryTagRoutes.js
@@ -4,8 +4,10 @@ import { authenticate } from '../middleware/authMiddleware.js';
const router = express.Router();
-router.get('/', authenticate, getTags);
-router.post('/', authenticate, createTag);
-router.delete('/:tagId', authenticate, deleteTag);
+router.use(authenticate);
+
+router.get('/', getTags);
+router.post('/', createTag);
+router.delete('/:tagId', deleteTag);
export default router;
diff --git a/backend/services/diaryMemberService.js b/backend/services/diaryMemberService.js
index 86c5d1b..98cbd78 100644
--- a/backend/services/diaryMemberService.js
+++ b/backend/services/diaryMemberService.js
@@ -14,6 +14,7 @@ class DiaryMemberService {
async getNotesForMember(userToken, clubId, diaryDateId, memberId) {
await checkAccess(userToken, clubId);
+ console.log(clubId, diaryDateId, memberId);
return await DiaryMemberNote.findAll({ where: { diaryDateId, memberId }, order: [['createdAt', 'DESC']] });
}
diff --git a/backend/services/diaryService.js b/backend/services/diaryService.js
index 0b97255..c0f236d 100644
--- a/backend/services/diaryService.js
+++ b/backend/services/diaryService.js
@@ -109,21 +109,33 @@ class DiaryService {
if (!diaryDate) {
throw new HttpError('DiaryDate not found', 404);
}
+ console.log('[DiaryService::addTagToDiaryDate] - Add tag to diary date');
const existingEntry = await DiaryDateTag.findOne({
where: { diaryDateId, tagId }
});
if (existingEntry) {
return;
}
+ console.log('[DiaryService::addTagToDiaryDate] - Tag not found, creating new entry');
const tag = await DiaryTag.findByPk(tagId);
if (!tag) {
throw new HttpError('Tag not found', 404);
}
+ console.log('[DiaryService::addTagToDiaryDate] - Add tag to diary date');
await DiaryDateTag.create({
diaryDateId,
tagId
- })
- return diaryDate.getDiaryTags();
+ });
+ console.log('[DiaryService::addTagToDiaryDate] - Get tags');
+ const tags = await DiaryDateTag.findAll({ where: {
+ diaryDateId: diaryDateId },
+ include: {
+ model: DiaryTag,
+ as: 'tag'
+ }
+ });
+ console.log(tags);
+ return tags.map(tag => tag.tag);
}
async getDiaryNotesForDateAndMember(diaryDateId, memberId) {
diff --git a/frontend/src/assets/css/main.scss b/frontend/src/assets/css/main.scss
index 5057895..c90c0f0 100644
--- a/frontend/src/assets/css/main.scss
+++ b/frontend/src/assets/css/main.scss
@@ -63,4 +63,7 @@ button.cancel-action {
button.cancel-action:hover {
background-color: #f2f2f2;
color: #45a049;
+}
+.pointer {
+ cursor: pointer;
}
\ No newline at end of file
diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue
index 9c2e4e6..ec3bc3f 100644
--- a/frontend/src/views/DiaryView.vue
+++ b/frontend/src/views/DiaryView.vue
@@ -158,17 +158,6 @@
-
Teilnehmer
-
Aktivitäten
@@ -179,11 +168,36 @@
+ @remove="removeActivityTag" :allow-empty="false" @keydown.enter.prevent="addNewTagFromInput" />
+
Teilnehmer
+
+
+
+
+ ×
+
Tag-Historie {{ tagHistoryMember.firstName }} {{ tagHistoryMember.lastName }}
+ Diese Funktion ist noch nicht implementiert
+
+
+
+
![]()
+
@@ -212,6 +226,7 @@ export default {
activities: [],
notes: [],
newNoteContent: '',
+ noteMember: null,
selectedMember: null,
showNotesModal: false,
selectedActivityTags: [],
@@ -241,6 +256,9 @@ export default {
addNewTimeblock: false,
showGeneralData: false,
editingGroupId: null,
+ doMemberTagUpdates: true,
+ showTagHistoryModal: false,
+ tagHistoryMember: null,
};
},
watch: {
@@ -409,18 +427,25 @@ export default {
description: this.newActivity,
tags: this.selectedActivityTags.map(tag => tag.id)
});
- this.activities.push(response.data);
+ this.activities.push(response.data[0]);
this.newActivity = '';
this.selectedActivityTags = [];
}
},
- async openNotesModal(member) {
+ async selectMember(member) {
this.selectedMember = member;
- await this.loadMemberImage(member);
+ },
+ async openNotesModal(member) {
+ this.noteMember = member;
+ try {
+ await this.loadMemberImage(member);
+ } catch (error) {
+ }
this.loadMemberNotesAndTags(this.date.id, member.id);
this.showNotesModal = true;
},
async loadMemberNotesAndTags(diaryDateId, memberId) {
+ this.doMemberTagUpdates = false;
try {
const notesResponse = await apiClient.get(`/diarymember/${this.currentClub}/note`, {
params: { diaryDateId, memberId }
@@ -431,15 +456,16 @@ export default {
});
this.selectedMemberTags = tagsResponse.data.map(tag => ({
id: tag.tag.id,
- name: tag.tag.name
+ label: tag.tag.label
}));
} catch (error) {
console.error('Error loading member notes and tags:', error);
alert('Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
}
+ this.doMemberTagUpdates = true;
},
async addMemberNote() {
- if (this.newNoteContent) {
+ if (this.newNoteContent && this.selectedMember) {
const response = await apiClient.post(`/diarymember/${this.currentClub}/note`, {
memberId: this.selectedMember.id,
diaryDateId: this.date.id,
@@ -448,6 +474,8 @@ export default {
this.notes = response.data;
this.newNoteContent = '';
this.selectedTagsNotes = [];
+ } else {
+ alert('Bitte wählen Sie einen Teilnehmer aus und geben Sie einen Notiztext ein.');
}
},
async deleteNote(noteId) {
@@ -468,7 +496,7 @@ export default {
async addNewTag(newTagName) {
try {
const response = await apiClient.post('/tags', { name: newTagName });
- const newTag = response.data;
+ const newTag = response.data[0];
this.availableTags.push(newTag);
this.selectedActivityTags.push(newTag);
} catch (error) {
@@ -495,9 +523,13 @@ export default {
}
},
async linkTagToDiaryDate(tag) {
+ if (!tag || !tag.id) {
+ console.warn("Ungültiges Tag-Objekt:", tag);
+ return;
+ }
try {
const tagId = tag.id;
- await apiClient.post(`/diary/tag/${this.currentClub}/add-tag`, {
+ const response = await apiClient.post(`/diary/tag/${this.currentClub}/add-tag`, {
diaryDateId: this.date.id,
tagId: tagId
});
@@ -522,17 +554,14 @@ export default {
async updateActivityTags() {
try {
const selectedTags = this.selectedActivityTags;
-
- if (!selectedTags || !Array.isArray(selectedTags)) {
+ if (!Array.isArray(selectedTags)) {
throw new TypeError('Expected selectedTags to be an array');
}
-
for (let tag of selectedTags) {
- if (!this.previousActivityTags.includes(tag)) {
+ if (tag && tag.id && !this.previousActivityTags.some(prevTag => prevTag.id === tag.id)) {
await this.linkTagToDiaryDate(tag);
}
}
-
this.previousActivityTags = [...selectedTags];
} catch (error) {
console.error('Fehler beim Verknüpfen der Tags mit dem Trainingstag:', error);
@@ -540,6 +569,9 @@ export default {
}
},
async updateMemberTags() {
+ if (!this.doMemberTagUpdates || !this.selectedMember) {
+ return;
+ }
try {
for (let tag of this.selectedMemberTags) {
if (!this.previousMemberTags.includes(tag)) {
@@ -590,12 +622,12 @@ export default {
alert('Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
}
},
- handleActivityInput() {
- if (this.newPlanItem.activity) {
- this.showDropdown = true;
- } else {
- this.showDropdown = false;
+ async handleActivityTagInput(tags) {
+ const newTags = tags.filter(tag => !this.previousActivityTags.some(prevTag => prevTag.id === tag.id));
+ for (const tag of newTags) {
+ await this.linkTagToDiaryDate(tag);
}
+ this.previousActivityTags = [...tags];
},
selectPredefinedActivity(activity) {
this.newPlanItem.activity = activity.name;
@@ -744,7 +776,7 @@ export default {
alert('Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
}
},
- async loadMemberImage(member) {
+/* async loadMemberImage(member) {
try {
const response = await apiClient.get(`/clubmembers/image/${this.currentClub}/${member.id}`, {
responseType: 'blob',
@@ -752,10 +784,9 @@ export default {
const imageUrl = URL.createObjectURL(response.data);
member.imageUrl = imageUrl;
} catch (error) {
- console.error("Failed to load member image:", error);
member.imageUrl = null;
}
- },
+ },*/
async generatePDF() {
const pdf = new PDFGenerator();
pdf.addTrainingPlan(this.currentClubName, this.date.date, this.trainingStart, this.trainingEnd, this.trainingPlan);
@@ -786,7 +817,6 @@ export default {
this.imageUrl = URL.createObjectURL(response.data);
this.showImage = true;
} catch (error) {
- console.error("Failed to load member image:", error);
this.imageUrl = null;
}
},
@@ -838,7 +868,6 @@ export default {
this.showGeneralData = !this.showGeneralData;
},
getFormattedDate(date) {
- console.log(date, typeof date);
return (new Date(date)).toLocaleDateString('de-DE', { year: 'numeric', month: '2-digit', day: '2-digit'});
},
editGroup(groupId) {
@@ -861,6 +890,14 @@ export default {
cancelEditGroup() {
this.editingGroupId = null;
},
+ async openTagInfos(member) {
+ this.showTagHistoryModal = true;
+ this.tagHistoryMember = member;
+ },
+ closeTagHistoryModal() {
+ this.showTagHistoryModal = false;
+ this.tagHistoryMember = null;
+ },
},
async mounted() {
await this.init();
@@ -1025,6 +1062,13 @@ input[type="number"] {
color: #45a049;
}
+.highlighted {
+ background-color: #45a049;
+ color: white;
+ padding: 0.2em;
+ border-radius: 4px;
+}
+
.add-plan-item {
border: 1px solid black;
cursor: pointer;
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
index a912ac9..2e3703e 100644
--- a/frontend/vite.config.js
+++ b/frontend/vite.config.js
@@ -3,6 +3,7 @@ import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
+ mode: 'development',
resolve: {
alias: {
'@': '/src'