import { useState, useEffect } from "react"; import { isValidDateString } from "@/lib/utils/date-utils"; export interface Task { id: number | string; headline: string; description?: string; dateToFinish?: string | null; dueDate?: string | null; projectId: number; projectName: string; status: number; editorId?: string; editorFirstname?: string; editorLastname?: string; authorFirstname?: string; authorLastname?: string; milestone?: string | null; milestoneHeadline?: string; editTo?: string; editFrom?: string; type?: string; dependingTicketId?: number | null; createdOn?: string; editedOn?: string | null; assignedTo?: number[]; } export interface UseTasksOptions { limit?: number; includeDone?: boolean; sortField?: 'dateToFinish' | 'createdOn' | 'status'; sortDirection?: 'asc' | 'desc'; } export function useTasks({ limit = 10, includeDone = false, sortField = 'dateToFinish', sortDirection = 'asc' }: UseTasksOptions = {}) { const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [refreshTrigger, setRefreshTrigger] = useState(0); const refresh = () => { setRefreshTrigger(prev => prev + 1); }; useEffect(() => { const fetchTasks = async () => { setLoading(true); setError(null); try { const response = await fetch('/api/leantime/tasks'); if (!response.ok) { throw new Error('Failed to fetch tasks'); } const data = await response.json(); if (!Array.isArray(data) && !Array.isArray(data.tasks)) { setTasks([]); return; } // Handle both API response formats const tasksArray = Array.isArray(data) ? data : data.tasks; // Filter and sort tasks const filteredTasks = tasksArray .filter((task: Task) => { // Include done tasks only if specified if (!includeDone && task.status === 5) { return false; } return true; }) .sort((a: Task, b: Task) => { // Sort by date if (sortField === 'dateToFinish') { const dateA = getValidDate(a); const dateB = getValidDate(b); // If both dates are valid, compare them if (dateA && dateB) { const timeA = new Date(dateA).getTime(); const timeB = new Date(dateB).getTime(); if (timeA !== timeB) { return sortDirection === 'asc' ? timeA - timeB : timeB - timeA; } } // If only one date is valid, put the task with a date first if (dateA) return sortDirection === 'asc' ? -1 : 1; if (dateB) return sortDirection === 'asc' ? 1 : -1; } // Sort by created date if (sortField === 'createdOn') { const dateA = a.createdOn ? new Date(a.createdOn).getTime() : 0; const dateB = b.createdOn ? new Date(b.createdOn).getTime() : 0; return sortDirection === 'asc' ? dateA - dateB : dateB - dateA; } // Sort by status if (sortField === 'status') { const statusA = a.status || 0; const statusB = b.status || 0; return sortDirection === 'asc' ? statusA - statusB : statusB - statusA; } return 0; }); setTasks(limit ? filteredTasks.slice(0, limit) : filteredTasks); } catch (error) { setError(error instanceof Error ? error.message : 'Failed to fetch tasks'); } finally { setLoading(false); } }; fetchTasks(); }, [limit, includeDone, sortField, sortDirection, refreshTrigger]); return { tasks, loading, error, refresh }; } // Helper function function getValidDate(task: Task): string | null { if (task.dateToFinish && isValidDateString(task.dateToFinish)) { return task.dateToFinish; } if (task.dueDate && isValidDateString(task.dueDate)) { return task.dueDate; } return null; }