124 lines
3.8 KiB
TypeScript
124 lines
3.8 KiB
TypeScript
import { fetchGanttSnapshot } from "@/lib/data/gantt-snapshot";
|
|
|
|
export interface Task {
|
|
id: string;
|
|
title: string;
|
|
description?: string;
|
|
type: "idea" | "task" | "bug" | "research" | "plan";
|
|
status: "open" | "todo" | "blocked" | "in-progress" | "review" | "validate" | "archived" | "canceled" | "done";
|
|
priority: "low" | "medium" | "high" | "urgent";
|
|
projectId: string;
|
|
sprintId?: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
createdById?: string;
|
|
createdByName?: string;
|
|
createdByAvatarUrl?: string;
|
|
updatedById?: string;
|
|
updatedByName?: string;
|
|
updatedByAvatarUrl?: string;
|
|
assigneeId?: string;
|
|
assigneeName?: string;
|
|
assigneeEmail?: string;
|
|
assigneeAvatarUrl?: string;
|
|
dueDate?: string;
|
|
comments: unknown[];
|
|
tags: string[];
|
|
attachments: unknown[];
|
|
}
|
|
|
|
export interface TaskStatusCounts {
|
|
open: number;
|
|
inProgress: number;
|
|
review: number;
|
|
done: number;
|
|
total: number;
|
|
}
|
|
|
|
function isDoneStatus(status: Task["status"]): boolean {
|
|
return status === "done";
|
|
}
|
|
|
|
function isOpenStatus(status: Task["status"]): boolean {
|
|
return status === "open" || status === "todo" || status === "blocked";
|
|
}
|
|
|
|
function isReviewStatus(status: Task["status"]): boolean {
|
|
return status === "review" || status === "validate";
|
|
}
|
|
|
|
function byUpdatedDesc(a: Task, b: Task): number {
|
|
return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
|
|
}
|
|
|
|
function toDateOnly(value: string): string {
|
|
return value.split("T")[0];
|
|
}
|
|
|
|
async function fetchTasksFromApi(): Promise<Task[]> {
|
|
const snapshot = await fetchGanttSnapshot();
|
|
return snapshot.tasks;
|
|
}
|
|
|
|
export async function fetchAllTasks(): Promise<Task[]> {
|
|
return fetchTasksFromApi();
|
|
}
|
|
|
|
export async function fetchActiveTasks(): Promise<Task[]> {
|
|
const tasks = await fetchTasksFromApi();
|
|
return tasks.filter((task) => !isDoneStatus(task.status));
|
|
}
|
|
|
|
export async function countActiveTasks(): Promise<number> {
|
|
const tasks = await fetchTasksFromApi();
|
|
return tasks.filter((task) => !isDoneStatus(task.status)).length;
|
|
}
|
|
|
|
export async function countTotalTasks(): Promise<number> {
|
|
const tasks = await fetchTasksFromApi();
|
|
return tasks.length;
|
|
}
|
|
|
|
export async function getTaskStatusCounts(): Promise<TaskStatusCounts> {
|
|
const tasks = await fetchTasksFromApi();
|
|
const counts: TaskStatusCounts = { open: 0, inProgress: 0, review: 0, done: 0, total: tasks.length };
|
|
|
|
for (const task of tasks) {
|
|
if (isOpenStatus(task.status)) counts.open++;
|
|
else if (task.status === "in-progress") counts.inProgress++;
|
|
else if (isReviewStatus(task.status)) counts.review++;
|
|
else if (task.status === "done") counts.done++;
|
|
}
|
|
|
|
return counts;
|
|
}
|
|
|
|
export async function countHighPriorityTasks(): Promise<number> {
|
|
const tasks = await fetchTasksFromApi();
|
|
return tasks.filter((task) => (task.priority === "high" || task.priority === "urgent") && !isDoneStatus(task.status)).length;
|
|
}
|
|
|
|
export async function countOverdueTasks(): Promise<number> {
|
|
const tasks = await fetchTasksFromApi();
|
|
const today = toDateOnly(new Date().toISOString());
|
|
return tasks.filter((task) => Boolean(task.dueDate) && !isDoneStatus(task.status) && toDateOnly(task.dueDate as string) < today).length;
|
|
}
|
|
|
|
export async function fetchRecentlyUpdatedTasks(limit = 5): Promise<Task[]> {
|
|
const tasks = await fetchTasksFromApi();
|
|
return [...tasks].sort(byUpdatedDesc).slice(0, limit);
|
|
}
|
|
|
|
export async function fetchRecentlyCompletedTasks(limit = 5): Promise<Task[]> {
|
|
const tasks = await fetchTasksFromApi();
|
|
return tasks.filter((task) => isDoneStatus(task.status)).sort(byUpdatedDesc).slice(0, limit);
|
|
}
|
|
|
|
export async function fetchHighPriorityOpenTasks(limit = 5): Promise<Task[]> {
|
|
const tasks = await fetchTasksFromApi();
|
|
return tasks
|
|
.filter((task) => (task.priority === "high" || task.priority === "urgent") && !isDoneStatus(task.status))
|
|
.sort(byUpdatedDesc)
|
|
.slice(0, limit);
|
|
}
|