import { useState, useEffect, useRef } from "react" import { Pause, Play } from "lucide-react" import { Button } from "@/app/_components/ui/button" import { cn } from "@/app/_lib/utils" import { Slider } from "@/app/_components/ui/slider" import { getMonthName } from "@/app/_utils/common" interface SmoothYearTimelineProps { startYear: number endYear: number onChange?: (year: number, month: number, progress: number) => void className?: string autoPlay?: boolean autoPlaySpeed?: number // Time to progress through one month in ms } export function SmoothYearTimeline({ startYear = 2020, endYear = 2024, onChange, className, autoPlay = true, autoPlaySpeed = 1000, // Speed of month progress }: SmoothYearTimelineProps) { const [currentYear, setCurrentYear] = useState(startYear) const [currentMonth, setCurrentMonth] = useState(1) // Start at January (1) const [progress, setProgress] = useState(0) // Progress within the current month const [isPlaying, setIsPlaying] = useState(autoPlay) const [isDragging, setIsDragging] = useState(false) const animationRef = useRef(null) const lastUpdateTimeRef = useRef(0) // Calculate total months from start to end year const totalMonths = ((endYear - startYear) * 12) + 12 // +12 to include all months of end year const calculateOverallProgress = (): number => { const yearDiff = currentYear - startYear const monthProgress = (yearDiff * 12) + (currentMonth - 1) return ((monthProgress + progress) / (totalMonths - 1)) * 100 } const calculateTimeFromProgress = (overallProgress: number): { year: number; month: number; progress: number } => { const totalProgress = (overallProgress * (totalMonths - 1)) / 100 const monthsFromStart = Math.floor(totalProgress) const year = startYear + Math.floor(monthsFromStart / 12) const month = (monthsFromStart % 12) + 1 // 1-12 for months const monthProgress = totalProgress - Math.floor(totalProgress) return { year: Math.min(year, endYear), month: Math.min(month, 12), progress: monthProgress } } // Calculate the current position for the active marker const calculateMarkerPosition = (): string => { const overallProgress = calculateOverallProgress() return `${overallProgress}%` } const animate = (timestamp: number) => { if (!lastUpdateTimeRef.current) { lastUpdateTimeRef.current = timestamp } if (!isDragging) { const elapsed = timestamp - lastUpdateTimeRef.current const progressIncrement = elapsed / autoPlaySpeed let newProgress = progress + progressIncrement let newMonth = currentMonth let newYear = currentYear if (newProgress >= 1) { newProgress = 0 newMonth = currentMonth + 1 if (newMonth > 12) { newMonth = 1 newYear = currentYear + 1 if (newYear > endYear) { newYear = startYear newMonth = 1 } } setCurrentMonth(newMonth) setCurrentYear(newYear) } setProgress(newProgress) if (onChange) { onChange(newYear, newMonth, newProgress) } lastUpdateTimeRef.current = timestamp } if (isPlaying) { animationRef.current = requestAnimationFrame(animate) } } useEffect(() => { if (isPlaying) { lastUpdateTimeRef.current = 0 animationRef.current = requestAnimationFrame(animate) } else if (animationRef.current) { cancelAnimationFrame(animationRef.current) } return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current) } } }, [isPlaying, currentYear, currentMonth, progress, isDragging]) const handlePlayPause = () => { setIsPlaying(!isPlaying) } const handleSliderChange = (value: number[]) => { const overallProgress = value[0] const { year, month, progress } = calculateTimeFromProgress(overallProgress) setCurrentYear(year) setCurrentMonth(month) setProgress(progress) if (onChange) { onChange(year, month, progress) } } const handleSliderDragStart = () => { setIsDragging(true) } const handleSliderDragEnd = () => { setIsDragging(false) } // Create year markers const yearMarkers = [] for (let year = startYear; year <= endYear; year++) { yearMarkers.push(year) } return (
{/* Current month/year marker that moves with the slider */}
{getMonthName(currentMonth)} {currentYear}
{/* Wrap button and slider in their container */}
{/* Play/Pause button */} {/* Slider */}
{/* Year markers */}
{yearMarkers.map((year, index) => (
{year}
))}
) }