import { useState, useEffect } from "react"; import Layout from "@/components/Layout"; import SEO from "@/components/SEO"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; import { Target, TrendingUp, CheckCircle, Loader2, Plus, Calendar, } from "lucide-react"; import { useAuth } from "@/contexts/AuthContext"; import { aethexToast } from "@/lib/aethex-toast"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; interface Task { id: string; title: string; description?: string; status: string; priority: string; due_date?: string; completed_at?: string; } interface Project { id: string; name: string; description: string; status: string; start_date: string; end_date?: string; lead?: { full_name: string; avatar_url?: string; }; tasks: Task[]; task_stats: { total: number; done: number; }; } interface Stats { total: number; active: number; completed: number; } const getStatusColor = (status: string) => { switch (status) { case "active": return "bg-green-500/20 text-green-300 border-green-500/30"; case "completed": return "bg-blue-500/20 text-blue-300 border-blue-500/30"; case "on_hold": return "bg-amber-500/20 text-amber-300 border-amber-500/30"; default: return "bg-slate-500/20 text-slate-300 border-slate-500/30"; } }; const getTaskStatusColor = (status: string) => { switch (status) { case "done": return "bg-green-500/20 text-green-300"; case "in_progress": return "bg-blue-500/20 text-blue-300"; case "todo": return "bg-slate-500/20 text-slate-300"; default: return "bg-slate-500/20 text-slate-300"; } }; export default function StaffProjectTracking() { const { session } = useAuth(); const [projects, setProjects] = useState([]); const [stats, setStats] = useState({ total: 0, active: 0, completed: 0 }); const [selectedProject, setSelectedProject] = useState(null); const [loading, setLoading] = useState(true); const [taskDialog, setTaskDialog] = useState(null); const [newTask, setNewTask] = useState({ title: "", description: "", priority: "medium", due_date: "" }); useEffect(() => { if (session?.access_token) { fetchProjects(); } }, [session?.access_token]); const fetchProjects = async () => { try { const res = await fetch("/api/staff/projects", { headers: { Authorization: `Bearer ${session?.access_token}` }, }); const data = await res.json(); if (res.ok) { setProjects(data.projects || []); setStats(data.stats || { total: 0, active: 0, completed: 0 }); } } catch (err) { aethexToast.error("Failed to load projects"); } finally { setLoading(false); } }; const updateTaskStatus = async (taskId: string, status: string) => { try { const res = await fetch("/api/staff/projects", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${session?.access_token}`, }, body: JSON.stringify({ action: "update_task", task_id: taskId, status }), }); if (res.ok) { aethexToast.success("Task updated"); fetchProjects(); } } catch (err) { aethexToast.error("Failed to update task"); } }; const createTask = async () => { if (!taskDialog || !newTask.title) return; try { const res = await fetch("/api/staff/projects", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${session?.access_token}`, }, body: JSON.stringify({ action: "create_task", project_id: taskDialog, ...newTask, }), }); if (res.ok) { aethexToast.success("Task created"); setTaskDialog(null); setNewTask({ title: "", description: "", priority: "medium", due_date: "" }); fetchProjects(); } } catch (err) { aethexToast.error("Failed to create task"); } }; const avgProgress = projects.length > 0 ? Math.round( projects.reduce((sum, p) => sum + (p.task_stats.total > 0 ? (p.task_stats.done / p.task_stats.total) * 100 : 0), 0) / projects.length ) : 0; if (loading) { return (
); } return (
{/* Background effects */}
{/* Header */}

Project Tracking

Your projects, tasks, and progress

{/* Summary */}

My Projects

{stats.total}

Avg Progress

{avgProgress}%

Active

{stats.active}

{/* Projects */}
{projects.map((project) => ( setSelectedProject(selectedProject === project.id ? null : project.id)} >
{project.name} {project.description}
{project.status.replace("_", " ").replace(/\b\w/g, (l) => l.toUpperCase())}
Tasks Progress {project.task_stats.done}/{project.task_stats.total}
0 ? (project.task_stats.done / project.task_stats.total) * 100 : 0} className="h-2" />
{project.lead && (

Lead

{project.lead.full_name}

)}

Start Date

{new Date(project.start_date).toLocaleDateString()}

{project.end_date && (

End Date

{new Date(project.end_date).toLocaleDateString()}

)}
{selectedProject === project.id && (

Tasks

{project.tasks.map((task) => (

{task.title}

{task.due_date && (

Due: {new Date(task.due_date).toLocaleDateString()}

)}
))} {project.tasks.length === 0 && (

No tasks yet

)}
)}
))}
{projects.length === 0 && (

No projects found

)}
{/* Create Task Dialog */} setTaskDialog(null)}> Add New Task
setNewTask({ ...newTask, title: e.target.value })} className="bg-slate-700 border-slate-600 text-slate-100" />