"use client" import React, { useCallback, useEffect, useRef, useState } from "react" import Image from "next/image" import NoResultIcon from "@/public/icons/no-result.svg" import { useProjectFiltersState } from "@/state/useProjectFiltersState" import { cva } from "class-variance-authority" import { LangProps } from "@/types/common" import { ProjectInterface, ProjectSection, ProjectSectionLabelMapping, ProjectSections, ProjectStatus, ProjectStatusDescriptionMapping, } from "@/lib/types" import { cn } from "@/lib/utils" import { useTranslation } from "@/app/i18n/client" import ProjectCard from "./project-card" const sectionTitleClass = cva( "relative font-sans text-base font-bold uppercase tracking-[3.36px] text-anakiwa-950 after:ml-8 after:absolute after:top-1/2 after:h-[1px] after:w-full after:translate-y-1/2 after:bg-anakiwa-300 after:content-['']" ) const NoResults = ({ lang }: LangProps["params"]) => { const { t } = useTranslation(lang, "common") return (
no result icon
{t("noResults")} {t("noResultsDescription")}
) } const ProjectStatusOrderList = ["active", "maintained", "inactive"] export const ProjectList = ({ lang }: LangProps["params"]) => { const { t } = useTranslation(lang, "resources-page") const SCROLL_OFFSET = -400 const [activeId, setActiveId] = useState("") const [isManualScroll, setIsManualScroll] = useState(false) const [isMounted, setIsMounted] = useState(false) const { projects, searchQuery, queryString } = useProjectFiltersState( (state) => state ) 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) } }, []) const hasActiveFilters = searchQuery !== "" || queryString !== "" // 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 ) // show all projects without sections if there are active filters if (hasActiveFilters) { return (
{projects.map((project) => ( ))}
) } 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 (
{!hasActiveFilters && (

{status}

{description}
)}
{projects.map((project) => ( ))}
) })}
) }