parsaaghayi-front/src/app/(routes)/(website)/components/projects/projects.tsx
2024-10-20 19:15:49 +03:30

136 lines
5.0 KiB
TypeScript

"use client";
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";
interface MyProjectsProps {
dict: {
homePage: {
projects: {
title: string;
description: string;
};
};
};
}
const MAX_PROJECTS = 6;
const MAX_CATEGORIES = 5;
export default function Projects({ dict }: MyProjectsProps) {
const [categories, setCategories] = useState<ProjectCategory[]>([]);
const [projects, setProjects] = useState<Project[]>([]);
const [selectedCategory, setSelectedCategory] = useState<string>("Newest");
useEffect(() => {
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 || []; // 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 }) => ({
...project,
images: JSON.parse(project.images),
}));
setProjects(updatedData);
// Extract unique categories
const uniqueCategories: ProjectCategory[] = [
{ label: "Newest", active: false },
...resCategories.slice(0, MAX_CATEGORIES).map((category: string) => ({
label: category,
active: false,
})),
];
setCategories(uniqueCategories);
};
fetchProjects();
}, []);
// Group projects by category
const groupProjectsByCategory = (projects: Project[]) => {
return projects.reduce<Record<string, Project[]>>((acc, project) => {
const category = project.category || "Uncategorized"; // Default category
if (!acc[category]) {
acc[category] = [];
}
acc[category].push(project);
return acc;
}, {});
};
const groupedProjects = useMemo(() => groupProjectsByCategory(projects), [projects]);
// Filter projects by 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) => (
<div className="flex w-full flex-wrap justify-center gap-5">
{Array.from({ length: count }, (_, index) => (
<div key={index} className="w-[45%] md:w-[30%]">
<Skeleton containerClassName={"w-full"} height={150} />
<Skeleton containerClassName={"w-full"} height={40} />
<Skeleton containerClassName={"w-full"} height={60} />
</div>
))}
</div>
);
return (
<div className="flex w-full max-w-[90%] flex-wrap items-center justify-center pt-[50px]" id="projects">
<h2 className="my-10 mt-20 text-[55px] font-[800] capitalize text-black">{dict.homePage.projects.title}</h2>
<p className="text-center text-[21px] font-[400] text-black">{dict.homePage.projects.description}</p>
<ul className="mb-10 mt-20 flex w-full flex-wrap items-center justify-center gap-2">
{categories.length > 0 ? (
categories.map((category, index) => (
<li
key={index}
onClick={() => setSelectedCategory(category.label)}
className={`select-none whitespace-nowrap rounded-md 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}
</li>
))
) : (
renderSkeletons(4) // Adjust the count as needed
)}
</ul>
<div className="flex w-full flex-wrap items-start justify-center gap-8 lg:gap-20">
{filteredProjects.length > 0 ? (
filteredProjects.map((project, index) => (
<div key={index} className="project flex w-[45%] flex-wrap">
<div className="relative my-5 h-[200px] w-full overflow-hidden bg-[#FFEBDB] md:h-[250px] lg:h-[300px]">
{project.images.map((image, idx) => (
<img
key={idx}
src={image.src}
alt="UI/UX Vector"
className={`absolute ${idx === 0 ? "bottom-0 start-0" : "end-0 top-0"} z-${image.zIndex} project-image w-[85%] max-w-[350px]`}
/>
))}
</div>
<h5 className="w-full text-[15px] font-[600] text-[#FD6F00] lg:text-[20px]">{project.category}</h5>
<p className="text-[18px] font-[800] text-black hover:cursor-pointer lg:text-[22px]">{project.title}</p>
</div>
))
) : (
renderSkeletons(3) // Adjust the count as needed
)}
</div>
</div>
);
}