From 3ecf429927069e5ab03bbeafcdeba1368d748375 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:39:49 -0600 Subject: [PATCH] consolidate divs in summary timeline --- .../components/timeline/SummarySegment.tsx | 75 +++----- .../components/timeline/SummaryTimeline.tsx | 173 ++++++++++-------- web/src/types/review.ts | 7 + 3 files changed, 124 insertions(+), 131 deletions(-) diff --git a/web/src/components/timeline/SummarySegment.tsx b/web/src/components/timeline/SummarySegment.tsx index 6903d473c..4945e9b5d 100644 --- a/web/src/components/timeline/SummarySegment.tsx +++ b/web/src/components/timeline/SummarySegment.tsx @@ -1,68 +1,39 @@ -import { useEventSegmentUtils } from "@/hooks/use-event-segment-utils"; -import { ReviewSegment, ReviewSeverity } from "@/types/review"; -import React, { useMemo } from "react"; -// import useTapUtils from "@/hooks/use-tap-utils"; +import { cn } from "@/lib/utils"; +import { ConsolidatedSegmentData } from "@/types/review"; type SummarySegmentProps = { - events: ReviewSegment[]; - segmentTime: number; - segmentDuration: number; - segmentHeight: number; - severityType: ReviewSeverity; + segmentData: ConsolidatedSegmentData; + totalDuration: number; }; export function SummarySegment({ - events, - segmentTime, - segmentDuration, - segmentHeight, - severityType, + segmentData, + totalDuration, }: SummarySegmentProps) { - const { getSeverity, getReviewed, displaySeverityType } = - useEventSegmentUtils(segmentDuration, events, severityType); + const { startTime, endTime, severity, reviewed } = segmentData; - const severity = useMemo( - () => getSeverity(segmentTime, displaySeverityType), - [getSeverity, segmentTime, displaySeverityType], - ); - - const reviewed = useMemo( - () => getReviewed(segmentTime), - [getReviewed, segmentTime], - ); - - const segmentKey = useMemo(() => segmentTime, [segmentTime]); - - const severityColors: { [key: number]: string } = { - 1: reviewed + const severityColors: { [key: string]: string } = { + significant_motion: reviewed ? "bg-severity_significant_motion/50" : "bg-severity_significant_motion", - 2: reviewed ? "bg-severity_detection/50" : "bg-severity_detection", - 3: reviewed ? "bg-severity_alert/50" : "bg-severity_alert", + detection: reviewed ? "bg-severity_detection/50" : "bg-severity_detection", + alert: reviewed ? "bg-severity_alert/50" : "bg-severity_alert", + empty: "bg-transparent", }; + const height = ((endTime - startTime) / totalDuration) * 100; + return ( -
- {severity.map((severityValue: number, index: number) => ( - - {severityValue === displaySeverityType && ( -
-
-
+
+
+
- ))} + >
+
); } diff --git a/web/src/components/timeline/SummaryTimeline.tsx b/web/src/components/timeline/SummaryTimeline.tsx index 7e67b9da6..d17709bdf 100644 --- a/web/src/components/timeline/SummaryTimeline.tsx +++ b/web/src/components/timeline/SummaryTimeline.tsx @@ -1,17 +1,20 @@ -import { - RefObject, - useCallback, - useEffect, - useMemo, +import React, { useRef, useState, + useMemo, + useCallback, + useEffect, } from "react"; import { SummarySegment } from "./SummarySegment"; +import { + ConsolidatedSegmentData, + ReviewSegment, + ReviewSeverity, +} from "@/types/review"; import { useTimelineUtils } from "@/hooks/use-timeline-utils"; -import { ReviewSegment, ReviewSeverity } from "@/types/review"; export type SummaryTimelineProps = { - reviewTimelineRef: RefObject; + reviewTimelineRef: React.RefObject; timelineStart: number; timelineEnd: number; segmentDuration: number; @@ -29,7 +32,6 @@ export function SummaryTimeline({ }: SummaryTimelineProps) { const summaryTimelineRef = useRef(null); const visibleSectionRef = useRef(null); - const [segmentHeight, setSegmentHeight] = useState(0); const [isDragging, setIsDragging] = useState(false); const [scrollStartPosition, setScrollStartPosition] = useState(0); @@ -43,61 +45,89 @@ export function SummaryTimeline({ [timelineEnd, timelineStart, segmentDuration], ); - const { alignStartDateToTimeline } = useTimelineUtils({ - segmentDuration, - timelineDuration: reviewTimelineDuration, - timelineRef: reviewTimelineRef, - }); - - const timelineStartAligned = useMemo( - () => alignStartDateToTimeline(timelineStart) + 2 * segmentDuration, - [timelineStart, alignStartDateToTimeline, segmentDuration], + const { alignStartDateToTimeline, alignEndDateToTimeline } = useTimelineUtils( + { + segmentDuration, + timelineDuration: reviewTimelineDuration, + timelineRef: reviewTimelineRef, + }, ); - // Generate segments for the timeline - const generateSegments = useCallback(() => { - const segmentCount = Math.ceil(reviewTimelineDuration / segmentDuration); + const consolidatedSegments = useMemo(() => { + const filteredEvents = events.filter( + (event) => event.severity === severityType, + ); - if (segmentHeight) { - return Array.from({ length: segmentCount }, (_, index) => { - const segmentTime = timelineStartAligned - index * segmentDuration; + const sortedEvents = filteredEvents.sort( + (a, b) => a.start_time - b.start_time, + ); - return ( - - ); + const consolidated: ConsolidatedSegmentData[] = []; + + let currentTime = alignEndDateToTimeline(timelineEnd); + const timelineStartAligned = alignStartDateToTimeline(timelineStart); + + sortedEvents.forEach((event) => { + const alignedStartTime = Math.max( + alignStartDateToTimeline(event.start_time), + currentTime, + ); + const alignedEndTime = Math.min( + event.end_time + ? alignEndDateToTimeline(event.end_time) + : alignedStartTime + segmentDuration, + timelineStartAligned, + ); + + if (alignedStartTime < alignedEndTime) { + if (alignedStartTime > currentTime) { + consolidated.push({ + startTime: currentTime, + endTime: alignedStartTime, + severity: "empty", + reviewed: false, + }); + } + + consolidated.push({ + startTime: alignedStartTime, + endTime: alignedEndTime, + severity: event.severity, + reviewed: event.has_been_reviewed, + }); + + currentTime = alignedEndTime; + } + }); + + if (currentTime < timelineStartAligned) { + consolidated.push({ + startTime: currentTime, + endTime: timelineStartAligned, + severity: "empty", + reviewed: false, }); } - }, [ - segmentDuration, - timelineStartAligned, - events, - reviewTimelineDuration, - segmentHeight, - severityType, - ]); - const segments = useMemo( - () => generateSegments(), - // we know that these deps are correct - // eslint-disable-next-line react-hooks/exhaustive-deps - [ - segmentDuration, - segmentHeight, - timelineStartAligned, - events, - reviewTimelineDuration, - segmentHeight, - generateSegments, - severityType, - ], - ); + return consolidated.length > 0 + ? consolidated + : [ + { + startTime: alignEndDateToTimeline(timelineEnd), + endTime: timelineStartAligned, + severity: "empty" as const, + reviewed: false, + }, + ]; + }, [ + events, + severityType, + timelineStart, + timelineEnd, + alignStartDateToTimeline, + alignEndDateToTimeline, + segmentDuration, + ]); const setVisibleSectionStyles = useCallback(() => { if ( @@ -137,15 +167,6 @@ export function SummaryTimeline({ observer.current = new ResizeObserver(() => { setVisibleSectionStyles(); - if (summaryTimelineRef.current) { - const { clientHeight: summaryTimelineVisibleHeight } = - summaryTimelineRef.current; - - setSegmentHeight( - summaryTimelineVisibleHeight / - (reviewTimelineDuration / segmentDuration), - ); - } }); observer.current.observe(content); @@ -163,18 +184,6 @@ export function SummaryTimeline({ segmentDuration, ]); - useEffect(() => { - if (summaryTimelineRef.current) { - const { clientHeight: summaryTimelineVisibleHeight } = - summaryTimelineRef.current; - - setSegmentHeight( - summaryTimelineVisibleHeight / - (reviewTimelineDuration / segmentDuration), - ); - } - }, [reviewTimelineDuration, summaryTimelineRef, segmentDuration]); - const timelineClick = useCallback( ( e: React.MouseEvent | React.TouchEvent, @@ -344,11 +353,17 @@ export function SummaryTimeline({ >
- {segments} + {consolidatedSegments.map((segment, index) => ( + + ))}