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) => (
+
+ ))}