feat(DiaryDateActivity, DiaryView): integrate groupId for enhanced activity management
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 42s

- Added `groupId` field to the DiaryDateActivity model to support group-specific activities.
- Updated create and update methods in DiaryDateActivityService to handle groupId, ensuring proper validation and association with groups.
- Enhanced DiaryView component to allow selection of groups for activities, improving user experience and activity organization.
- Implemented filtering logic in DiaryView to display activities based on selected group, enhancing data clarity and usability.
This commit is contained in:
Torsten Schulz (local)
2026-05-08 11:58:57 +02:00
parent 93796cecd6
commit 912bf88c3f
6 changed files with 287 additions and 64 deletions

View File

@@ -12,6 +12,9 @@ class DiaryDateActivityService {
async createActivity(userToken, clubId, data) {
await checkAccess(userToken, clubId);
const { activity, ...restData } = data;
const normalizedGroupId = data.groupId === '' || data.groupId === undefined || data.groupId === null
? null
: parseInt(data.groupId, 10);
// Versuche, die PredefinedActivity robust zu finden:
// 1) per übergebener ID
// 2) per Name ODER Code (das Feld "activity" kann Kürzel oder Name sein)
@@ -52,9 +55,20 @@ class DiaryDateActivityService {
} else if (typeof restData.duration === 'string') {
restData.duration = parseInt(restData.duration);
}
restData.groupId = Number.isFinite(normalizedGroupId) ? normalizedGroupId : null;
if (restData.groupId) {
const group = await Group.findByPk(restData.groupId);
if (!group || Number(group.diaryDateId) !== Number(data.diaryDateId)) {
throw new Error('Group isn\'t related to date');
}
}
const maxOrderId = await DiaryDateActivity.max('orderId', {
where: { diaryDateId: data.diaryDateId }
where: {
diaryDateId: data.diaryDateId,
groupId: restData.groupId
}
});
const newOrderId = maxOrderId !== null ? maxOrderId + 1 : 1;
restData.orderId = newOrderId;
@@ -92,6 +106,19 @@ class DiaryDateActivityService {
delete data.customActivityName;
}
if (data.groupId !== undefined) {
const normalizedGroupId = data.groupId === '' || data.groupId === null
? null
: parseInt(data.groupId, 10);
data.groupId = Number.isFinite(normalizedGroupId) ? normalizedGroupId : null;
if (data.groupId) {
const group = await Group.findByPk(data.groupId);
if (!group || Number(group.diaryDateId) !== Number(activity.diaryDateId)) {
throw new Error('Group isn\'t related to date');
}
}
}
return await activity.update(data);
}
@@ -112,12 +139,14 @@ class DiaryDateActivityService {
throw new Error('Activity not found');
}
const currentOrderId = activity.orderId;
const scopeGroupId = activity.groupId || null;
if (newOrderId < currentOrderId) {
await DiaryDateActivity.increment(
{ orderId: 1 },
{
where: {
diaryDateId: activity.diaryDateId,
groupId: scopeGroupId,
orderId: { [Op.gte]: newOrderId, [Op.lt]: currentOrderId },
},
}
@@ -128,6 +157,7 @@ class DiaryDateActivityService {
{
where: {
diaryDateId: activity.diaryDateId,
groupId: scopeGroupId,
orderId: { [Op.lte]: newOrderId, [Op.gt]: currentOrderId },
},
}
@@ -155,6 +185,10 @@ class DiaryDateActivityService {
}
]
},
{
model: Group,
as: 'planGroup'
},
{
model: GroupActivity,
as: 'groupActivities',
@@ -314,42 +348,15 @@ class DiaryDateActivityService {
async addGroupActivity(userToken, clubId, diaryDateId, groupId, activity, predefinedActivityId = null, timeblockId = null, duration = null, durationText = null) {
await checkAccess(userToken, clubId);
let diaryDateActivity;
if (timeblockId) {
// Verwende die spezifische Zeitblock-ID, falls angegeben
diaryDateActivity = await DiaryDateActivity.findOne({
where: {
id: timeblockId,
diaryDateId,
isTimeblock: true,
}
});
} else {
// Fallback: Verwende den letzten Zeitblock
diaryDateActivity = await DiaryDateActivity.findOne({
where: {
diaryDateId,
isTimeblock: true,
},
order: [['order_id', 'DESC']],
limit: 1
});
}
if (!diaryDateActivity) {
console.error('[DiaryDateActivityService::addGroupActivity] Activity not found');
throw new Error('Activity not found');
}
const group = await Group.findByPk(groupId);
if (!group) {
console.error('[DiaryDateActivityService::addGroupActivity] Group not found:', groupId);
throw new Error('Group not found');
}
if (group.diaryDateId !== diaryDateActivity.diaryDateId) {
if (Number(group.diaryDateId) !== Number(diaryDateId)) {
console.error('[DiaryDateActivityService::addGroupActivity] Group and date don\'t fit');
console.error('Group diaryDateId:', group.diaryDateId, 'Activity diaryDateId:', diaryDateActivity.diaryDateId);
console.error('Group diaryDateId:', group.diaryDateId, 'Activity diaryDateId:', diaryDateId);
throw new Error('Group isn\'t related to date');
}
@@ -384,9 +391,9 @@ class DiaryDateActivityService {
}
devLog(predefinedActivity);
const maxOrderId = await GroupActivity.max('orderId', {
const maxOrderId = await DiaryDateActivity.max('orderId', {
where: {
diaryDateActivity: diaryDateActivity.id,
diaryDateId,
groupId: Number(groupId)
}
});
@@ -400,34 +407,80 @@ class DiaryDateActivityService {
: String(durationText).trim() || null;
const activityData = {
diaryDateActivity: diaryDateActivity.id,
diaryDateId,
isTimeblock: false,
predefinedActivityId: predefinedActivity.id,
groupId: groupId,
customActivity: predefinedActivity.id,
duration: Number.isFinite(parsedDuration) ? parsedDuration : null,
durationText: normalizedDurationText,
orderId: nextOrderId
}
devLog(activityData);
return await GroupActivity.create(activityData);
return await DiaryDateActivity.create(activityData);
}
async updateGroupActivity(userToken, clubId, groupActivityId, predefinedActivityId, duration, durationText, orderId) {
async updateGroupActivity(userToken, clubId, groupActivityId, predefinedActivityId, duration, durationText, orderId, groupId) {
await checkAccess(userToken, clubId);
const planActivity = await DiaryDateActivity.findOne({
where: { id: groupActivityId, groupId: { [Op.not]: null } }
});
if (planActivity) {
const payload = {};
if (predefinedActivityId !== undefined && predefinedActivityId !== null) {
const predefinedActivity = await PredefinedActivity.findByPk(predefinedActivityId);
if (!predefinedActivity) {
throw new Error('Predefined activity not found');
}
payload.predefinedActivityId = predefinedActivityId;
}
if (groupId !== undefined && groupId !== null) {
const parsedGroupId = parseInt(groupId, 10);
if (Number.isFinite(parsedGroupId) && parsedGroupId > 0) {
const group = await Group.findByPk(parsedGroupId);
if (!group || Number(group.diaryDateId) !== Number(planActivity.diaryDateId)) {
throw new Error('Group isn\'t related to date');
}
payload.groupId = parsedGroupId;
}
}
if (duration !== undefined) {
const parsedDuration = duration === '' || duration === null
? null
: parseInt(duration, 10);
payload.duration = Number.isFinite(parsedDuration) ? parsedDuration : null;
}
if (durationText !== undefined) {
payload.durationText = durationText === null ? null : (String(durationText).trim() || null);
}
if (orderId !== undefined) {
const parsedOrderId = parseInt(orderId, 10);
if (Number.isFinite(parsedOrderId) && parsedOrderId > 0) {
payload.orderId = parsedOrderId;
}
}
return await planActivity.update(payload);
}
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');
}
if (predefinedActivityId !== undefined && predefinedActivityId !== null) {
// 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;
}
if (groupId !== undefined && groupId !== null) {
const parsedGroupId = parseInt(groupId, 10);
if (Number.isFinite(parsedGroupId) && parsedGroupId > 0) {
groupActivity.groupId = parsedGroupId;
}
}
if (duration !== undefined) {
const parsedDuration = duration === '' || duration === null
? null
@@ -448,6 +501,12 @@ class DiaryDateActivityService {
async deleteGroupActivity(userToken, clubId, groupActivityId) {
await checkAccess(userToken, clubId);
const planActivity = await DiaryDateActivity.findOne({
where: { id: groupActivityId, groupId: { [Op.not]: null } }
});
if (planActivity) {
return await planActivity.destroy();
}
const groupActivity = await GroupActivity.findByPk(groupActivityId);
if (!groupActivity) {
throw new Error('Group activity not found');