lint: fixes from lint and updates to typescript linting

This commit is contained in:
JohnMark Sill
2022-02-18 17:14:16 -06:00
parent 3f11100e7a
commit c3b813e821
13 changed files with 872 additions and 156 deletions
+5 -7
View File
@@ -2,7 +2,7 @@ import { h } from 'preact';
interface BubbleButtonProps {
variant?: 'primary' | 'secondary';
children?: JSX.Element;
children?: preact.JSX.Element;
disabled?: boolean;
className?: string;
onClick?: () => void;
@@ -22,12 +22,10 @@ export const BubbleButton = ({
if (disabled) {
computedClass += ' text-gray-200 dark:text-gray-200';
} else {
if (variant === 'primary') {
computedClass += ` ${PRIMARY_CLASS}`;
} else if (variant === 'secondary') {
computedClass += ` ${SECONDARY_CLASS}`;
}
} else if (variant === 'primary') {
computedClass += ` ${PRIMARY_CLASS}`;
} else if (variant === 'secondary') {
computedClass += ` ${SECONDARY_CLASS}`;
}
const onClickHandler = () => {
@@ -1,6 +1,7 @@
import { h } from 'preact';
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { useApiHost } from '../../api';
import { isNullOrUndefined } from '../../utils/objectUtils';
interface OnTimeUpdateEvent {
timestamp: number;
@@ -17,13 +18,11 @@ interface HistoryVideoProps {
id: string;
isPlaying: boolean;
currentTime: number;
onTimeUpdate: (event: OnTimeUpdateEvent) => void;
onTimeUpdate?: (event: OnTimeUpdateEvent) => void;
onPause: () => void;
onPlay: () => void;
}
const isNullOrUndefined = (object: any): boolean => object === null || object === undefined;
export const HistoryVideo = ({
id,
isPlaying: videoIsPlaying,
@@ -47,7 +46,7 @@ export const HistoryVideo = ({
setVideoHeight(videoHeight);
}
}
}, [videoRef.current]);
}, [videoRef]);
useEffect(() => {
initializeVideoContainerHeight();
@@ -56,6 +55,10 @@ export const HistoryVideo = ({
useEffect(() => {
const idExists = !isNullOrUndefined(id);
if (idExists) {
if (videoRef.current && !videoRef.current.paused) {
videoRef.current = undefined;
}
setVideoProperties({
posterUrl: `${apiHost}/api/events/${id}/snapshot.jpg`,
videoUrl: `${apiHost}/vod/event/${id}/index.m3u8`,
@@ -64,28 +67,15 @@ export const HistoryVideo = ({
} else {
setVideoProperties(undefined);
}
}, [id, videoHeight]);
}, [id, videoHeight, videoRef, apiHost]);
useEffect(() => {
const playVideo = (video: HTMLMediaElement) => {
console.debug('playVideo: attempt playback');
video
.play()
.then(() => {
console.debug('playVideo: video started');
})
.catch((e) => {
console.error('Fail', { e });
});
};
const playVideo = (video: HTMLMediaElement) => video.play();
const attemptPlayVideo = (video: HTMLMediaElement) => {
const videoHasNotLoaded = video.readyState <= 1;
console.debug('playVideo', { videoHasNotLoaded });
if (videoHasNotLoaded) {
console.debug('playVideo: attempt to load video');
video.oncanplay = () => {
console.debug('onLoad: video loaded');
playVideo(video);
};
video.load();
@@ -97,7 +87,6 @@ export const HistoryVideo = ({
const video = videoRef.current;
const videoExists = !isNullOrUndefined(video);
if (videoExists) {
console.log('check should start', { videoIsPlaying });
if (videoIsPlaying) {
attemptPlayVideo(video);
} else {
@@ -122,19 +111,22 @@ export const HistoryVideo = ({
isPlaying: videoIsPlaying,
timestamp: target.currentTime,
};
onTimeUpdate(timeUpdateEvent);
onTimeUpdate && onTimeUpdate(timeUpdateEvent);
},
[videoIsPlaying]
[videoIsPlaying, onTimeUpdate]
);
const videoPropertiesIsUndefined = isNullOrUndefined(videoProperties);
if (videoPropertiesIsUndefined) {
return <div style={{ height: `${videoHeight}px`, width: '100%' }}></div>;
return <div style={{ height: `${videoHeight}px`, width: '100%' }} />;
}
const { posterUrl, videoUrl, height } = videoProperties;
return (
<video
ref={videoRef}
key={posterUrl}
onTimeUpdate={onTimeUpdateHandler}
onPause={onPause}
onPlay={onPlay}
@@ -1,5 +1,5 @@
import { Fragment, h } from 'preact';
import { useEffect, useState } from 'preact/hooks';
import { useCallback, useEffect, useState } from 'preact/hooks';
import { useEvents } from '../../api';
import { useSearchString } from '../../hooks/useSearchString';
import { getNowYesterdayInLong } from '../../utils/dateUtil';
@@ -25,18 +25,19 @@ export default function HistoryViewer({ camera }) {
}
}, [events]);
const onTimeUpdateHandler = ({ timestamp, isPlaying }) => {};
const handleTimelineChange = useCallback(
(event: TimelineChangeEvent) => {
if (event.seekComplete) {
setCurrentEvent(event.timelineEvent);
const handleTimelineChange = (event: TimelineChangeEvent) => {
if (event.seekComplete) {
setCurrentEvent(event.timelineEvent);
if (isPlaying && event.timelineEvent) {
const eventTime = (event.markerTime.getTime() - event.timelineEvent.startTime.getTime()) / 1000;
setCurrentTime(eventTime);
if (isPlaying && event.timelineEvent) {
const eventTime = (event.markerTime.getTime() - event.timelineEvent.startTime.getTime()) / 1000;
setCurrentTime(eventTime);
}
}
}
};
},
[isPlaying]
);
const onPlayHandler = () => {
setIsPlaying(true);
@@ -47,7 +48,6 @@ export default function HistoryViewer({ camera }) {
};
const onPlayPauseHandler = (isPlaying: boolean) => {
console.debug('onPlayPauseHandler: setting isPlaying', { isPlaying });
setIsPlaying(isPlaying);
};
@@ -61,7 +61,6 @@ export default function HistoryViewer({ camera }) {
id={currentEvent ? currentEvent.id : undefined}
isPlaying={isPlaying}
currentTime={currentTime}
onTimeUpdate={onTimeUpdateHandler}
onPlay={onPlayHandler}
onPause={onPausedHandler}
/>
+1 -1
View File
@@ -9,7 +9,7 @@ export function LiveChip({ className }) {
class='animate-ping absolute inline-flex h-full w-full rounded-full opacity-75'
style={{ backgroundColor: 'rgb(74 222 128)' }}
/>
<span class='relative inline-flex rounded-full h-3 w-3' style={{ backgroundColor: 'rgb(74 222 128)' }}/>
<span class='relative inline-flex rounded-full h-3 w-3' style={{ backgroundColor: 'rgb(74 222 128)' }} />
</span>
</div>
<span>Live</span>
+44 -102
View File
@@ -1,6 +1,7 @@
import { Fragment, h } from 'preact';
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
import { longToDate } from '../../utils/dateUtil';
import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks';
import { getTimelineEventBlocksFromTimelineEvents } from '../../utils/Timeline/timelineEventUtils';
import { ScrollPermission } from './ScrollPermission';
import { TimelineBlocks } from './TimelineBlocks';
import { TimelineChangeEvent } from './TimelineChangeEvent';
import { DisabledControls, TimelineControls } from './TimelineControls';
@@ -11,7 +12,7 @@ interface TimelineProps {
events: TimelineEvent[];
isPlaying: boolean;
onChange: (event: TimelineChangeEvent) => void;
onPlayPause: (isPlaying: boolean) => void;
onPlayPause?: (isPlaying: boolean) => void;
}
export default function Timeline({ events, isPlaying, onChange, onPlayPause }: TimelineProps) {
@@ -26,12 +27,36 @@ export default function Timeline({ events, isPlaying, onChange, onPlayPause }: T
const [timelineOffset, setTimelineOffset] = useState<number | undefined>(undefined);
const [markerTime, setMarkerTime] = useState<Date | undefined>(undefined);
const [currentEvent, setCurrentEvent] = useState<TimelineEventBlock | undefined>(undefined);
const [scrollTimeout, setScrollTimeout] = useState<any | undefined>(undefined);
const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | undefined>(undefined);
const [scrollPermission, setScrollPermission] = useState<ScrollPermission>({
allowed: true,
resetAfterSeeked: false,
});
const scrollToPosition = useCallback(
(positionX: number) => {
if (timelineContainerRef.current) {
const permission: ScrollPermission = {
allowed: true,
resetAfterSeeked: true,
};
setScrollPermission(permission);
timelineContainerRef.current.scroll({
left: positionX,
behavior: 'smooth',
});
}
},
[timelineContainerRef]
);
const scrollToEvent = useCallback(
(event, offset = 0) => {
scrollToPosition(event.positionX + offset - timelineOffset);
},
[timelineOffset, scrollToPosition]
);
useEffect(() => {
if (timeline.length > 0 && currentEvent) {
const currentIndex = currentEvent.index;
@@ -57,86 +82,18 @@ export default function Timeline({ events, isPlaying, onChange, onPlayPause }: T
}
}, [timeline, currentEvent]);
const checkEventForOverlap = (firstEvent: TimelineEvent, secondEvent: TimelineEvent) => {
if (secondEvent.startTime < firstEvent.endTime && secondEvent.startTime > firstEvent.startTime) {
return true;
}
return false;
};
const determineOffset = (currentEvent: TimelineEventBlock, previousEvents: TimelineEventBlock[]): number => {
const OFFSET_DISTANCE_IN_PIXELS = 10;
const previousIndex = previousEvents.length - 1;
const previousEvent = previousEvents[previousIndex];
if (previousEvent) {
const isOverlap = checkEventForOverlap(previousEvent, currentEvent);
if (isOverlap) {
return OFFSET_DISTANCE_IN_PIXELS + determineOffset(currentEvent, previousEvents.slice(0, previousIndex));
}
}
return 0;
};
const buildTimelineView = (events: TimelineEvent[]): TimelineEventBlock[] => {
const firstEvent = events[0];
const firstEventTime = longToDate(firstEvent.start_time);
return events
.map((e, index) => {
const startTime = longToDate(e.start_time);
const endTime = e.end_time ? longToDate(e.end_time) : new Date();
const seconds = Math.round(Math.abs(endTime.getTime() - startTime.getTime()) / 1000);
const positionX = Math.round(Math.abs(startTime.getTime() - firstEventTime.getTime()) / 1000 + timelineOffset);
return {
...e,
startTime,
endTime,
width: seconds,
positionX,
index,
} as TimelineEventBlock;
})
.reduce((rowMap, current) => {
for (let i = 0; i < rowMap.length; i++) {
const row = rowMap[i] ?? [];
const lastItem = row[row.length - 1];
if (lastItem) {
const isOverlap = checkEventForOverlap(lastItem, current);
if (isOverlap) {
continue;
}
}
rowMap[i] = [...row, current];
return rowMap;
}
rowMap.push([current]);
return rowMap;
}, [] as TimelineEventBlock[][])
.flatMap((rows, rowPosition) => {
rows.forEach((eventBlock) => {
const OFFSET_DISTANCE_IN_PIXELS = 10;
eventBlock.yOffset = OFFSET_DISTANCE_IN_PIXELS * rowPosition;
});
return rows;
})
.sort((a, b) => a.startTime.getTime() - b.startTime.getTime());
};
useEffect(() => {
if (events && events.length > 0 && timelineOffset) {
const timelineEvents = buildTimelineView(events);
const timelineEvents = getTimelineEventBlocksFromTimelineEvents(events, timelineOffset);
const lastEventIndex = timelineEvents.length - 1;
const recentEvent = timelineEvents[lastEventIndex];
setTimeline(timelineEvents);
setMarkerTime(recentEvent.startTime);
setCurrentEvent(recentEvent);
onChange({
timelineEvent: recentEvent,
markerTime: recentEvent.startTime,
seekComplete: true,
});
scrollToEvent(recentEvent);
}
}, [events, timelineOffset]);
}, [events, timelineOffset, scrollToEvent]);
useEffect(() => {
const timelineIsLoaded = timeline.length > 0;
@@ -144,7 +101,7 @@ export default function Timeline({ events, isPlaying, onChange, onPlayPause }: T
const lastEvent = timeline[timeline.length - 1];
scrollToEvent(lastEvent);
}
}, [timeline]);
}, [timeline, scrollToEvent]);
const checkMarkerForEvent = (markerTime: Date) => {
const adjustedMarkerTime = new Date(markerTime);
@@ -197,32 +154,14 @@ export default function Timeline({ events, isPlaying, onChange, onPlayPause }: T
}
};
const scrollToPosition = (positionX: number) => {
if (timelineContainerRef.current) {
const permission: ScrollPermission = {
allowed: true,
resetAfterSeeked: true,
};
setScrollPermission(permission);
timelineContainerRef.current.scroll({
left: positionX,
behavior: 'smooth',
});
}
};
const scrollToEvent = (event, offset = 0) => {
scrollToPosition(event.positionX + offset - timelineOffset);
};
const getCurrentMarkerTime = () => {
const getCurrentMarkerTime = useCallback(() => {
if (timelineContainerRef.current && timeline.length > 0) {
const scrollPosition = timelineContainerRef.current.scrollLeft;
const firstTimelineEvent = timeline[0] as TimelineEventBlock;
const firstTimelineEventStartTime = firstTimelineEvent.startTime.getTime();
return new Date(firstTimelineEventStartTime + scrollPosition * 1000);
}
};
}, [timeline, timelineContainerRef]);
useEffect(() => {
if (timelineContainerRef) {
@@ -232,10 +171,13 @@ export default function Timeline({ events, isPlaying, onChange, onPlayPause }: T
}
}, [timelineContainerRef]);
const handleViewEvent = (event: TimelineEventBlock) => {
scrollToEvent(event);
setMarkerTime(getCurrentMarkerTime());
};
const handleViewEvent = useCallback(
(event: TimelineEventBlock) => {
scrollToEvent(event);
setMarkerTime(getCurrentMarkerTime());
},
[scrollToEvent, getCurrentMarkerTime]
);
const onPlayPauseHandler = (isPlaying: boolean) => {
onPlayPause(isPlaying);
@@ -260,7 +202,7 @@ export default function Timeline({ events, isPlaying, onChange, onPlayPause }: T
if (timelineOffset && timeline.length > 0) {
return <TimelineBlocks timeline={timeline} firstBlockOffset={timelineOffset} onEventClick={handleViewEvent} />;
}
}, [timeline, timelineOffset]);
}, [timeline, timelineOffset, handleViewEvent]);
return (
<Fragment>
@@ -279,7 +221,7 @@ export default function Timeline({ events, isPlaying, onChange, onPlayPause }: T
left: 'calc(100% / 2)',
borderRight: '2px solid rgba(252, 211, 77)',
}}
></div>
/>
</div>
</div>
<div ref={timelineContainerRef} onScroll={onTimelineScrollHandler} className='overflow-x-auto hide-scroll'>
@@ -9,7 +9,7 @@ interface TimelineBlockViewProps {
}
export const TimelineBlockView = ({ block, onClick }: TimelineBlockViewProps) => {
const onClickHandler = useCallback(() => onClick(block), [block]);
const onClickHandler = useCallback(() => onClick(block), [block, onClick]);
return (
<div
key={block.id}
@@ -20,6 +20,6 @@ export const TimelineBlockView = ({ block, onClick }: TimelineBlockViewProps) =>
left: `${block.positionX}px`,
width: `${block.width}px`,
}}
></div>
/>
);
};
+1 -1
View File
@@ -6,7 +6,7 @@ import { useConfig } from '../api';
import { Tabs, TextTab } from '../components/Tabs';
import { LiveChip } from '../components/LiveChip';
import { DebugCamera } from '../components/DebugCamera';
import { HistoryViewer } from '../components/HistoryViewer'
import HistoryViewer from '../components/HistoryViewer/HistoryViewer.tsx';
export default function Camera({ camera }) {
const { data: config } = useConfig();