"use client"; import { useEffect, useState } from "react"; import { useSession } from "next-auth/react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Plus, Sparkles, Loader2, MoreVertical, Trash2 } from "lucide-react"; import Link from "next/link"; import { useParams } from "next/navigation"; import { ProjectCreationModal } from "@/components/project-creation-modal"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { toast } from "sonner"; interface ProjectWithStats { id: string; name: string; slug: string; productName: string; productVision?: string; workspacePath?: string; status?: string; createdAt: string | null; updatedAt: string | null; stats: { sessions: number; costs: number; }; } function getTimeAgo(dateStr: string | null | undefined): string { if (!dateStr) return "Unknown"; const date = new Date(dateStr); if (isNaN(date.getTime())) return "Unknown"; const now = new Date(); const diff = now.getTime() - date.getTime(); const days = Math.floor(diff / (1000 * 60 * 60 * 24)); if (days === 0) return "Today"; if (days === 1) return "Yesterday"; if (days < 7) return `${days} days ago`; if (days < 30) return `${Math.floor(days / 7)} weeks ago`; if (days < 365) return `${Math.floor(days / 30)} months ago`; return `${Math.floor(days / 365)} years ago`; } export default function ProjectsPage() { const params = useParams(); const workspace = params.workspace as string; const { data: session, status } = useSession(); const [projects, setProjects] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showCreationModal, setShowCreationModal] = useState(false); const [projectToDelete, setProjectToDelete] = useState(null); const [isDeleting, setIsDeleting] = useState(false); const fetchProjects = async () => { try { setLoading(true); const res = await fetch("/api/projects"); if (!res.ok) { const err = await res.json(); throw new Error(err.error || "Failed to fetch projects"); } const data = await res.json(); setProjects(data.projects || []); setError(null); } catch (err: unknown) { console.error("Error fetching projects:", err); setError(err instanceof Error ? err.message : "Unknown error"); } finally { setLoading(false); } }; useEffect(() => { if (status === "authenticated") { fetchProjects(); } else if (status === "unauthenticated") { setLoading(false); } }, [status]); const handleDeleteProject = async () => { if (!projectToDelete) return; setIsDeleting(true); try { const res = await fetch("/api/projects/delete", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ projectId: projectToDelete.id }), }); if (res.ok) { toast.success("Project deleted"); setProjectToDelete(null); fetchProjects(); } else { const err = await res.json(); toast.error(err.error || "Failed to delete project"); } } catch (err) { console.error("Delete error:", err); toast.error("An error occurred"); } finally { setIsDeleting(false); } }; if (status === "loading") { return (
); } return ( <>

Projects

{session?.user?.email}

{loading && (
)} {error && (

Error: {error}

)} {!loading && !error && projects.length > 0 && (

Your Projects

{projects.map((project) => { const projectHref = `/${workspace}/project/${project.id}/overview`; return (
📦
{project.productName} {getTimeAgo(project.updatedAt)}
{project.status}
e.preventDefault()}> { e.preventDefault(); setProjectToDelete(project); }} > Delete Project

{project.productVision || "No description"}

{project.workspacePath && (

📁 {project.workspacePath.split("/").pop()}

)}
Sessions:{" "} {project.stats.sessions}
Costs:{" "} ${project.stats.costs.toFixed(2)}
); })} setShowCreationModal(true)} >

Create New Project

Start tracking a new product

)} {!loading && !error && projects.length === 0 && (

No projects yet

Create your first project to start tracking your AI-powered development workflow.

)}
{ setShowCreationModal(open); if (!open) fetchProjects(); }} workspace={workspace} /> !open && setProjectToDelete(null)}> Are you absolutely sure? This will delete "{projectToDelete?.productName}". Sessions will be preserved but unlinked. Cancel {isDeleting ? : } Delete Project ); }