feat: Mission Control dashboard for project management

This commit is contained in:
root
2026-02-16 11:22:06 +00:00
parent 11252e6520
commit 067be4d5a2
11 changed files with 552 additions and 21 deletions
+103
View File
@@ -0,0 +1,103 @@
"use client";
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
import { Task, TaskStatus, initialTasks } from "./types";
interface MissionControlStore {
tasks: Task[];
toggleTask: (id: string) => void;
updateTaskStatus: (id: string, status: TaskStatus) => void;
getProjectProgress: (projectId: string) => number;
getTasksByProject: (projectId: string) => Task[];
}
const MissionControlContext = createContext<MissionControlStore | null>(null);
const STORAGE_KEY = "sitemente:mission-control";
export function MissionControlProvider({ children }: { children: ReactNode }) {
const [tasks, setTasks] = useState<Task[]>(initialTasks);
// Load from localStorage on mount
useEffect(() => {
if (typeof window === "undefined") return;
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
try {
const parsed = JSON.parse(saved);
if (Array.isArray(parsed) && parsed.length > 0) {
setTasks(parsed);
}
} catch {
// Use default
}
}
}, []);
// Save to localStorage on change
useEffect(() => {
if (typeof window === "undefined") return;
localStorage.setItem(STORAGE_KEY, JSON.stringify(tasks));
}, [tasks]);
const toggleTask = (id: string) => {
setTasks((prev) =>
prev.map((t) => {
if (t.id !== id) return t;
const newStatus: TaskStatus = t.status === "done" ? "todo" : "done";
return {
...t,
status: newStatus,
completedAt: newStatus === "done" ? new Date().toISOString().split("T")[0] : undefined,
};
})
);
};
const updateTaskStatus = (id: string, status: TaskStatus) => {
setTasks((prev) =>
prev.map((t) =>
t.id === id
? {
...t,
status,
completedAt: status === "done" ? new Date().toISOString().split("T")[0] : undefined,
}
: t
)
);
};
const getProjectProgress = (projectId: string) => {
const projectTasks = tasks.filter((t) => t.project === projectId);
if (projectTasks.length === 0) return 0;
const done = projectTasks.filter((t) => t.status === "done").length;
return Math.round((done / projectTasks.length) * 100);
};
const getTasksByProject = (projectId: string) => {
return tasks.filter((t) => t.project === projectId).sort((a, b) => a.order - b.order);
};
return (
<MissionControlContext.Provider
value={{
tasks,
toggleTask,
updateTaskStatus,
getProjectProgress,
getTasksByProject,
}}
>
{children}
</MissionControlContext.Provider>
);
}
export function useMissionControl() {
const ctx = useContext(MissionControlContext);
if (!ctx) {
throw new Error("useMissionControl must be used within MissionControlProvider");
}
return ctx;
}