import React, { useState, useEffect, useRef, useCallback } from 'react'; import { CourseRow } from './CourseRow'; import { Section, Course } from '../types'; import { getCourses, getLearningPaths, PublicLearningPath } from '../services/db'; import { useAuth } from '../context/AuthContext'; import { Loader2, ChevronLeft, ChevronRight } from 'lucide-react'; import { LearningPathRow } from './LearningPathRow'; interface CourseGridProps { onCourseSelect?: (course: Course) => void; selectedCategoryFilter?: string; } export const CourseGrid: React.FC = ({ onCourseSelect, selectedCategoryFilter }) => { const [courses, setCourses] = useState([]); const [paths, setPaths] = useState([]); const [loading, setLoading] = useState(true); const [activeCategory, setActiveCategory] = useState('all'); const { user } = useAuth(); // Slider State & Refs for Categories const categoryScrollRef = useRef(null); const isMouseDownRef = useRef(false); const startXRef = useRef(0); const scrollLeftRef = useRef(0); const draggedDistanceRef = useRef(0); const [isDraggingCategory, setIsDraggingCategory] = useState(false); const [canScrollCatLeft, setCanScrollCatLeft] = useState(false); const [canScrollCatRight, setCanScrollCatRight] = useState(false); const checkCategoryBoundaries = useCallback(() => { if (!categoryScrollRef.current) return; const { scrollLeft, scrollWidth, clientWidth } = categoryScrollRef.current; setCanScrollCatLeft(scrollLeft > 10); setCanScrollCatRight(scrollLeft + clientWidth < scrollWidth - 10); }, []); useEffect(() => { const loadData = async () => { try { const [loadedCourses, loadedPaths] = await Promise.all([getCourses(), getLearningPaths()]); setCourses(loadedCourses); setPaths(loadedPaths); } finally { setLoading(false); } }; loadData(); }, [user]); useEffect(() => { checkCategoryBoundaries(); window.addEventListener('resize', checkCategoryBoundaries); return () => window.removeEventListener('resize', checkCategoryBoundaries); }, [checkCategoryBoundaries, courses]); const handleCategoryScroll = (direction: 'left' | 'right') => { if (!categoryScrollRef.current) return; const scrollAmount = 300; categoryScrollRef.current.scrollBy({ left: direction === 'left' ? -scrollAmount : scrollAmount, behavior: 'smooth' }); }; const handleCatMouseDown = (e: React.MouseEvent) => { if (!categoryScrollRef.current) return; isMouseDownRef.current = true; startXRef.current = e.pageX - categoryScrollRef.current.offsetLeft; scrollLeftRef.current = categoryScrollRef.current.scrollLeft; draggedDistanceRef.current = 0; setIsDraggingCategory(false); }; const handleCatMouseMove = (e: React.MouseEvent) => { if (!isMouseDownRef.current || !categoryScrollRef.current) return; e.preventDefault(); const x = e.pageX - categoryScrollRef.current.offsetLeft; const walk = (x - startXRef.current) * 1.4; draggedDistanceRef.current = Math.abs(walk); if (draggedDistanceRef.current > 5) { setIsDraggingCategory(true); categoryScrollRef.current.scrollLeft = scrollLeftRef.current - walk; } }; const handleCatMouseUp = () => { isMouseDownRef.current = false; setTimeout(() => { setIsDraggingCategory(false); draggedDistanceRef.current = 0; }, 50); }; const handleCategoryClick = (cat: string) => { if (draggedDistanceRef.current < 8) { setActiveCategory(cat); } }; const categories = Array.from(new Set(courses.map((course) => course.category))) .sort((left, right) => left.localeCompare(right, 'pt-BR')); if (loading) { return (
); } if (courses.length === 0) { return (

Cursos em breve

Ainda não há cursos publicados. Cadastre o primeiro curso no Painel do Instrutor.

); } // Filter courses if a specific category is active const filteredCourses = activeCategory === 'all' ? courses : courses.filter(c => c.category === activeCategory); // Group into curated sections for Netflix/Apple TV style layout const sections: Section[] = [ { title: activeCategory === 'all' ? 'Cursos em Destaque' : activeCategory, variant: 'landscape', courses: filteredCourses }, { title: 'Com Materiais & Planilhas para Download', variant: 'landscape', courses: courses.filter(c => (c.attachments && c.attachments.length > 0) || c.lessons.some(l => l.attachments && l.attachments.length > 0)) }, ]; return (
{/* Category Pills Slider Container */}
{/* Scroll Button Left */} {canScrollCatLeft && ( )} {/* Left Gradient Fade */} {canScrollCatLeft && (
)} {/* Scrollable Category Track */}
{categories.map(cat => { const count = courses.filter(c => c.category === cat).length; return ( ); })}
{/* Right Gradient Fade */} {canScrollCatRight && (
)} {/* Scroll Button Right */} {canScrollCatRight && ( )}
{/* Sections Rows */} {sections.map((section, index) => ( section.courses.length > 0 && ( ) ))} {activeCategory === 'all' && paths.length > 0 && }
); };