'use client'; import { useState, useEffect, useRef } from 'react'; interface TickerActivity { ticketNumber: string; title: string; priority: number; statusLabel: string; companyName: string; } interface TickerProps { activities: TickerActivity[]; speed: number; } export function Ticker({ activities, speed }: TickerProps) { const [isPaused, setIsPaused] = useState(false); const contentRef = useRef(null); const animationRef = useRef(null); const positionRef = useRef(0); const lastTimeRef = useRef(0); // Simple requestAnimationFrame animation that respects speed useEffect(() => { if (!contentRef.current) return; const animate = (timestamp: number) => { if (lastTimeRef.current === 0) { lastTimeRef.current = timestamp; } const deltaTime = timestamp - lastTimeRef.current; lastTimeRef.current = timestamp; if (!isPaused && contentRef.current) { // Move based on speed - higher speed = faster movement // Speed 10 = 20px/s, Speed 60 = 120px/s, Speed 100 = 200px/s const pixelsPerSecond = speed * 2; positionRef.current -= (pixelsPerSecond * deltaTime) / 1000; // Get the width of the first set const contentWidth = contentRef.current.scrollWidth / 2; // Reset when we've scrolled past the first set if (Math.abs(positionRef.current) >= contentWidth) { positionRef.current = 0; } contentRef.current.style.transform = `translateX(${positionRef.current}px)`; } animationRef.current = requestAnimationFrame(animate); }; animationRef.current = requestAnimationFrame(animate); return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, [speed, isPaused]); const getPriorityColor = (priority: number) => { if (priority <= 3) return 'text-red-500'; if (priority <= 5) return 'text-orange-500'; return 'text-blue-500'; }; const getPriorityIcon = (priority: number) => { if (priority <= 3) return '🔴'; if (priority <= 5) return '🟠'; return '🔵'; }; const getStatusColor = (statusLabel: string) => { const status = statusLabel?.toLowerCase() || ''; if (status.includes('new') || status.includes('resource requested') || status.includes('end user note added')) { return 'text-red-500 font-bold'; } if (status.includes('in progress')) { return 'text-green-500 font-bold'; } return 'text-gray-500'; }; if (activities.length === 0) { return (
No recent ticket activity
); } // Limit to 20 items for better performance on low-end hardware const limitedActivities = activities.slice(0, 20); return (
setIsPaused(true)} onMouseLeave={() => setIsPaused(false)} >
{/* Duplicate content for seamless loop */} {[...limitedActivities, ...limitedActivities].map((activity, index) => (
{/* Line 1: Priority - Ticket Number - Company Name */}
{getPriorityIcon(activity.priority)} {activity.ticketNumber} - {activity.companyName}
{/* Line 2: Title - Status */}
{activity.title?.substring(0, 60) || ''} - {activity.statusLabel || 'Unknown'}
))}
); }