diff --git a/Internal/adapters/repository/projectRepo.go b/Internal/adapters/repository/projectRepo.go index a06199f..8ede3b1 100644 --- a/Internal/adapters/repository/projectRepo.go +++ b/Internal/adapters/repository/projectRepo.go @@ -25,3 +25,11 @@ func (pr *ProjectRepo) FetchProjects(projects []domain.Project) ([]domain.Projec } return projects, nil } + +func (pr *ProjectRepo) ProjectById(id string) (*domain.Project, error) { + var project domain.Project + if err := pr.DB.Gorm.First(&project, id).Error; err != nil { + return nil, err + } + return &project, nil +} diff --git a/Internal/api/Routes/routev1.go b/Internal/api/Routes/routev1.go index 1fc52f9..c908a3e 100644 --- a/Internal/api/Routes/routev1.go +++ b/Internal/api/Routes/routev1.go @@ -51,6 +51,7 @@ func SetupRouterV1(r *gin.Engine, deps Deps) { project := protected.Group("/project") { project.GET("/projects", deps.Project.GetAllProjectHandler) + project.GET("/:projectid", deps.Project.GetProjectHandler) } } } diff --git a/Internal/api/handlers/projectHandler.go b/Internal/api/handlers/projectHandler.go index d4d37ec..043041d 100644 --- a/Internal/api/handlers/projectHandler.go +++ b/Internal/api/handlers/projectHandler.go @@ -61,3 +61,19 @@ func (ph *ProjectHandler) GetAllProjectHandler(c *gin.Context) { "data": projects, }) } + +func (ph *ProjectHandler) GetProjectHandler(c *gin.Context) { + projectId := c.Param("projectid") + project, err := ph.ProjectService.GetProjectById(projectId) + if err != nil { + c.JSON(500, gin.H{ + "message": "failed to get project", + "data": err.Error(), + }) + return + } + c.JSON(200, gin.H{ + "message": "success in fetching project", + "data": project, + }) +} diff --git a/Internal/api/middleware/auth.go b/Internal/api/middleware/auth.go index 6fb6683..8c6ce6b 100644 --- a/Internal/api/middleware/auth.go +++ b/Internal/api/middleware/auth.go @@ -27,6 +27,7 @@ func AuthMiddleware(userRepo *repository.UserRepository, cfg *config.Config) gin "message": "Authorization header not found", "data": err.Error(), }) + c.Abort() return } parts := strings.Split(authHeader, " ") diff --git a/Internal/core/services/projectService.go b/Internal/core/services/projectService.go index b9ce760..8d36158 100644 --- a/Internal/core/services/projectService.go +++ b/Internal/core/services/projectService.go @@ -45,3 +45,11 @@ func (ps *ProjectService) GetProjects(Role string) ([]domain.Project, error) { } return project, nil } + +func (ps *ProjectService) GetProjectById(id string) (*domain.Project, error) { + project, err := ps.ProjectRepo.ProjectById(id) + if err != nil { + return nil, err + } + return project, nil +} diff --git a/Lb-web/src/features/project/components/CreateProjectModal.tsx b/Lb-web/src/features/project/components/CreateProjectModal.tsx index 87ecd94..c127db2 100644 --- a/Lb-web/src/features/project/components/CreateProjectModal.tsx +++ b/Lb-web/src/features/project/components/CreateProjectModal.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; +import { Textarea } from "../../../components/ui/textarea"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { useAuth } from "@/features/Login/context/AuthContext"; diff --git a/Lb-web/src/features/project/pages/ProjectDashboard.tsx b/Lb-web/src/features/project/pages/ProjectDashboard.tsx new file mode 100644 index 0000000..e61e152 --- /dev/null +++ b/Lb-web/src/features/project/pages/ProjectDashboard.tsx @@ -0,0 +1,113 @@ +import { useEffect, useState } from "react"; +import { useParams, Link } from "react-router"; +import { projectService } from "../services/projectService"; +import { Button } from "@/components/ui/button"; +import { ArrowLeft, LayoutDashboard, Settings } from "lucide-react"; + + +export default function ProjectDashboard() { + const { id } = useParams<{ id: string }>(); + const [project, setProject] = useState<{ id: number; name: string; desc: string; created_at: string } | null>(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchProject = async () => { + if (!id) return; + setIsLoading(true); + try { + const data = await projectService.getProjectById(id); + setProject(data); + } catch (err: any) { // eslint-disable-line @typescript-eslint/no-explicit-any + setError("Failed to load project details."); + console.error(err); + } finally { + setIsLoading(false); + } + }; + + fetchProject(); + }, [id]); + + if (isLoading) { + return ( +
+
+
+ ); + } + + if (error || !project) { + return ( +
+

{error || "Project not found"}

+ + + +
+ ); + } + + return ( +
+ {/* Subtle Background */} +
+ + {/* Sidebar (Mockup for now, or just a simple header) */} + {/* Let's stick to a clean layout similar to Home but focused on the project */} + +
+
+ + + +
+

{project.name}

+

Project Dashboard

+
+
+
+ + +
+
+ +
+
+
+

Welcome to {project.name}

+

+ {project.desc || "No description provided for this project."} +

+
+ Created on {new Date(project.created_at).toLocaleDateString()} + {/* Potential place for more stats like '3 Members', '5 Tasks', etc. */} +
+
+ + {/* Placeholder for future dashboard widgets */} +
+
+ Widget Placeholder +
+
+ Widget Placeholder +
+
+ Widget Placeholder +
+
+
+
+
+ ); +} diff --git a/Lb-web/src/features/project/services/projectService.ts b/Lb-web/src/features/project/services/projectService.ts index c5e8613..e0cba4b 100644 --- a/Lb-web/src/features/project/services/projectService.ts +++ b/Lb-web/src/features/project/services/projectService.ts @@ -23,5 +23,9 @@ export const projectService = { getProjects: async (): Promise => { const response = await api.get('/protected/project/projects'); return response.data.data; + }, + getProjectById: async (id: string): Promise => { + const response = await api.get(`/protected/project/${id}`); + return response.data.data; } }; diff --git a/Lb-web/src/main.tsx b/Lb-web/src/main.tsx index e120bda..424efa0 100644 --- a/Lb-web/src/main.tsx +++ b/Lb-web/src/main.tsx @@ -11,6 +11,7 @@ import { ProtectedRoute, PublicRoute, AdminRoute } from './features/Login/compon import SettingsLayout from './features/admin-setting/layout/SettingsLayout.tsx' import UserManagement from './features/admin-setting/pages/UserManagement.tsx' import Appearance from './features/admin-setting/pages/Appearance.tsx' +import ProjectDashboard from './features/project/pages/ProjectDashboard.tsx' const router = createBrowserRouter([ { @@ -60,6 +61,10 @@ const router = createBrowserRouter([ element: } ] + }, + { + path: 'project/:id', + element: } ] } diff --git a/Lb-web/src/pages/Home.tsx b/Lb-web/src/pages/Home.tsx index 8e5e840..242ac9f 100644 --- a/Lb-web/src/pages/Home.tsx +++ b/Lb-web/src/pages/Home.tsx @@ -121,20 +121,22 @@ export default function Home() {
{projects.map((project: { id: number; name: string; desc: string; created_at: string }) => ( -
-
-
- {project.name.charAt(0).toUpperCase()} + +
+
+
+ {project.name.charAt(0).toUpperCase()} +
+
+

{project.name}

+

+ {project.desc || "No description provided."} +

+
+ Created {new Date(project.created_at).toLocaleDateString()}
-

{project.name}

-

- {project.desc || "No description provided."} -

-
- Created {new Date(project.created_at).toLocaleDateString()} -
-
+ ))}