import React, { useState, useEffect } from "react"; import { Project } from "../entities/Project"; import { MagnifyingGlassIcon, FolderIcon, Squares2X2Icon, Bars3Icon, } from "@heroicons/react/24/solid"; import ConfirmDialog from "./Shared/ConfirmDialog"; import ProjectModal from "./Project/ProjectModal"; import { useDataContext } from "../contexts/DataContext"; import useFetchProjects from "../hooks/useFetchProjects"; import { PriorityType, StatusType } from "../entities/Task"; import { useSearchParams } from "react-router-dom"; import ProjectItem from "./Project/ProjectItem"; type ProjectTaskCounts = Record; const getPriorityStyles = (priority: PriorityType) => { switch (priority) { case "low": return { color: "bg-green-500" }; case "medium": return { color: "bg-yellow-500" }; case "high": return { color: "bg-red-500" }; default: return { color: "bg-gray-500" }; } }; const Projects: React.FC = () => { const { areas, createProject, updateProject, deleteProject } = useDataContext(); const [taskStatusCounts, setTaskStatusCounts] = useState>({}); const [isProjectModalOpen, setIsProjectModalOpen] = useState(false); const [projectToEdit, setProjectToEdit] = useState(null); const [projectToDelete, setProjectToDelete] = useState(null); const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false); const [activeDropdown, setActiveDropdown] = useState(null); const [searchQuery, setSearchQuery] = useState(""); const [viewMode, setViewMode] = useState<"cards" | "list">("cards"); const [searchParams, setSearchParams] = useSearchParams(); const activeFilter = searchParams.get("active") || "all"; const areaFilter = searchParams.get("area_id") || ""; const { projects, taskStatusCounts: fetchedTaskStatusCounts, isLoading, isError, mutate, } = useFetchProjects({ activeFilter, areaFilter }); useEffect(() => { setTaskStatusCounts(fetchedTaskStatusCounts || {}); }, [fetchedTaskStatusCounts]); const getCompletionPercentage = (projectId: number | undefined) => { if (!projectId) return 0; const taskStatus = taskStatusCounts[projectId] || { not_started: 0, in_progress: 0, done: 0, archived: 0, }; const totalTasks = taskStatus.done + taskStatus.not_started + taskStatus.in_progress; if (totalTasks === 0) return 0; return Math.round((taskStatus.done / totalTasks) * 100); }; const handleSaveProject = async (project: Project) => { if (project.id) { await updateProject(project.id, project); } else { await createProject(project); } setIsProjectModalOpen(false); mutate(); }; const handleEditProject = (project: Project) => { setProjectToEdit(project); setIsProjectModalOpen(true); }; const handleDeleteProject = async () => { if (!projectToDelete) return; await deleteProject(projectToDelete.id!); setIsConfirmDialogOpen(false); setProjectToDelete(null); mutate(); }; const handleActiveFilterChange = (e: React.ChangeEvent) => { const newActiveFilter = e.target.value; const params = new URLSearchParams(searchParams); if (newActiveFilter === "all") { params.delete("active"); } else { params.set("active", newActiveFilter); } setSearchParams(params); }; const handleAreaFilterChange = (e: React.ChangeEvent) => { const newAreaFilter = e.target.value; const params = new URLSearchParams(searchParams); if (newAreaFilter === "") { params.delete("area_id"); } else { params.set("area_id", newAreaFilter); } setSearchParams(params); }; const filteredProjects = projects.filter((project) => project.name.toLowerCase().includes(searchQuery.toLowerCase()) ); if (isLoading) { return (
Loading projects...
); } if (isError) { return (
Error loading projects.
); } const groupedProjects = filteredProjects.reduce>( (acc, project) => { const areaName = project.area ? project.area.name : "Uncategorized"; if (!acc[areaName]) acc[areaName] = []; acc[areaName].push(project); return acc; }, {} ); return (

Projects

{/* View Mode and Filters */}
{/* Search Bar */}
setSearchQuery(e.target.value)} className="w-full bg-transparent border-none focus:ring-0 focus:outline-none dark:text-white" />
{/* Projects Grid/List */}
{Object.keys(groupedProjects).length === 0 ? (
No projects found.
) : ( Object.keys(groupedProjects).map((areaName) => ( {viewMode === "cards" && (

{areaName}

)} {groupedProjects[areaName].map((project) => { const { color } = getPriorityStyles(project.priority || "low"); return ( ); })}
)) )}
{isProjectModalOpen && ( { setIsProjectModalOpen(false); setProjectToEdit(null); }} onSave={handleSaveProject} project={projectToEdit || undefined} areas={areas} /> )} {isConfirmDialogOpen && ( setIsConfirmDialogOpen(false)} /> )}
); }; export default Projects;