import { useData } from '../context/DataContext'; import { useRef, useState, useMemo } from 'react'; import { ArrowRight, ChevronLeft, ChevronRight, ChevronDown, User, Tag, Calendar, ExternalLink, Filter, Search, X } from 'lucide-react'; import { type Project } from '../data'; import ProjectModal from './ProjectModal'; import { useLang } from '../context/LanguageContext'; const INITIAL_COUNT = 6; const LOAD_MORE_COUNT = 3; export default function ProjectCarousel() { const { t } = useLang(); const { projects, loading, error, refetch } = useData(); const scrollRef = useRef(null); const [selectedProject, setSelectedProject] = useState(null); const [visibleCount, setVisibleCount] = useState(INITIAL_COUNT); // Filter state const [searchQuery, setSearchQuery] = useState(''); const [filterCategory, setFilterCategory] = useState(''); const [filterYear, setFilterYear] = useState(''); const categories = useMemo( () => [...new Set(projects.flatMap((p) => p.category))].sort(), [projects] ); const years = useMemo( () => [...new Set(projects.map((p) => p.year))].sort((a: number, b: number) => b - a), [projects] ); // Filter + search logic const filtered = useMemo(() => { const q = searchQuery.toLowerCase().trim(); return projects.filter((p) => { const matchSearch = !q || p.title.toLowerCase().includes(q) || p.studentName.toLowerCase().includes(q) || p.category.join(' ').toLowerCase().includes(q) || p.description.toLowerCase().includes(q); const matchCategory = !filterCategory || p.category.includes(filterCategory); const matchYear = !filterYear || String(p.year) === filterYear; return matchSearch && matchCategory && matchYear; }); }, [searchQuery, filterCategory, filterYear, projects]); const visibleProjects = filtered.slice(0, visibleCount); const hasMore = visibleCount < filtered.length; const isFiltered = searchQuery || filterCategory || filterYear; const resetFilters = () => { setSearchQuery(''); setFilterCategory(''); setFilterYear(''); setVisibleCount(INITIAL_COUNT); }; const handleFilterChange = (setter: (v: string) => void) => (v: string) => { setter(v); setVisibleCount(INITIAL_COUNT); }; const handleLoadMore = () => setVisibleCount((prev) => prev + LOAD_MORE_COUNT); const handleShowLess = () => { setVisibleCount(INITIAL_COUNT); document.getElementById('portofolio')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); }; const scroll = (direction: 'left' | 'right') => { const container = scrollRef.current; if (!container) return; const cardWidth = container.firstElementChild ? (container.firstElementChild as HTMLElement).offsetWidth + 24 : 400; container.scrollBy({ left: direction === 'right' ? cardWidth : -cardWidth, behavior: 'smooth' }); }; return ( <> {/* Project Modal */} setSelectedProject(null)} />
{/* Header row */}

{t.project.sectionTitle}

{t.project.sectionDesc}

{/* Scroll control buttons */}
{/* Filter + Search Section */}
{/* Row 1: Label + Reset */}
{t.project.filterTitle}
{isFiltered && ( )}
{/* Row 2: Search bar */}
{ setSearchQuery(e.target.value); setVisibleCount(INITIAL_COUNT); }} placeholder={t.project.searchPlaceholder} className="w-full bg-slate-50 text-slate-700 text-sm rounded py-2 pl-9 pr-4 border border-slate-200 focus:outline-none focus:ring-2 focus:ring-primary-gold" /> {searchQuery && ( )}
{/* Row 3: Dropdowns */}
{/* Category Filter */}
{/* Year Filter */}
{/* Results count */} {isFiltered && (

{t.project.showing}{' '} {filtered.length}{' '} {t.project.matching}

)} {/* Cards */} {loading ? (
{[1, 2, 3].map((n) => (
))}
) : error ? (

Gagal memuat portofolio

{error}

) : visibleProjects.length === 0 ? (

{t.project.noData}

{t.project.noDataSub}

) : ( <> {/* Scrollable cards */}
{visibleProjects.map((project) => (
{/* Image */}
{project.title} { (e.target as HTMLImageElement).src = 'https://placehold.co/800x600/003150/FDB813?text=Informatika+UNTAN'; }} /> {/* Tag at top-left, raised like achievements, max 2 tags then (..) */} {project.category && project.category.length > 0 && (
{project.category.slice(0, 2).map((cat, i) => ( {cat} ))} {project.category.length > 2 && ( (..) )}
)} {/* Title block — inline background follows text width */}

{project.title}

{/* Body */}
{/* Meta row */}
{project.studentName && ( {project.studentName} )} {project.year && ( {project.year} )}

{project.description}

{/* Actions */}
{project.link && ( {t.project.visitLink} )}
))}
{/* Scroll hint */}

{t.project.scrollHint}

{/* Load More / Show Less */}
{hasMore && ( )} {!hasMore && visibleProjects.length > 0 && filtered.length > INITIAL_COUNT && (

{t.project.showing} {filtered.length} {t.project.allShown}

)} {visibleCount > INITIAL_COUNT && visibleProjects.length > 0 && ( )}
)}
); }