"Updated backend and frontend code: added console logs, modified DiaryMemberController, DiaryTagController, DiaryService, and DiaryView, and made changes to CSS and vite.config.js"
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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']] });
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -63,4 +63,7 @@ button.cancel-action {
|
||||
button.cancel-action:hover {
|
||||
background-color: #f2f2f2;
|
||||
color: #45a049;
|
||||
}
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -158,17 +158,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3>Teilnehmer</h3>
|
||||
<ul>
|
||||
<li v-for="member in sortedMembers()" :key="member.id">
|
||||
<input type="checkbox" :value="member.id" @change="toggleParticipant(member.id)"
|
||||
:checked="isParticipant(member.id)">
|
||||
<span @click="openNotesModal(member)" class="clickable">{{ member.firstName }} {{
|
||||
member.lastName }}</span>
|
||||
<span @click="showPic(member)" class="img-icon" v-if="member.hasImage">🖼</span>
|
||||
<span>ℹ</span>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Aktivitäten</h3>
|
||||
<textarea v-model="newActivity"></textarea>
|
||||
<button @click="addActivity">Aktivität hinzufügen</button>
|
||||
@@ -179,11 +168,36 @@
|
||||
</ul>
|
||||
<multiselect v-model="selectedActivityTags" :options="availableTags" placeholder="Tags auswählen"
|
||||
label="name" track-by="id" multiple :close-on-select="true" @tag="addNewTag"
|
||||
@remove="removeActivityTag" @input="updateActivityTags" :allow-empty="false"
|
||||
@keydown.enter.prevent="addNewTagFromInput" />
|
||||
@remove="removeActivityTag" :allow-empty="false" @keydown.enter.prevent="addNewTagFromInput" />
|
||||
<h3>Teilnehmer</h3>
|
||||
<ul>
|
||||
<li v-for="member in sortedMembers()" :key="member.id">
|
||||
<input type="checkbox" :value="member.id" @change="toggleParticipant(member.id)"
|
||||
:checked="isParticipant(member.id)">
|
||||
<span class="clickable" @click="selectMember(member)"
|
||||
:class="{ highlighted: selectedMember && selectedMember.id === member.id }">{{
|
||||
member.firstName
|
||||
}} {{
|
||||
member.lastName }}</span>
|
||||
<span @click="openNotesModal(member)" class="clickable">📝</span>
|
||||
<span @click="showPic(member)" class="img-icon" v-if="member.hasImage">🖼</span>
|
||||
<span class="pointer" @click="openTagInfos(member)">ℹ️</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="showTagHistoryModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" @click="closeTagHistoryModal">×</span>
|
||||
<h3>Tag-Historie {{ tagHistoryMember.firstName }} {{ tagHistoryMember.lastName }}</h3>
|
||||
Diese Funktion ist noch nicht implementiert
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showImage" class="memberImage">
|
||||
<img :src="imageUrl" @click="closeImage" />
|
||||
</div>
|
||||
</div>
|
||||
<img v-if="showImage" class="img" :src="imageUrl" @click="closeImage()" />
|
||||
</template>
|
||||
@@ -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;
|
||||
|
||||
@@ -3,6 +3,7 @@ import vue from '@vitejs/plugin-vue';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
mode: 'development',
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': '/src'
|
||||
|
||||
Reference in New Issue
Block a user