import { useQuery } from '@tanstack/vue-query'; import { computed, Ref, unref, watch } from 'vue'; import axios from '@/plugins/w@custom/axios/models/axios'; import moment from 'moment'; import timelineUtils from '@/plugins/tm@dashboard/tasks/_utils/timeline.utils'; import { detectCollision, calculateTimeblockDuration, getCollisionSegments, type Timeblock, type CollisionInfo, } from './timeblock.utils'; interface Employee { id: number; name: string; surname: string; work_start: number; work_end: number; } export function useEmployeeTimeline( employee: Ref, date: Ref, currentTimeblock: Ref, ) { // Fetch employee's tasks for the selected date const { data: tasksData, isLoading, error, refetch, } = useQuery({ queryKey: computed(() => [ 'employee-timeline', unref(employee)?.id, unref(date) ? moment(unref(date)).format('YYYY-MM-DD') : null, ]), queryFn: async () => { const emp = unref(employee); const d = unref(date); if (!emp?.id || !d) { return null; } const dateStr = moment(d).format('YYYY-MM-DD'); const queryParams = new URLSearchParams({ start: dateStr, end: dateStr, employee_id: emp.id.toString(), }).toString(); const response = await axios.get_auth(`v1/subtasks?${queryParams}`); return response; }, enabled: computed(() => { const emp = unref(employee); const d = unref(date); return !!(emp?.id && d); }), }); // Generate timeline tasks from fetched data const timelineTasks = computed(() => { const data = unref(tasksData); const emp = unref(employee); const d = unref(date); if (!data || !emp || !d) { return []; } const subtasks = [...(data.subtasks || []), ...(data.blockers || [])]; const selectedDateStr = moment(d).format('YYYY-MM-DD'); try { // Process timeblocks directly instead of using timeline utils // which is designed for multi-day views const tasks: any[] = []; subtasks.forEach((subtask) => { if ( ![ 'blocker', 'adhoc', 'home_office', 'vacation', 'free_day', 'office365_blocker', ].includes(subtask.type) ) { subtask.timeblocks?.forEach((timeblock: any) => { const timeblockDateStr = moment(timeblock.start).format( 'YYYY-MM-DD', ); // Only include timeblocks for the selected date if (timeblockDateStr === selectedDateStr) { let type = 'subtask'; if (subtask.type === 'office365') type = 'office365'; tasks.push({ id: subtask.id, start: new Date(timeblock.start), end: new Date(timeblock.end), master_task: subtask.master_task, date: new Date(timeblock.start), project_code: subtask.project_code, subtask: subtask, type, _timeblock_id: timeblock.id, _timeblock_is_finished: timeblock.is_finished, _real_start: new Date(timeblock.start), _real_end: new Date(timeblock.end), }); } }); } }); return tasks; } catch (error) { console.error('Error generating timeline tasks:', error); return []; } }); // Calculate scheduled time for the day (in hours) const scheduledTime = computed(() => { const tasks = unref(timelineTasks); const d = unref(date); if (!tasks || !d) return 0; let totalMinutes = 0; tasks.forEach((task) => { if ( task.type === 'non-working-hours' || task.subtask?.is_finished || task.blocker?.is_finished ) { return; } totalMinutes += timelineUtils._getDifferenceInMinutes( task._real_end, task._real_start, ); }); return (totalMinutes / 60).toFixed(1); }); // Calculate free/unscheduled time for the day (in hours) const freeTime = computed(() => { const emp = unref(employee); const d = unref(date); const scheduled = parseFloat(String(unref(scheduledTime))); if (!emp || !d) return '0'; const dailyCapacityHours = emp.work_end - emp.work_start; return (dailyCapacityHours - scheduled).toFixed(1); }); // Detect collisions with current timeblock const collision = computed(() => { const timeblock = unref(currentTimeblock); const tasks = unref(timelineTasks); if (!timeblock || !tasks) { return { hasCollision: false, startCollides: false, endCollides: false, collidingTasks: [], }; } return detectCollision(timeblock, tasks); }); // Get collision segments for timeline visualization const collisionSegments = computed(() => { const timeblock = unref(currentTimeblock); const tasks = unref(timelineTasks); if (!timeblock || !tasks) { return []; } return getCollisionSegments(timeblock, tasks); }); // Calculate current timeblock duration const timeblockDuration = computed(() => { const timeblock = unref(currentTimeblock); if (!timeblock) return 0; return calculateTimeblockDuration(timeblock); }); watch( scheduledTime, (newVal) => { console.log('scheduledTime', newVal); }, { immediate: true }, ); watch( freeTime, (newVal) => { console.log('freeTime', newVal); }, { immediate: true }, ); return { // Query states isLoading, error, refetch, // Timeline data timelineTasks, scheduledTime, freeTime, // Collision detection collision, collisionSegments, timeblockDuration, }; }