Neah/hooks/use-tasks.ts
2025-05-02 18:19:46 +02:00

140 lines
4.2 KiB
TypeScript

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<Task[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(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;
}