From 9c98052638943ad5b14ce1413aabb2de42767ace Mon Sep 17 00:00:00 2001 From: sanjidaRimi023 Date: Fri, 1 May 2026 22:19:05 +0600 Subject: [PATCH] feat:added project details page with prod. api --- src/App.tsx | 2 +- src/components/ProjectCard.tsx | 102 +++++ src/components/ProjectsSection.tsx | 101 +---- src/pages/ProjectDetails.tsx | 618 ++++++++++++++++------------- 4 files changed, 448 insertions(+), 375 deletions(-) create mode 100644 src/components/ProjectCard.tsx diff --git a/src/App.tsx b/src/App.tsx index c08e028..85a4320 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,7 +23,7 @@ function AnimatedRoutes() { } /> } /> - } /> + } /> {/* } /> } /> */} {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx new file mode 100644 index 0000000..75dfd4a --- /dev/null +++ b/src/components/ProjectCard.tsx @@ -0,0 +1,102 @@ +import { motion } from "framer-motion"; +import { ExternalLink } from "lucide-react"; +import { useState } from "react"; +import { Link } from "react-router-dom"; + +export function ProjectCard({ project, color, index, isInView }) { + const [mousePosition, setMousePosition] = useState({ x: 50, y: 50 }); + const [isHovered, setIsHovered] = useState(false); + + const handleMouseMove = (e: React.MouseEvent) => { + const rect = e.currentTarget.getBoundingClientRect(); + const x = ((e.clientX - rect.left) / rect.width) * 100; + const y = ((e.clientY - rect.top) / rect.height) * 100; + setMousePosition({ x, y }); + }; + + return ( + + setIsHovered(true)} + onMouseLeave={() => { + setIsHovered(false); + setMousePosition({ x: 50, y: 50 }); + }} + > + {/* Main Card Container with 3D Tilt */} +
+ {/* Image Container */} +
+ {project.title} + + {/* Dynamic Shine Overlay */} +
+
+ + {/* Gradient Overlay */} +
+ + {/* Content */} +
+
+ {/* Category */} + + {project.category} + + + {/* Title */} +

+ {project.title} +

+ + {/* View Project Link */} + + live + + +
+
+ + {/* Neon Border Glow */} +
+
+ + + ); +} \ No newline at end of file diff --git a/src/components/ProjectsSection.tsx b/src/components/ProjectsSection.tsx index 5b1ce67..381eed3 100644 --- a/src/components/ProjectsSection.tsx +++ b/src/components/ProjectsSection.tsx @@ -1,9 +1,10 @@ import { Button } from "@/components/ui/button"; import { useProjects } from "@/hooks/queires/useProjects"; import { motion, useInView } from "framer-motion"; -import { ArrowRight, ExternalLink } from "lucide-react"; -import { useRef, useState } from "react"; +import { ArrowRight } from "lucide-react"; +import { useRef } from "react"; import { Link } from "react-router-dom"; +import { ProjectCard } from "./ProjectCard"; const gradientColors = [ "from-neon-blue/90", @@ -98,99 +99,3 @@ export default function ProjectsSection() { ); } - -function ProjectCard({ project, color, index, isInView }) { - const [mousePosition, setMousePosition] = useState({ x: 50, y: 50 }); - const [isHovered, setIsHovered] = useState(false); - - const handleMouseMove = (e: React.MouseEvent) => { - const rect = e.currentTarget.getBoundingClientRect(); - const x = ((e.clientX - rect.left) / rect.width) * 100; - const y = ((e.clientY - rect.top) / rect.height) * 100; - setMousePosition({ x, y }); - }; - - return ( - setIsHovered(true)} - onMouseLeave={() => { - setIsHovered(false); - setMousePosition({ x: 50, y: 50 }); - }} - > - {/* Main Card Container with 3D Tilt */} -
- {/* Image Container */} -
- {project.title} - - {/* Dynamic Shine Overlay */} -
-
- - {/* Gradient Overlay */} -
- - {/* Content */} -
-
- {/* Category */} - - {project.category} - - - {/* Title */} -

- {project.title} -

- - {/* View Project Link */} - - live - - -
-
- - {/* Neon Border Glow */} -
-
- - ); -} diff --git a/src/pages/ProjectDetails.tsx b/src/pages/ProjectDetails.tsx index c6fe2d3..9f52362 100644 --- a/src/pages/ProjectDetails.tsx +++ b/src/pages/ProjectDetails.tsx @@ -1,366 +1,432 @@ -import { useParams, Link, useNavigate } from 'react-router-dom'; -import { motion } from 'framer-motion'; -import { ArrowLeft, ExternalLink, Github, Calendar, Clock, Users, ChevronRight } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import ReactMarkdown from 'react-markdown'; -import remarkGfm from 'remark-gfm'; -import Navbar from '@/components/Navbar'; -import Footer from '@/components/Footer'; -import PageTransition from '@/components/PageTransition'; -import { getProjectBySlug, getRelatedProjects } from '@/data/projectData'; +import Footer from "@/components/Footer"; +import Navbar from "@/components/Navbar"; +import PageTransition from "@/components/PageTransition"; +import { Button } from "@/components/ui/button"; +import { useProjectById } from "@/hooks/queires/useProjects"; +import { motion } from "framer-motion"; +import { + Calendar, + ChevronRight, + Clock, + ExternalLink, + Github, + Users, +} from "lucide-react"; +import ReactMarkdown from "react-markdown"; +import { Link, useNavigate, useParams } from "react-router-dom"; +import remarkGfm from "remark-gfm"; + +interface Result { + label: string; + value: string | number; +} + +interface ProjectData { + id: string; + category: string; + title: string; + description: string; + year: string | number; + duration: string; + team: string | number; + client: string; + liveUrl: string; + codeUrl?: string; + image: string; + results?: Result[]; + fullDescription: string; + features?: string[]; + technologies?: string[]; + challenges?: string[]; + gallery?: string[]; +} + +const CATEGORY_LABELS: Record = { + web: "Web Development", + mobile: "Mobile App", + ai: "AI & Machine Learning", + cloud: "Cloud Solutions", +}; export default function ProjectDetails() { - const { slug } = useParams<{ slug: string }>(); + const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); - const project = getProjectBySlug(slug || ''); + const { data, isLoading, isError } = useProjectById(id || ""); - if (!project) { + const project: ProjectData | null = + data?.data?.data || data?.data || data || null; + + if (isLoading) { return (
-
-

Project Not Found

-

The project you're looking for doesn't exist.

- +
+
+ + Loading project details... +
); } - const relatedProjects = getRelatedProjects(project); - const categoryLabels: Record = { - web: 'Web Development', - mobile: 'Mobile App', - ai: 'AI & Machine Learning', - cloud: 'Cloud Solutions', - }; + if (isError || !project) { + return ( + +
+
+

+ Project Not Found +

+

+ The project you're looking for does not exist or could not be + loaded. +

+ +
+
+
+ ); + } return ( -
+
- {/* Hero */} -
-
-
-
+ {/* Hero Section */} +
+ {/* Ambient Background Glows */} +
+
+
-
- {/* Breadcrumb */} - + {/* Breadcrumb Navigation */} + - Home - - Projects - - {project.title} - + + Home + + + + Projects + + + + {project.title} + +
- {/* Content */} -
+ {/* Content Block */} +
- {categoryLabels[project.category]} + {CATEGORY_LABELS[project.category] || project.category} {project.title} {project.description} - {/* Meta */} + {/* Project Metadata */} -
- -

Year

-

{project.year}

-
-
- -

Duration

-

{project.duration}

-
-
- -

Team

-

{project.team}

-
-
-

Client

-

{project.client}

-
+ {[ + { label: "Year", value: project.year, icon: Calendar }, + { label: "Duration", value: project.duration, icon: Clock }, + { label: "Team Size", value: project.team, icon: Users }, + { label: "Client", value: project.client }, + ].map((item, idx) => ( +
+ {item.icon ? ( + + ) : ( +
+ )} + + {item.label} + + + {item.value} + +
+ ))} - {/* Actions */} + {/* Call to Actions */} - - + + + + {project.codeUrl && ( + + + + )}
- {/* Image */} + {/* Project Cover Visual */} {project.title} +
- {/* Results */} -
-
- -

Key Results

-
- -
- {project.results.map((result, index) => ( - -

- {result.value} -

-

{result.label}

-
- ))} -
-
-
- - {/* Details */} -
-
-
- {/* Full Description */} + {/* Key Results Section */} + {project.results && project.results.length > 0 && ( +
+
-

About the Project

-
+

+ Key Performance Outcomes +

+

+ Measurable impact and business value generated by this + project. +

+ + +
+ {project.results.map((result, index) => ( + + + {result.value} + + + {result.label} + + + ))} +
+
+
+ )} + + {/* Main Details Section */} +
+
+
+ {/* Main Text Content */} +
+

+ About the Project +

+

{children}

, - strong: ({ children }) => {children}, - ul: ({ children }) =>
    {children}
, - li: ({ children }) =>
  • {children}
  • , + p: ({ children }) => ( +

    + {children} +

    + ), + strong: ({ children }) => ( + + {children} + + ), + ul: ({ children }) => ( +
      + {children} +
    + ), + li: ({ children }) => ( +
  • {children}
  • + ), }} > {project.fullDescription}
    - +
    - {/* Features & Tech */} -
    - -

    Key Features

    -
      - {project.features.map((feature, index) => ( -
    • - - {feature} -
    • - ))} -
    -
    - - -

    Technologies Used

    -
    - {project.technologies.map((tech) => ( - - {tech} - - ))} + {/* Sidebar Capabilities */} +
    + {/* Features */} + {project.features && project.features.length > 0 && ( +
    +

    + Key Capabilities +

    +
      + {project.features.map((feature, index) => ( +
    • + + + {feature} + +
    • + ))} +
    - + )} - -

    Challenges Solved

    -
      - {project.challenges.map((challenge, index) => ( -
    • - - {challenge} -
    • - ))} -
    -
    + {/* Technologies Used */} + {project.technologies && project.technologies.length > 0 && ( +
    +

    + Technologies Used +

    +
    + {project.technologies.map((tech) => ( + + {tech} + + ))} +
    +
    + )} + + {/* Challenges Solved */} + {project.challenges && project.challenges.length > 0 && ( +
    +

    + Challenges Solved +

    +
      + {project.challenges.map((challenge, index) => ( +
    • + + + {challenge} + +
    • + ))} +
    +
    + )}
    - {/* Gallery */} -
    -
    - -

    Project Gallery

    -
    + {/* Gallery Section */} + {project.gallery && project.gallery.length > 0 && ( +
    +
    +
    +

    + Project Gallery +

    +

    + A visual overview of the implementation and user interface. +

    +
    -
    - {project.gallery.map((image, index) => ( - - {`${project.title} - - ))} -
    -
    -
    - - {/* Related Projects */} - {relatedProjects.length > 0 && ( -
    -
    - -

    Related Projects

    -
    - -
    - {relatedProjects.map((relatedProject, index) => ( - + {project.gallery.map((image, index) => ( + - -
    - {relatedProject.title} -
    -
    -

    - {relatedProject.title} -

    -

    - {relatedProject.description} -

    -
    - -
    + {`${project.title} +
    + ))}
    - - - - - -
    )}