'use client'; import { useState, useEffect, useCallback } from 'react'; import { useTranslations } from 'next-intl'; import { motion } from 'framer-motion'; import { Database, Server, Store, Code2, Box } from 'lucide-react'; interface SkillItem { name: string; level: number; } interface SkillGroup { category: string; items: SkillItem[]; } // Move iconMap outside component for better performance const iconMap: Record = { 'Python': , 'Server': , 'Google Ads': , 'Meta Ads': , 'Shopware': , 'Shopify': , 'WooCommerce': , 'JTL WAWI': , 'AirFlow': }; const Skills = () => { const t = useTranslations('pages.about.skills'); const [selectedSkill, setSelectedSkill] = useState(null); const [allSkills, setAllSkills] = useState([]); // Memoized event handlers const handleHoverStart = useCallback((skillName: string) => { setSelectedSkill(skillName); }, []); const handleHoverEnd = useCallback(() => { setSelectedSkill(null); }, []); const handleClick = useCallback((skillName: string) => { setSelectedSkill(prev => prev === skillName ? null : skillName); }, []); useEffect(() => { try { const skillGroups = t.raw('skillGroups') as SkillGroup[]; if (Array.isArray(skillGroups)) { const skills = skillGroups.flatMap(group => group.items); setAllSkills(skills); } } catch { setAllSkills([]); } }, [t]); if (allSkills.length === 0) { return null; } return (
{/* Skills Progress Bars */}
{allSkills.map((skill) => ( handleHoverStart(skill.name)} onHoverEnd={handleHoverEnd} >
{skill.name} {selectedSkill === skill.name && ( {skill.level}% Proficiency )}
{skill.level}%
))}
{/* Skills Icons Grid */}
{allSkills.map((skill) => ( handleClick(skill.name)} role="button" aria-pressed={selectedSkill === skill.name} >
{iconMap[skill.name] || }
{skill.name} {selectedSkill === skill.name && ( {skill.level}% )}
))}
); }; export default Skills;