From 940f77e29be5c76011b852a02a51cb32c4150d72 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 8 May 2026 11:28:22 +0200 Subject: [PATCH] feat(DiaryDateActivity): enhance group activity management with duration and order features - Added `duration`, `durationText`, and `orderId` fields to the GroupActivity model to support detailed activity tracking. - Updated `addGroupActivity` and `updateGroupActivity` methods in the DiaryDateActivityService to handle new fields, improving activity management capabilities. - Enhanced the DiaryView component to allow users to input and display duration and duration text for group activities, improving user experience and data clarity. --- .../diaryDateActivityController.js | 26 ++++++++-- ...d_duration_and_order_to_group_activity.sql | 4 ++ backend/models/GroupActivity.js | 13 +++++ backend/services/diaryDateActivityService.js | 48 ++++++++++++++++--- frontend/src/views/DiaryView.vue | 27 ++++++++++- 5 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 backend/migrations/20260508_add_duration_and_order_to_group_activity.sql diff --git a/backend/controllers/diaryDateActivityController.js b/backend/controllers/diaryDateActivityController.js index d34261c0..a8403aa7 100644 --- a/backend/controllers/diaryDateActivityController.js +++ b/backend/controllers/diaryDateActivityController.js @@ -122,8 +122,18 @@ export const getDiaryDateActivities = async (req, res) => { export const addGroupActivity = async(req, res) => { try { const { authcode: userToken } = req.headers; - const { clubId, diaryDateId, groupId, activity, predefinedActivityId, timeblockId } = req.body; - const activityItem = await diaryDateActivityService.addGroupActivity(userToken, clubId, diaryDateId, groupId, activity, predefinedActivityId, timeblockId); + const { clubId, diaryDateId, groupId, activity, predefinedActivityId, timeblockId, duration, durationText } = req.body; + const activityItem = await diaryDateActivityService.addGroupActivity( + userToken, + clubId, + diaryDateId, + groupId, + activity, + predefinedActivityId, + timeblockId, + duration, + durationText + ); // Emit Socket-Event const diaryDate = await DiaryDate.findByPk(diaryDateId); @@ -142,8 +152,16 @@ 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); + const { predefinedActivityId, duration, durationText, orderId } = req.body; + const activityItem = await diaryDateActivityService.updateGroupActivity( + userToken, + clubId, + groupActivityId, + predefinedActivityId, + duration, + durationText, + orderId + ); // Emit Socket-Event const GroupActivity = (await import('../models/GroupActivity.js')).default; diff --git a/backend/migrations/20260508_add_duration_and_order_to_group_activity.sql b/backend/migrations/20260508_add_duration_and_order_to_group_activity.sql new file mode 100644 index 00000000..0c50754b --- /dev/null +++ b/backend/migrations/20260508_add_duration_and_order_to_group_activity.sql @@ -0,0 +1,4 @@ +ALTER TABLE `group_activity` + ADD COLUMN `duration` INT NULL AFTER `custom_activity`, + ADD COLUMN `duration_text` VARCHAR(255) NULL AFTER `duration`, + ADD COLUMN `order_id` INT NOT NULL DEFAULT 1 AFTER `duration_text`; diff --git a/backend/models/GroupActivity.js b/backend/models/GroupActivity.js index a1122036..4e0f5202 100644 --- a/backend/models/GroupActivity.js +++ b/backend/models/GroupActivity.js @@ -31,6 +31,19 @@ const GroupActivity = sequelize.define('GroupActivity', { type: DataTypes.INTEGER, allowNull: true, }, + duration: { + type: DataTypes.INTEGER, + allowNull: true + }, + durationText: { + type: DataTypes.STRING, + allowNull: true + }, + orderId: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: 1 + }, }, { tableName: 'group_activity', underscored: true, diff --git a/backend/services/diaryDateActivityService.js b/backend/services/diaryDateActivityService.js index 3a3b0722..7400b68b 100644 --- a/backend/services/diaryDateActivityService.js +++ b/backend/services/diaryDateActivityService.js @@ -156,8 +156,10 @@ class DiaryDateActivityService { ] }, { - model: GroupActivity, + model: GroupActivity, as: 'groupActivities', + separate: true, + order: [['orderId', 'ASC'], ['id', 'ASC']], include: [ { model: Group, @@ -310,7 +312,7 @@ class DiaryDateActivityService { return activitiesWithImages; } - async addGroupActivity(userToken, clubId, diaryDateId, groupId, activity, predefinedActivityId = null, timeblockId = null) { + async addGroupActivity(userToken, clubId, diaryDateId, groupId, activity, predefinedActivityId = null, timeblockId = null, duration = null, durationText = null) { await checkAccess(userToken, clubId); let diaryDateActivity; @@ -382,16 +384,33 @@ class DiaryDateActivityService { } devLog(predefinedActivity); + const maxOrderId = await GroupActivity.max('orderId', { + where: { + diaryDateActivity: diaryDateActivity.id + } + }); + const nextOrderId = Number.isFinite(maxOrderId) ? (maxOrderId + 1) : 1; + + const parsedDuration = duration === '' || duration === undefined || duration === null + ? null + : parseInt(duration, 10); + const normalizedDurationText = durationText === undefined || durationText === null + ? null + : String(durationText).trim() || null; + const activityData = { diaryDateActivity: diaryDateActivity.id, groupId: groupId, - customActivity: predefinedActivity.id + customActivity: predefinedActivity.id, + duration: Number.isFinite(parsedDuration) ? parsedDuration : null, + durationText: normalizedDurationText, + orderId: nextOrderId } devLog(activityData); return await GroupActivity.create(activityData); } - async updateGroupActivity(userToken, clubId, groupActivityId, predefinedActivityId) { + async updateGroupActivity(userToken, clubId, groupActivityId, predefinedActivityId, duration, durationText, orderId) { await checkAccess(userToken, clubId); const groupActivity = await GroupActivity.findByPk(groupActivityId); if (!groupActivity) { @@ -404,8 +423,25 @@ class DiaryDateActivityService { throw new Error('Predefined activity not found'); } - // Aktualisiere die customActivity (die auf die PredefinedActivity verweist) - groupActivity.customActivity = predefinedActivityId; + if (predefinedActivityId !== undefined && predefinedActivityId !== null) { + // Aktualisiere die customActivity (die auf die PredefinedActivity verweist) + groupActivity.customActivity = predefinedActivityId; + } + if (duration !== undefined) { + const parsedDuration = duration === '' || duration === null + ? null + : parseInt(duration, 10); + groupActivity.duration = Number.isFinite(parsedDuration) ? parsedDuration : null; + } + if (durationText !== undefined) { + groupActivity.durationText = durationText === null ? null : (String(durationText).trim() || null); + } + if (orderId !== undefined) { + const parsedOrderId = parseInt(orderId, 10); + if (Number.isFinite(parsedOrderId) && parsedOrderId > 0) { + groupActivity.orderId = parsedOrderId; + } + } return await groupActivity.save(); } diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index d3faad85..77bb5f7e 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -471,7 +471,23 @@ - + +
+ + +
+ + X @@ -479,7 +495,12 @@