"use client"
import ProjectCard from "./project-card"
import { SectionWrapper } from "@/app/components/wrappers/SectionWrapper"
import { LABELS } from "@/app/labels"
import { useProjects } from "@/app/providers/ProjectsProvider"
import {
ProjectInterface,
ProjectSection,
ProjectSectionLabelMapping,
ProjectSections,
ProjectStatus,
ProjectStatusDescriptionMapping,
} from "@/lib/types"
import { cn } from "@/lib/utils"
import NoResultIcon from "@/public/icons/no-result.svg"
import Image from "next/image"
import React, { useCallback, useEffect, useRef, useState } from "react"
const NoResults = () => {
return (
{LABELS.COMMON.NO_RESULTS}
{LABELS.COMMON.NO_RESULTS_DESCRIPTION}
)
}
const ProjectStatusOrderList = ["active", "maintained", "inactive"]
export const ProjectList = () => {
const SCROLL_OFFSET = -400
const [activeId, setActiveId] = useState("")
const [isManualScroll, setIsManualScroll] = useState(false)
const [isMounted, setIsMounted] = useState(false)
const { projects, searchQuery, activeFilters } = useProjects()
const hasSearchParams =
searchQuery?.length > 0 ||
Object.values({
keywords: activeFilters?.keywords ?? [],
builtWith: activeFilters?.builtWith ?? [],
themes: activeFilters?.themes ?? [],
}).some((arr) => arr.length > 0)
const noItems = projects?.length === 0
const sectionsRef = useRef | null>(null) // sections are constant so useRef might be better here
useEffect(() => {
setIsMounted(true)
if (typeof window !== "undefined") {
sectionsRef.current = document.querySelectorAll("div[data-section]")
const handleScroll = () => {
if (isManualScroll) return
sectionsRef.current?.forEach((section: any) => {
const sectionTop = section.offsetTop - SCROLL_OFFSET
if (window.scrollY >= sectionTop && window.scrollY > 0) {
setActiveId(section.getAttribute("id"))
}
})
}
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
}
}, [SCROLL_OFFSET, isManualScroll])
const scrollToId = useCallback((id: string) => {
if (typeof window !== "undefined") {
const element = document.getElementById(id)
const top = element?.offsetTop ?? 0
if (element) {
setActiveId(id) // active clicked id
setIsManualScroll(true) // tell the window event listener to ignore this scrolling
window?.scrollTo({
behavior: "smooth",
top: (top ?? 0) - SCROLL_OFFSET,
})
}
setTimeout(() => setIsManualScroll(false), 800)
}
}, [])
// loading state skeleton
if (!isMounted) {
return (
)
}
if (noItems) return
const projectsGroupByStatus = projects.reduce((acc, project) => {
acc[project.projectStatus] = [
...(acc[project.projectStatus] || []),
project,
]
return acc
}, {} as Record)
if (hasSearchParams) {
return (
{projects?.map((project: any) => (
))}
)
}
return (
{ProjectStatusOrderList.map((status, index) => {
const projects = projectsGroupByStatus[status as ProjectStatus] ?? []
const description =
ProjectStatusDescriptionMapping?.[status as ProjectStatus]
const hasProjects = projects?.length > 0
if (!hasProjects) return null // no projects for this status, hide the section
return (
{projects.map((project: any) => (
))}
)
})}
)
}