From 2e03cfcbc8ed7ac5f44c2fa5059b09190f24369b Mon Sep 17 00:00:00 2001 From: parsa aghaei Date: Sun, 20 Oct 2024 17:51:51 +0330 Subject: [PATCH] homePage projects component updated for Clean Code --- .../components/projects/projects.tsx | 126 ++++++------------ src/app/types/types.ts | 14 ++ 2 files changed, 58 insertions(+), 82 deletions(-) diff --git a/src/app/(routes)/(website)/components/projects/projects.tsx b/src/app/(routes)/(website)/components/projects/projects.tsx index 05dd9bb..3b0d786 100644 --- a/src/app/(routes)/(website)/components/projects/projects.tsx +++ b/src/app/(routes)/(website)/components/projects/projects.tsx @@ -1,24 +1,10 @@ "use client"; - -import React, { useEffect, useState } from "react"; +import { Project, ProjectCategory } from "@/app/types/types"; +import React, { useEffect, useState, useMemo } from "react"; import Skeleton from "react-loading-skeleton"; import "react-loading-skeleton/dist/skeleton.css"; -type Category = { - label: string; - active: boolean; -}; - -type Project = { - id: number; - title: string; - category: string; - images: { src: string; position: string; zIndex: number }[]; - created_at: string; - updated_at: string; -}; - interface MyProjectsProps { dict: { homePage: { @@ -30,8 +16,11 @@ interface MyProjectsProps { }; } -export default function MyProjects({ dict }: MyProjectsProps) { - const [categories, setCategories] = useState([]); +const MAX_PROJECTS = 6; +const MAX_CATEGORIES = 5; + +export default function Projects({ dict }: MyProjectsProps) { + const [categories, setCategories] = useState([]); const [projects, setProjects] = useState([]); const [selectedCategory, setSelectedCategory] = useState("Newest"); @@ -39,8 +28,8 @@ export default function MyProjects({ dict }: MyProjectsProps) { const fetchProjects = async () => { const res = await fetch("/api/website/projects?sort=desc&per_page=20"); const data = await res.json(); - const resProjects = data.projects.data; - const resCategories = data.categories; + const resProjects = data.projects.data || []; // Use default value if undefined + const resCategories = data.categories || []; // Use default value if undefined // Convert JSON string to array const updatedData = resProjects.map((project: { images: string }) => ({ @@ -51,14 +40,14 @@ export default function MyProjects({ dict }: MyProjectsProps) { setProjects(updatedData); // Extract unique categories - const uniqueCategories: Category[] = [{ label: "Newest", active: false }]; - const onlyFiveCategoris: Category[] = [ - ...resCategories.map((category: string) => ({ + const uniqueCategories: ProjectCategory[] = [ + { label: "Newest", active: false }, + ...resCategories.slice(0, MAX_CATEGORIES).map((category: string) => ({ label: category, active: false, })), - ].slice(0, 5); - uniqueCategories.push(...onlyFiveCategoris); + ]; + setCategories(uniqueCategories); }; @@ -68,7 +57,7 @@ export default function MyProjects({ dict }: MyProjectsProps) { // Group projects by category const groupProjectsByCategory = (projects: Project[]) => { return projects.reduce>((acc, project) => { - const category = project.category; + const category = project.category || "Uncategorized"; // Default category if (!acc[category]) { acc[category] = []; } @@ -77,95 +66,68 @@ export default function MyProjects({ dict }: MyProjectsProps) { }, {}); }; - const groupedProjects = groupProjectsByCategory(projects); + const groupedProjects = useMemo(() => groupProjectsByCategory(projects), [projects]); // Filter projects by selected category - const filteredProjects: Project[] = - selectedCategory === "Newest" - ? projects.slice(0, 6) // Get first 6 projects for "Newest" - : groupedProjects[selectedCategory]?.slice(0, 6) || []; // Get first 6 projects from selected category + const filteredProjects: Project[] = useMemo(() => { + return selectedCategory === "Newest" + ? projects.slice(0, MAX_PROJECTS) + : groupedProjects[selectedCategory]?.slice(0, MAX_PROJECTS) || []; + }, [selectedCategory, projects, groupedProjects]); + + const renderSkeletons = (count: number) => ( +
+ {Array.from({ length: count }, (_, index) => ( +
+ + + +
+ ))} +
+ ); return ( -
-

{dict.homePage.projects.title}

-

- {dict.homePage.projects.description} -

+
+

{dict.homePage.projects.title}

+

{dict.homePage.projects.description}

    {categories.length > 0 ? ( categories.map((category, index) => (
  • setSelectedCategory(category.label)} - className={`select-none whitespace-nowrap rounded-md border border-[#545454] bg-[#F8F8F8] p-2 text-[14px] md:text-[18px] font-[600] hover:cursor-pointer hover:border-[#FD6F00] capitalize ${ - selectedCategory === category.label - ? "bg-[#FD6F00] text-[#FFFFFF]" - : "text-[#000]" + className={`select-none whitespace-nowrap rounded-md border border-[#545454] bg-[#F8F8F8] p-2 text-[14px] font-[600] capitalize hover:cursor-pointer hover:border-[#FD6F00] md:text-[18px] ${ + selectedCategory === category.label ? "bg-[#FD6F00] text-[#FFFFFF]" : "text-[#000]" }`} > {category.label}
  • )) ) : ( -
    - - - - -
    + renderSkeletons(4) // Adjust the count as needed )}
{filteredProjects.length > 0 ? ( filteredProjects.map((project, index) => ( -
+
{project.images.map((image, idx) => ( UI/UX Vector ))}
-
- {project.category} -
-

- {project.title} -

+
{project.category}
+

{project.title}

)) ) : ( -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
+ renderSkeletons(3) // Adjust the count as needed )}
diff --git a/src/app/types/types.ts b/src/app/types/types.ts index a184ca7..a3b0caf 100644 --- a/src/app/types/types.ts +++ b/src/app/types/types.ts @@ -200,3 +200,17 @@ export type Service = { imageSrc: string; altText: string; }; + +export type ProjectCategory = { + label: string; + active: boolean; +}; + +export type Project = { + id: number; + title: string; + category: string; + images: { src: string; position: string; zIndex: number }[]; + created_at: string; + updated_at: string; +};