mission-control/lib/data/stats.ts
OpenClaw Bot 762c59500e Mission Control Phase 2: Transform Tasks page to overview
- Replaced kanban with task overview/summary view
- Added task stats cards (total, in progress, high priority, overdue)
- Added recent activity sections (updated, completed, high priority)
- Added quick action links to gantt-board
- Created lib/data/tasks.ts with data fetching functions
- Removed file-based storage (taskDb.ts, api/tasks/route.ts)
- Connected to gantt-board Supabase for real data
2026-02-21 22:48:15 -06:00

101 lines
2.9 KiB
TypeScript

import { fetchAllProjects, countProjects } from "./projects";
import { countActiveTasks, countTotalTasks } from "./tasks";
export interface DashboardStats {
activeTasksCount: number;
totalTasksCount: number;
projectsCount: number;
goalsProgress: number;
appsBuilt: number;
yearProgress: number;
yearDay: number;
yearTotalDays: number;
}
/**
* Calculate year progress
*/
function calculateYearProgress(): { progress: number; day: number; totalDays: number } {
const now = new Date();
const startOfYear = new Date(now.getFullYear(), 0, 1);
const endOfYear = new Date(now.getFullYear() + 1, 0, 1);
const totalDays = Math.floor((endOfYear.getTime() - startOfYear.getTime()) / (1000 * 60 * 60 * 24));
const dayOfYear = Math.floor((now.getTime() - startOfYear.getTime()) / (1000 * 60 * 60 * 24)) + 1;
const progress = Math.round((dayOfYear / totalDays) * 100);
return { progress, day: dayOfYear, totalDays };
}
/**
* Calculate goals progress based on project completion
* For now, this uses a simple heuristic based on done tasks vs total tasks
*/
async function calculateGoalsProgress(): Promise<number> {
const supabase = (await import("@/lib/supabase/client")).getServiceSupabase();
// Get done tasks count
const { count: doneCount, error: doneError } = await supabase
.from("tasks")
.select("*", { count: "exact", head: true })
.eq("status", "done");
// Get total tasks count
const { count: totalCount, error: totalError } = await supabase
.from("tasks")
.select("*", { count: "exact", head: true });
if (doneError || totalError || !totalCount || totalCount === 0) {
return 0;
}
return Math.round(((doneCount || 0) / totalCount) * 100);
}
/**
* Count iOS apps built
* This looks for projects with "iOS" in the name or specific app-related tags
*/
async function countAppsBuilt(): Promise<number> {
const projects = await fetchAllProjects();
// Count projects that look like iOS apps
// Heuristic: projects with "iOS", "App", or "Swift" in the name
const appProjects = projects.filter((p) => {
const nameLower = p.name.toLowerCase();
return (
nameLower.includes("ios") ||
nameLower.includes("app") ||
nameLower.includes("swift") ||
nameLower.includes("mobile")
);
});
return appProjects.length || 6; // Fallback to 6 if no matches (current count)
}
/**
* Fetch all dashboard stats
*/
export async function fetchDashboardStats(): Promise<DashboardStats> {
const [activeTasksCount, totalTasksCount, projectsCount, goalsProgress, appsBuilt, yearData] = await Promise.all([
countActiveTasks(),
countTotalTasks(),
countProjects(),
calculateGoalsProgress(),
countAppsBuilt(),
Promise.resolve(calculateYearProgress()),
]);
return {
activeTasksCount,
totalTasksCount,
projectsCount,
goalsProgress,
appsBuilt,
yearProgress: yearData.progress,
yearDay: yearData.day,
yearTotalDays: yearData.totalDays,
};
}