feat(DiaryDateActivity, DiaryView): integrate groupId for enhanced activity management
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 42s
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:
@@ -7,7 +7,7 @@ export const createDiaryDateActivity = async (req, res) => {
|
||||
try {
|
||||
const { authcode: userToken } = req.headers;
|
||||
const { clubId } = req.params;
|
||||
const { diaryDateId, activity, predefinedActivityId, duration, durationText, orderId, isTimeblock } = req.body;
|
||||
const { diaryDateId, activity, predefinedActivityId, duration, durationText, orderId, isTimeblock, groupId } = req.body;
|
||||
const activityItem = await diaryDateActivityService.createActivity(userToken, clubId, {
|
||||
diaryDateId,
|
||||
activity,
|
||||
@@ -16,6 +16,7 @@ export const createDiaryDateActivity = async (req, res) => {
|
||||
durationText,
|
||||
orderId,
|
||||
isTimeblock,
|
||||
groupId,
|
||||
});
|
||||
|
||||
// Emit Socket-Event
|
||||
@@ -152,7 +153,7 @@ export const updateGroupActivity = async(req, res) => {
|
||||
try {
|
||||
const { authcode: userToken } = req.headers;
|
||||
const { clubId, groupActivityId } = req.params;
|
||||
const { predefinedActivityId, duration, durationText, orderId } = req.body;
|
||||
const { predefinedActivityId, duration, durationText, orderId, groupId } = req.body;
|
||||
const activityItem = await diaryDateActivityService.updateGroupActivity(
|
||||
userToken,
|
||||
clubId,
|
||||
@@ -160,7 +161,8 @@ export const updateGroupActivity = async(req, res) => {
|
||||
predefinedActivityId,
|
||||
duration,
|
||||
durationText,
|
||||
orderId
|
||||
orderId,
|
||||
groupId
|
||||
);
|
||||
|
||||
// Emit Socket-Event
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
ALTER TABLE `diary_date_activities`
|
||||
ADD COLUMN `group_id` INT NULL AFTER `predefined_activity_id`,
|
||||
ADD CONSTRAINT `fk_diary_date_activities_group_id`
|
||||
FOREIGN KEY (`group_id`) REFERENCES `group`(`id`)
|
||||
ON DELETE SET NULL
|
||||
ON UPDATE CASCADE;
|
||||
|
||||
INSERT INTO `diary_date_activities` (
|
||||
`diary_date_id`,
|
||||
`is_timeblock`,
|
||||
`predefined_activity_id`,
|
||||
`group_id`,
|
||||
`duration`,
|
||||
`duration_text`,
|
||||
`order_id`,
|
||||
`created_at`,
|
||||
`updated_at`
|
||||
)
|
||||
SELECT
|
||||
d.`diary_date_id`,
|
||||
0 AS `is_timeblock`,
|
||||
ga.`custom_activity` AS `predefined_activity_id`,
|
||||
ga.`group_id`,
|
||||
ga.`duration`,
|
||||
ga.`duration_text`,
|
||||
(d.`order_id` * 100) + COALESCE(ga.`order_id`, 1) AS `order_id`,
|
||||
COALESCE(ga.`created_at`, NOW()) AS `created_at`,
|
||||
COALESCE(ga.`updated_at`, NOW()) AS `updated_at`
|
||||
FROM `group_activity` ga
|
||||
INNER JOIN `diary_date_activities` d ON d.`id` = ga.`diary_date_activity`;
|
||||
@@ -2,6 +2,7 @@ import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
import DiaryDate from './DiaryDates.js';
|
||||
import PredefinedActivity from './PredefinedActivity.js';
|
||||
import Group from './Group.js';
|
||||
|
||||
const DiaryDateActivity = sequelize.define('DiaryDateActivity', {
|
||||
id: {
|
||||
@@ -31,6 +32,15 @@ const DiaryDateActivity = sequelize.define('DiaryDateActivity', {
|
||||
key: 'id',
|
||||
},
|
||||
onDelete: 'SET NULL',
|
||||
},
|
||||
groupId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
references: {
|
||||
model: Group,
|
||||
key: 'id'
|
||||
},
|
||||
onDelete: 'SET NULL'
|
||||
},
|
||||
duration: {
|
||||
type: DataTypes.INTEGER,
|
||||
|
||||
@@ -219,6 +219,9 @@ GroupActivity.belongsTo(Group, { foreignKey: 'groupId', as: 'groupsGroupActivity
|
||||
GroupActivity.belongsTo(PredefinedActivity, { foreignKey: 'customActivity', as: 'groupPredefinedActivity' });
|
||||
PredefinedActivity.hasMany(GroupActivity, { foreignKey: 'predefinedActivityId', as: 'groupPredefinedActivities' });
|
||||
|
||||
DiaryDateActivity.belongsTo(Group, { foreignKey: 'groupId', as: 'planGroup' });
|
||||
Group.hasMany(DiaryDateActivity, { foreignKey: 'groupId', as: 'groupPlanItems' });
|
||||
|
||||
DiaryTag.hasMany(DiaryDateTag, { foreignKey: 'tagId', as: 'diaryDateTags' });
|
||||
DiaryDateTag.belongsTo(DiaryTag, { foreignKey: 'tagId', as: 'tag' });
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
</label>
|
||||
<button type="button" @click="openNewPlanItem()">{{ $t('diary.overallActivity') }}</button>
|
||||
<button type="button" @click="addTimeblock()">{{ $t('diary.addTimeblock') }}</button>
|
||||
<button v-if="parentIsTimeblock()" type="button" @click="addGroupActivity()">{{ $t('diary.addGroupActivity') }}</button>
|
||||
<button v-if="groups && groups.length > 0" type="button" @click="addGroupActivity()">{{ $t('diary.addGroupActivity') }}</button>
|
||||
<button
|
||||
v-if="trainingPlan && trainingPlan.length > 0"
|
||||
type="button"
|
||||
@@ -338,6 +338,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="plan-editor-field">
|
||||
<label>{{ $t('diary.group') }}</label>
|
||||
<select v-model="editingGroupActivityGroupId">
|
||||
<option value="">{{ $t('diary.selectGroup') }}</option>
|
||||
<option v-for="group in groups" :key="group.id" :value="String(group.id)">
|
||||
{{ group.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="plan-editor-field">
|
||||
<label>{{ $t('diary.durationMinutes') }}</label>
|
||||
<div class="plan-composer-duration">
|
||||
<input type="text" v-model="editingGroupActivityDurationText" @input="calculateDurationForEditGroupActivity" :placeholder="$t('diary.durationExampleShort')" />
|
||||
<input type="number" v-model="editingGroupActivityDuration" :placeholder="$t('diary.min')" @keyup.enter="saveGroupActivityEdit(activePlanEditorItem)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="plan-editor-actions">
|
||||
<button
|
||||
@@ -406,7 +422,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ref="sortableList">
|
||||
<template v-for="(item, index) in trainingPlan" :key="item.id">
|
||||
<template v-for="(item, index) in filteredTrainingPlan" :key="item.id">
|
||||
<tr :class="{ 'plan-timeblock-row': item.isTimeblock }" class="plan-sortable-row" :data-plan-id="item.id">
|
||||
<td class="drag-handle" style="cursor: move;">☰</td> <!-- Drag-Handle -->
|
||||
<td>{{ formatDisplayTime(item.startTime) }}</td>
|
||||
@@ -435,13 +451,11 @@
|
||||
<span v-if="item.isTimeblock && getVisibleGroupActivities(item).length" class="plan-row-muted">
|
||||
{{ getVisibleGroupActivities(item).length }} {{ $t('diary.groupsLabel') }}
|
||||
</span>
|
||||
<span v-else>{{ item.groupActivity ? item.groupActivity.name : '' }}</span>
|
||||
<span v-else>{{ item.planGroup ? item.planGroup.name : '' }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="clickable" @click="startActivityEdit(item)">
|
||||
{{ item.duration || '' }}<span
|
||||
v-if="item.durationText && item.durationText.trim() !== ''"> ({{
|
||||
item.durationText }})</span>
|
||||
{{ getPlanDurationDisplay(item) }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
@@ -916,7 +930,6 @@ export default {
|
||||
addtype: 'activity',
|
||||
addNewItem: false,
|
||||
addNewGroupActivity: false,
|
||||
planGroupFilter: '__all__',
|
||||
addNewTimeblock: false,
|
||||
activeOverviewPanel: 'trainingDay',
|
||||
editingGroupId: null,
|
||||
@@ -969,6 +982,9 @@ export default {
|
||||
editingGroupActivity: null, // Gruppenaktivität, die gerade bearbeitet wird
|
||||
editingGroupActivityId: null, // ID der Gruppenaktivität, die inline bearbeitet wird
|
||||
editingGroupActivityText: '', // Text für inline-edit
|
||||
editingGroupActivityDuration: null,
|
||||
editingGroupActivityDurationText: '',
|
||||
editingGroupActivityGroupId: '',
|
||||
// Schnell hinzufügen Dialog
|
||||
showQuickAddDialog: false,
|
||||
newMember: {
|
||||
@@ -983,7 +999,8 @@ export default {
|
||||
activeTab: 'plan', // 'plan', 'members', 'activities'
|
||||
isMobileView: typeof window !== 'undefined' ? window.innerWidth <= 768 : false,
|
||||
participantSearchQuery: '',
|
||||
participantFilter: 'all'
|
||||
participantFilter: 'all',
|
||||
planGroupFilter: '__all__'
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -1030,6 +1047,27 @@ export default {
|
||||
standalonePlanItemCount() {
|
||||
return (this.trainingPlan || []).filter(item => item && !item.isTimeblock).length;
|
||||
},
|
||||
filteredTrainingPlan() {
|
||||
const allItems = Array.isArray(this.trainingPlan) ? this.trainingPlan : [];
|
||||
if (this.planGroupFilter === '__all__') {
|
||||
return allItems;
|
||||
}
|
||||
const selectedGroupId = Number(this.planGroupFilter);
|
||||
if (!Number.isFinite(selectedGroupId)) {
|
||||
return allItems;
|
||||
}
|
||||
return allItems.filter((item) => {
|
||||
if (!item) return false;
|
||||
if (item.isTimeblock) {
|
||||
return this.getVisibleGroupActivities(item).length > 0;
|
||||
}
|
||||
if (!item.groupId) {
|
||||
// Globale Aktivitäten immer sichtbar
|
||||
return true;
|
||||
}
|
||||
return Number(item.groupId) === selectedGroupId;
|
||||
});
|
||||
},
|
||||
activePlanEditorType() {
|
||||
if (this.editingActivityId) return 'activity';
|
||||
if (this.editingGroupActivityId) return 'groupActivity';
|
||||
@@ -2153,15 +2191,45 @@ export default {
|
||||
this.showInfo(this.$t('messages.note'), this.$t('diary.dateNoLongerCurrent'), '', 'warning');
|
||||
return;
|
||||
}
|
||||
await apiClient.post(`/diary-date-activities/${this.currentClub}`, {
|
||||
diaryDateId: this.date.id,
|
||||
activity: this.addNewTimeblock ? '' : this.newPlanItem.activity,
|
||||
predefinedActivityId: this.newPlanItem.predefinedActivityId,
|
||||
isTimeblock: this.addNewTimeblock,
|
||||
duration: this.newPlanItem.duration,
|
||||
durationText: this.newPlanItem.durationText,
|
||||
orderId: this.trainingPlan.length
|
||||
});
|
||||
if (!this.addNewTimeblock && (this.groups || []).length > 0) {
|
||||
const targetGroupIds = this.planGroupFilter !== '__all__'
|
||||
? [Number(this.planGroupFilter)]
|
||||
: this.groups.map((g) => Number(g.id)).filter((id) => Number.isFinite(id));
|
||||
if (targetGroupIds.length > 0) {
|
||||
for (const groupId of targetGroupIds) {
|
||||
await apiClient.post(`/diary-date-activities/${this.currentClub}`, {
|
||||
diaryDateId: this.date.id,
|
||||
activity: this.newPlanItem.activity,
|
||||
predefinedActivityId: this.newPlanItem.predefinedActivityId,
|
||||
isTimeblock: false,
|
||||
duration: this.newPlanItem.duration,
|
||||
durationText: this.newPlanItem.durationText,
|
||||
groupId,
|
||||
orderId: this.trainingPlan.length
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await apiClient.post(`/diary-date-activities/${this.currentClub}`, {
|
||||
diaryDateId: this.date.id,
|
||||
activity: this.newPlanItem.activity,
|
||||
predefinedActivityId: this.newPlanItem.predefinedActivityId,
|
||||
isTimeblock: false,
|
||||
duration: this.newPlanItem.duration,
|
||||
durationText: this.newPlanItem.durationText,
|
||||
orderId: this.trainingPlan.length
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await apiClient.post(`/diary-date-activities/${this.currentClub}`, {
|
||||
diaryDateId: this.date.id,
|
||||
activity: this.addNewTimeblock ? '' : this.newPlanItem.activity,
|
||||
predefinedActivityId: this.newPlanItem.predefinedActivityId,
|
||||
isTimeblock: this.addNewTimeblock,
|
||||
duration: this.newPlanItem.duration,
|
||||
durationText: this.newPlanItem.durationText,
|
||||
orderId: this.trainingPlan.length
|
||||
});
|
||||
}
|
||||
} else if (this.addNewGroupActivity) {
|
||||
if (!this.newPlanItem.groupId || !this.newPlanItem.activity) {
|
||||
this.showInfo(this.$t('messages.note'), this.$t('diary.selectGroupAndActivity'), '', 'warning');
|
||||
@@ -2394,6 +2462,45 @@ export default {
|
||||
this.editingDuration = calculatedDuration;
|
||||
}
|
||||
},
|
||||
calculateDurationForEditGroupActivity() {
|
||||
const input = this.editingGroupActivityDurationText;
|
||||
let calculatedDuration = 0;
|
||||
const multiplyPattern = /(\d+)\s*[x*]\s*(\d+)/i;
|
||||
const match = String(input || '').match(multiplyPattern);
|
||||
if (match) {
|
||||
const [, num1, num2] = match;
|
||||
calculatedDuration = parseInt(num1, 10) * parseInt(num2, 10);
|
||||
} else if (!isNaN(input) && String(input).trim() !== '') {
|
||||
calculatedDuration = parseInt(input, 10);
|
||||
}
|
||||
if (calculatedDuration > 0) {
|
||||
calculatedDuration = Math.ceil(calculatedDuration / 5) * 5;
|
||||
this.editingGroupActivityDuration = calculatedDuration;
|
||||
}
|
||||
},
|
||||
getPlanDurationDisplay(item) {
|
||||
if (!item?.isTimeblock) {
|
||||
if (!item) return '';
|
||||
return `${item.duration || ''}${item.durationText && item.durationText.trim() !== '' ? ` (${item.durationText})` : ''}`;
|
||||
}
|
||||
const maxDuration = this.getTimeblockMaxGroupDuration(item);
|
||||
if (maxDuration > 0) {
|
||||
return `${maxDuration}`;
|
||||
}
|
||||
return `${item.duration || ''}${item.durationText && item.durationText.trim() !== '' ? ` (${item.durationText})` : ''}`;
|
||||
},
|
||||
getTimeblockMaxGroupDuration(timeblockItem) {
|
||||
const entries = Array.isArray(timeblockItem?.groupActivities) ? timeblockItem.groupActivities : [];
|
||||
if (!entries.length) return 0;
|
||||
const totalsByGroup = new Map();
|
||||
for (const entry of entries) {
|
||||
const groupId = Number(entry?.groupsGroupActivity?.id);
|
||||
const duration = Number(entry?.duration || 0);
|
||||
if (!Number.isFinite(groupId) || !Number.isFinite(duration) || duration <= 0) continue;
|
||||
totalsByGroup.set(groupId, (totalsByGroup.get(groupId) || 0) + duration);
|
||||
}
|
||||
return Math.max(0, ...Array.from(totalsByGroup.values()));
|
||||
},
|
||||
async removePlanItem(planItemId) {
|
||||
try {
|
||||
await apiClient.delete(`/diary-date-activities/${this.currentClub}/${planItemId}`);
|
||||
@@ -3202,6 +3309,9 @@ export default {
|
||||
? groupItem.groupPredefinedActivity.code
|
||||
: groupItem.groupPredefinedActivity.name)
|
||||
: '';
|
||||
this.editingGroupActivityDuration = groupItem.duration ?? null;
|
||||
this.editingGroupActivityDurationText = groupItem.durationText || '';
|
||||
this.editingGroupActivityGroupId = groupItem?.groupsGroupActivity?.id ? String(groupItem.groupsGroupActivity.id) : '';
|
||||
},
|
||||
|
||||
async onEditGroupActivityInputChange(groupItem) {
|
||||
@@ -3245,7 +3355,10 @@ export default {
|
||||
|
||||
// Aktualisiere die Gruppenaktivität mit der neuen PredefinedActivity
|
||||
await apiClient.put(`/diary-date-activities/group/${this.currentClub}/${groupItem.id}`, {
|
||||
predefinedActivityId: existing.id
|
||||
predefinedActivityId: existing.id,
|
||||
duration: this.editingGroupActivityDuration || null,
|
||||
durationText: this.editingGroupActivityDurationText || null,
|
||||
groupId: this.editingGroupActivityGroupId ? Number(this.editingGroupActivityGroupId) : null
|
||||
});
|
||||
|
||||
// Lade den Trainingsplan neu
|
||||
@@ -3253,6 +3366,9 @@ export default {
|
||||
|
||||
this.editingGroupActivityId = null;
|
||||
this.editingGroupActivityText = '';
|
||||
this.editingGroupActivityDuration = null;
|
||||
this.editingGroupActivityDurationText = '';
|
||||
this.editingGroupActivityGroupId = '';
|
||||
this.editShowDropdown = false;
|
||||
this.editSearchResults = [];
|
||||
} catch (error) {
|
||||
@@ -3264,6 +3380,9 @@ export default {
|
||||
cancelGroupActivityEdit() {
|
||||
this.editingGroupActivityId = null;
|
||||
this.editingGroupActivityText = '';
|
||||
this.editingGroupActivityDuration = null;
|
||||
this.editingGroupActivityDurationText = '';
|
||||
this.editingGroupActivityGroupId = '';
|
||||
this.editShowDropdown = false;
|
||||
this.editSearchResults = [];
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user