fix(task-edit): fixed free time calculation

This commit is contained in:
Matej Glasnák committed 2026-02-03 04:18:40 +01:00
1 parent 68e7c0d785
commit c9772400bd
2 files changed
+37 -9

No files matched your search

@@ -26,6 +26,7 @@ export function useEmployeeTimeline(
otherLocalTimeblocks?: Ref<Timeblock[]>, otherLocalTimeblocks?: Ref<Timeblock[]>,
editingBlockerId?: Ref<number | null>, editingBlockerId?: Ref<number | null>,
draftTimeblocks?: Ref<Timeblock[]>, draftTimeblocks?: Ref<Timeblock[]>,
allEditingTimeblockIds?: Ref<number[]>,
) { ) {
// Fetch employee's tasks for the selected date // Fetch employee's tasks for the selected date
const { const {
@@ -267,6 +268,11 @@ export function useEmployeeTimeline(
if (!tasks || !d) return 0; if (!tasks || !d) return 0;
// Get IDs of timeblocks being edited locally to exclude them from scheduled time
const editingTimeblockIds = allEditingTimeblockIds
? new Set(unref(allEditingTimeblockIds).filter((id) => id != null))
: new Set();
let totalMinutes = 0; let totalMinutes = 0;
tasks.forEach((task) => { tasks.forEach((task) => {
@@ -278,6 +284,11 @@ export function useEmployeeTimeline(
return; return;
} }
// Skip timeblocks that are being edited locally to avoid double-counting
if (task._timeblock_id && editingTimeblockIds.has(task._timeblock_id)) {
return;
}
totalMinutes += timelineUtils._getDifferenceInMinutes( totalMinutes += timelineUtils._getDifferenceInMinutes(
task._real_end, task._real_end,
task._real_start, task._real_start,
@@ -287,14 +298,10 @@ export function useEmployeeTimeline(
return (totalMinutes / 60).toFixed(1); return (totalMinutes / 60).toFixed(1);
}); });
// Calculate free/unscheduled time for the day (in hours) // Calculate total planned time including local edits (for display purposes)
const freeTime = computed(() => { const totalPlannedTime = computed(() => {
const emp = unref(employee);
const d = unref(date);
const scheduled = parseFloat(String(unref(scheduledTime))); const scheduled = parseFloat(String(unref(scheduledTime)));
if (!emp || !d) return '0';
// Calculate duration of other local unsaved timeblocks for the same date // Calculate duration of other local unsaved timeblocks for the same date
let localTimeblocksHours = 0; let localTimeblocksHours = 0;
if (otherLocalTimeblocks) { if (otherLocalTimeblocks) {
@@ -313,9 +320,20 @@ export function useEmployeeTimeline(
localTimeblocksHours += calculateTimeblockDuration(currentTb); localTimeblocksHours += calculateTimeblockDuration(currentTb);
} }
return (scheduled + localTimeblocksHours).toFixed(1);
});
// Calculate free/unscheduled time for the day (in hours)
const freeTime = computed(() => {
const emp = unref(employee);
const d = unref(date);
const totalPlanned = parseFloat(String(unref(totalPlannedTime)));
if (!emp || !d) return '0';
const dailyCapacityHours = emp.work_end - emp.work_start; const dailyCapacityHours = emp.work_end - emp.work_start;
return (dailyCapacityHours - scheduled - localTimeblocksHours).toFixed(1); return (dailyCapacityHours - totalPlanned).toFixed(1);
}); });
// Detect collisions with current timeblock // Detect collisions with current timeblock
@@ -367,6 +385,7 @@ export function useEmployeeTimeline(
// Timeline data // Timeline data
timelineTasks, timelineTasks,
scheduledTime, scheduledTime,
totalPlannedTime,
freeTime, freeTime,
// Collision detection // Collision detection
@@ -14,7 +14,7 @@
:has-start-time-error="hasStartTimeError" :has-start-time-error="hasStartTimeError"
:has-end-time-error="hasEndTimeError" :has-end-time-error="hasEndTimeError"
:end-time-error-message="endTimeErrorMessage" :end-time-error-message="endTimeErrorMessage"
:planned-time="_scheduledTime" :planned-time="_totalPlannedTime"
:free-time="_freeTime" :free-time="_freeTime"
:employee="employee" :employee="employee"
:index="index" :index="index"
@@ -238,6 +238,13 @@ const otherTimeblocksForSameDate = computed(() => {
}); });
}); });
// Get all timeblock IDs being edited locally for this employee (to exclude from server scheduled time)
const allEditingTimeblockIds = computed(() => {
return props.allEmployeeTimeblocks
.filter((tb) => tb.id != null)
.map((tb) => tb.id) as number[];
});
// Use timeline composable // Use timeline composable
const editingBlockerIdRef = computed(() => props.editingBlockerId); const editingBlockerIdRef = computed(() => props.editingBlockerId);
const draftTimeblocksRef = computed(() => props.draftTimeblocks); const draftTimeblocksRef = computed(() => props.draftTimeblocks);
@@ -246,6 +253,7 @@ const {
isLoading, isLoading,
timelineTasks, timelineTasks,
scheduledTime: _scheduledTime, scheduledTime: _scheduledTime,
totalPlannedTime: _totalPlannedTime,
freeTime: _freeTime, freeTime: _freeTime,
timeblockDuration, timeblockDuration,
refetch, refetch,
@@ -256,6 +264,7 @@ const {
otherTimeblocksForSameDate, otherTimeblocksForSameDate,
editingBlockerIdRef, editingBlockerIdRef,
draftTimeblocksRef, draftTimeblocksRef,
allEditingTimeblockIds,
); );
// Force refetch when date changes // Force refetch when date changes