"use client"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Category } from "@/lib/types"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { useRouter } from "next/navigation"; import React, { useEffect, useState } from "react"; const defaultLogo = "/default-logo.png"; // Fallback logo path const MAX_DESCRIPTION_LENGTH = 100; // Set max length for description const MAX_LOGOS = 5; // Max logos to display at once const formattedBadge = (type: string) => { switch (type) { case "vm": return VM; case "ct": return LXC; case "pve": return PVE; case "addon": return ADDON; } return null; }; const CategoryView = () => { const [categories, setCategories] = useState([]); const [selectedCategoryIndex, setSelectedCategoryIndex] = useState(null); const [currentScripts, setCurrentScripts] = useState([]); const [logoIndices, setLogoIndices] = useState<{ [key: string]: number }>({}); const router = useRouter(); useEffect(() => { const fetchCategories = async () => { try { const basePath = process.env.NODE_ENV === "production" ? "/ProxmoxVE" : ""; const response = await fetch(`${basePath}/api/categories`); if (!response.ok) { throw new Error("Failed to fetch categories"); } const data = await response.json(); setCategories(data); // Initialize logo indices const initialLogoIndices: { [key: string]: number } = {}; data.forEach((category: any) => { initialLogoIndices[category.name] = 0; }); setLogoIndices(initialLogoIndices); } catch (error) { console.error("Error fetching categories:", error); } }; fetchCategories(); }, []); const handleCategoryClick = (index: number) => { setSelectedCategoryIndex(index); setCurrentScripts(categories[index]?.scripts || []); // Update scripts for the selected category }; const handleBackClick = () => { setSelectedCategoryIndex(null); setCurrentScripts([]); // Clear scripts when going back }; const handleScriptClick = (scriptSlug: string) => { router.push(`/scripts?id=${scriptSlug}`); }; const navigateCategory = (direction: "prev" | "next") => { if (selectedCategoryIndex !== null) { const newIndex = direction === "prev" ? (selectedCategoryIndex - 1 + categories.length) % categories.length : (selectedCategoryIndex + 1) % categories.length; setSelectedCategoryIndex(newIndex); setCurrentScripts(categories[newIndex]?.scripts || []); // Update scripts for the new category } }; const switchLogos = (categoryName: string, direction: "prev" | "next") => { setLogoIndices((prev) => { const currentIndex = prev[categoryName] || 0; const category = categories.find((cat) => cat.name === categoryName); if (!category || !category.scripts) return prev; const totalLogos = category.scripts.length; const newIndex = direction === "prev" ? (currentIndex - MAX_LOGOS + totalLogos) % totalLogos : (currentIndex + MAX_LOGOS) % totalLogos; return { ...prev, [categoryName]: newIndex }; }); }; const truncateDescription = (text: string) => { return text.length > MAX_DESCRIPTION_LENGTH ? `${text.slice(0, MAX_DESCRIPTION_LENGTH)}...` : text; }; const renderResources = (script: any) => { const cpu = script.install_methods[0]?.resources.cpu; const ram = script.install_methods[0]?.resources.ram; const hdd = script.install_methods[0]?.resources.hdd; const resourceParts = []; if (cpu) resourceParts.push( CPU: {cpu}vCPU , ); if (ram) resourceParts.push( RAM: {ram}MB , ); if (hdd) resourceParts.push( HDD: {hdd}GB , ); return resourceParts.length > 0 ? (
{resourceParts.map((part, index) => ( {part} {index < resourceParts.length - 1 && " | "} ))}
) : null; }; return (
{categories.length === 0 && (

No categories available. Please check the API endpoint.

)} {selectedCategoryIndex !== null ? (
{/* Header with Navigation */}

{categories[selectedCategoryIndex].name}

{/* Scripts Grid */}
{currentScripts .sort((a, b) => a.name.localeCompare(b.name)) .map((script) => ( handleScriptClick(script.slug)} >

{script.name}

{script.name

Created at: {script.date_created || "No date available"}

{truncateDescription(script.description || "No description available.")}

{renderResources(script)}
))}
{/* Back to Categories Button */}
) : (
{/* Categories Grid */}

Categories

{categories.reduce((total, category) => total + (category.scripts?.length || 0), 0)} Total scripts

{categories.map((category, index) => ( handleCategoryClick(index)} className="cursor-pointer hover:shadow-lg flex flex-col items-center justify-center py-6 transition-shadow duration-300" >

{category.name}

{category.scripts && category.scripts .slice(logoIndices[category.name] || 0, (logoIndices[category.name] || 0) + MAX_LOGOS) .map((script, i) => (
{script.name { e.stopPropagation(); handleScriptClick(script.slug); }} /> {formattedBadge(script.type)}
))}

{(category as any).description || "No description available."}

))}
)}
); }; export default CategoryView;