feat: Optimize activity ordering and enhance plan item movement functionality
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 45s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 45s
This commit is contained in:
@@ -64,17 +64,8 @@ class DiaryDateActivityService {
|
||||
}
|
||||
}
|
||||
|
||||
const maxOrderWhere = restData.groupId
|
||||
? {
|
||||
diaryDateId: data.diaryDateId,
|
||||
groupId: restData.groupId
|
||||
}
|
||||
: {
|
||||
// Globale Aktivitäten bei "Alle" sollen am Ende des gesamten Tagesplans landen.
|
||||
diaryDateId: data.diaryDateId
|
||||
};
|
||||
const maxOrderId = await DiaryDateActivity.max('orderId', {
|
||||
where: maxOrderWhere
|
||||
where: { diaryDateId: data.diaryDateId }
|
||||
});
|
||||
const newOrderId = maxOrderId !== null ? maxOrderId + 1 : 1;
|
||||
restData.orderId = newOrderId;
|
||||
@@ -125,6 +116,12 @@ class DiaryDateActivityService {
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(data)) {
|
||||
if (data[key] === undefined) {
|
||||
delete data[key];
|
||||
}
|
||||
}
|
||||
|
||||
return await activity.update(data);
|
||||
}
|
||||
|
||||
@@ -145,14 +142,12 @@ 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 },
|
||||
},
|
||||
}
|
||||
@@ -163,7 +158,6 @@ class DiaryDateActivityService {
|
||||
{
|
||||
where: {
|
||||
diaryDateId: activity.diaryDateId,
|
||||
groupId: scopeGroupId,
|
||||
orderId: { [Op.lte]: newOrderId, [Op.gt]: currentOrderId },
|
||||
},
|
||||
}
|
||||
@@ -308,10 +302,7 @@ class DiaryDateActivityService {
|
||||
|
||||
devLog(predefinedActivity);
|
||||
const maxOrderId = await DiaryDateActivity.max('orderId', {
|
||||
where: {
|
||||
diaryDateId,
|
||||
groupId: Number(groupId)
|
||||
}
|
||||
where: { diaryDateId }
|
||||
});
|
||||
const nextOrderId = Number.isFinite(maxOrderId) ? (maxOrderId + 1) : 1;
|
||||
|
||||
|
||||
@@ -442,6 +442,18 @@
|
||||
</div>
|
||||
<div class="plan-row-actions">
|
||||
<button @click="startActivityEdit(item)" class="plan-row-action-button">{{ $t('common.edit') }}</button>
|
||||
<button
|
||||
@click="movePlanItem(item, 'up')"
|
||||
class="plan-row-action-button"
|
||||
:disabled="!canMovePlanItem(item, 'up')"
|
||||
title="Nach oben"
|
||||
>↑</button>
|
||||
<button
|
||||
@click="movePlanItem(item, 'down')"
|
||||
class="plan-row-action-button"
|
||||
:disabled="!canMovePlanItem(item, 'down')"
|
||||
title="Nach unten"
|
||||
>↓</button>
|
||||
<button v-if="!isStructuralPlanItem(item)" @click="toggleActivityMembers(item)" class="plan-row-action-button">{{ $t('diary.assignShort') }}</button>
|
||||
<button @click="removePlanItem(item.id)" class="plan-row-action-button plan-row-action-button-danger">{{ $t('common.delete') }}</button>
|
||||
</div>
|
||||
@@ -460,6 +472,18 @@
|
||||
</div>
|
||||
<div class="plan-row-actions">
|
||||
<button @click="startActivityEdit(item)" class="plan-row-action-button">{{ $t('common.edit') }}</button>
|
||||
<button
|
||||
@click="movePlanItem(item, 'up')"
|
||||
class="plan-row-action-button"
|
||||
:disabled="!canMovePlanItem(item, 'up')"
|
||||
title="Nach oben"
|
||||
>↑</button>
|
||||
<button
|
||||
@click="movePlanItem(item, 'down')"
|
||||
class="plan-row-action-button"
|
||||
:disabled="!canMovePlanItem(item, 'down')"
|
||||
title="Nach unten"
|
||||
>↓</button>
|
||||
<button v-if="!isStructuralPlanItem(item)" @click="toggleActivityMembers(item)" class="plan-row-action-button">{{ $t('diary.assignShort') }}</button>
|
||||
<button @click="removePlanItem(item.id)" class="plan-row-action-button plan-row-action-button-danger">{{ $t('common.delete') }}</button>
|
||||
</div>
|
||||
@@ -2762,16 +2786,68 @@ export default {
|
||||
this.showInfo(this.$t('messages.error'), this.$t('diary.errorOccurred'), '', 'error');
|
||||
}
|
||||
},
|
||||
getOrderedPlanItems() {
|
||||
return (Array.isArray(this.trainingPlan) ? this.trainingPlan : [])
|
||||
.filter(item => item && !item.isTimeblock)
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
const orderA = Number.isFinite(Number(a?.orderId)) ? Number(a.orderId) : Number.MAX_SAFE_INTEGER;
|
||||
const orderB = Number.isFinite(Number(b?.orderId)) ? Number(b.orderId) : Number.MAX_SAFE_INTEGER;
|
||||
if (orderA !== orderB) return orderA - orderB;
|
||||
return Number(a?.id || 0) - Number(b?.id || 0);
|
||||
});
|
||||
},
|
||||
canMovePlanItem(item, direction) {
|
||||
const orderedItems = this.getOrderedPlanItems();
|
||||
const index = orderedItems.findIndex(entry => Number(entry?.id) === Number(item?.id));
|
||||
if (index < 0) return false;
|
||||
if (direction === 'up') return index > 0;
|
||||
if (direction === 'down') return index < orderedItems.length - 1;
|
||||
return false;
|
||||
},
|
||||
async movePlanItem(item, direction) {
|
||||
if (!this.canMovePlanItem(item, direction)) {
|
||||
return;
|
||||
}
|
||||
const orderedItems = this.getOrderedPlanItems();
|
||||
const index = orderedItems.findIndex(entry => Number(entry?.id) === Number(item?.id));
|
||||
const targetIndex = direction === 'up' ? index - 1 : index + 1;
|
||||
const targetItem = orderedItems[targetIndex];
|
||||
if (!targetItem) return;
|
||||
|
||||
const currentOrder = Number.isFinite(Number(item.orderId)) ? Number(item.orderId) : index + 1;
|
||||
const targetOrder = Number.isFinite(Number(targetItem.orderId)) ? Number(targetItem.orderId) : targetIndex + 1;
|
||||
|
||||
try {
|
||||
await apiClient.put(`/diary-date-activities/${this.currentClub}/${item.id}`, {
|
||||
orderId: targetOrder
|
||||
});
|
||||
await apiClient.put(`/diary-date-activities/${this.currentClub}/${targetItem.id}`, {
|
||||
orderId: currentOrder
|
||||
});
|
||||
await this.loadTrainingPlan();
|
||||
} catch (error) {
|
||||
this.showInfo(this.$t('messages.error'), this.$t('diary.errorOccurred'), '', 'error');
|
||||
}
|
||||
},
|
||||
async onDragEnd(evt) {
|
||||
const oldIndex = Number.isInteger(evt.oldDraggableIndex) ? evt.oldDraggableIndex : evt.oldIndex;
|
||||
const newIndex = Number.isInteger(evt.newDraggableIndex) ? evt.newDraggableIndex : evt.newIndex;
|
||||
const movedItem = this.trainingPlan[oldIndex];
|
||||
const visibleItems = this.filteredTrainingPlan.slice();
|
||||
const movedId = evt?.item?.dataset?.planId;
|
||||
const movedItem = movedId
|
||||
? this.trainingPlan.find(item => Number(item.id) === Number(movedId))
|
||||
: visibleItems[oldIndex];
|
||||
if (!movedItem) {
|
||||
return;
|
||||
}
|
||||
const targetItem = visibleItems[newIndex];
|
||||
const targetOrder = targetItem && Number(targetItem.id) !== Number(movedItem.id)
|
||||
? Number(targetItem.orderId)
|
||||
: newIndex + 1;
|
||||
try {
|
||||
await apiClient.put(`/diary-date-activities/${this.currentClub}/${movedItem.id}/order`, {
|
||||
orderId: newIndex + 1
|
||||
orderId: targetOrder
|
||||
});
|
||||
await this.loadTrainingPlan();
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user