import useDraggableHandler from "@/hooks/use-handle-dragging"; import { useEffect, useCallback, useMemo, useRef, useState, RefObject, } from "react"; import EventSegment from "./EventSegment"; import { useEventUtils } from "@/hooks/use-event-utils"; import { ReviewSegment, ReviewSeverity } from "@/types/review"; export type EventReviewTimelineProps = { segmentDuration: number; timestampSpread: number; timelineStart: number; timelineEnd: number; showHandlebar?: boolean; handlebarTime?: number; setHandlebarTime?: React.Dispatch>; showMinimap?: boolean; minimapStartTime?: number; minimapEndTime?: number; events: ReviewSegment[]; severityType: ReviewSeverity; contentRef: RefObject; onHandlebarDraggingChange?: (isDragging: boolean) => void; }; export function EventReviewTimeline({ segmentDuration, timestampSpread, timelineStart, timelineEnd, showHandlebar = false, handlebarTime, setHandlebarTime, showMinimap = false, minimapStartTime, minimapEndTime, events, severityType, contentRef, onHandlebarDraggingChange, }: EventReviewTimelineProps) { const [isDragging, setIsDragging] = useState(false); const scrollTimeRef = useRef(null); const timelineRef = useRef(null); const handlebarTimeRef = useRef(null); const observer = useRef(null); const timelineDuration = useMemo( () => timelineStart - timelineEnd, [timelineEnd, timelineStart], ); const { alignStartDateToTimeline, alignEndDateToTimeline } = useEventUtils( events, segmentDuration, ); const { handleMouseDown, handleMouseUp, handleMouseMove } = useDraggableHandler({ contentRef, timelineRef, scrollTimeRef, alignStartDateToTimeline, alignEndDateToTimeline, segmentDuration, showHandlebar, handlebarTime, setHandlebarTime, timelineDuration, timelineStart, isDragging, setIsDragging, handlebarTimeRef, }); function handleResize() { // TODO: handle screen resize for mobile // eslint-disable-next-line no-empty if (timelineRef.current && contentRef.current) { } } useEffect(() => { if (contentRef.current) { const content = contentRef.current; observer.current = new ResizeObserver(() => { handleResize(); }); observer.current.observe(content); return () => { observer.current?.unobserve(content); }; } // should only be calculated at beginning // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Generate segments for the timeline const generateSegments = useCallback(() => { const segmentCount = timelineDuration / segmentDuration; const segmentAlignedTime = alignStartDateToTimeline(timelineStart); return Array.from({ length: segmentCount }, (_, index) => { const segmentTime = segmentAlignedTime - index * segmentDuration; return ( ); }); // we know that these deps are correct // eslint-disable-next-line react-hooks/exhaustive-deps }, [ segmentDuration, timestampSpread, timelineStart, timelineDuration, showMinimap, minimapStartTime, minimapEndTime, events, ]); const segments = useMemo( () => generateSegments(), // we know that these deps are correct // eslint-disable-next-line react-hooks/exhaustive-deps [ segmentDuration, timestampSpread, timelineStart, timelineDuration, showMinimap, minimapStartTime, minimapEndTime, events, ], ); useEffect(() => { if (onHandlebarDraggingChange) { onHandlebarDraggingChange(isDragging); } }, [isDragging, onHandlebarDraggingChange]); return (
{segments}
{showHandlebar && (
)}
); } export default EventReviewTimeline;