fix: handle multiple days

This commit is contained in:
Carlos Valente
2024-08-28 19:00:14 +02:00
committed by Carlos Valente
parent f8ca5b9cef
commit db8ed93d41
5 changed files with 29 additions and 22 deletions
@@ -1,6 +1,6 @@
import { memo } from 'react'; import { memo } from 'react';
import { useViewportSize } from '@mantine/hooks'; import { useViewportSize } from '@mantine/hooks';
import { isOntimeEvent, MaybeNumber, OntimeEvent } from 'ontime-types'; import { isOntimeEvent, isPlayableEvent, MaybeNumber, OntimeRundown } from 'ontime-types';
import { checkIsNextDay, dayInMs, getLastEvent, MILLIS_PER_HOUR } from 'ontime-utils'; import { checkIsNextDay, dayInMs, getLastEvent, MILLIS_PER_HOUR } from 'ontime-utils';
import { useTimelineOverview } from '../../../common/hooks/useSocket'; import { useTimelineOverview } from '../../../common/hooks/useSocket';
@@ -14,7 +14,7 @@ import style from './Timeline.module.scss';
interface TimelineProps { interface TimelineProps {
selectedEventId: string | null; selectedEventId: string | null;
rundown: OntimeEvent[]; rundown: OntimeRundown;
} }
export default memo(Timeline); export default memo(Timeline);
@@ -27,15 +27,14 @@ function Timeline(props: TimelineProps) {
if (plannedStart === null || plannedEnd === null) { if (plannedStart === null || plannedEnd === null) {
return null; return null;
} }
const { lastEvent } = getLastEvent(rundown); const { lastEvent } = getLastEvent(rundown);
const startHour = getStartHour(plannedStart); const startHour = getStartHour(plannedStart);
const endHour = getEndHour(plannedEnd + (lastEvent?.delay ?? 0)); const endHour = getEndHour(plannedEnd + (lastEvent?.delay ?? 0));
let hasTimelinePassedMidnight = false;
let previousEventStartTime: MaybeNumber = null; let previousEventStartTime: MaybeNumber = null;
// we use selectedEventId as a signifier on whether the timeline is live // we use selectedEventId as a signifier on whether the timeline is live
let eventStatus: ProgressStatus = selectedEventId ? 'done' : 'future'; let eventStatus: ProgressStatus = selectedEventId ? 'done' : 'future';
let elapsedDays = 0;
return ( return (
<div className={style.timeline}> <div className={style.timeline}>
@@ -44,7 +43,7 @@ function Timeline(props: TimelineProps) {
<div className={style.timelineEvents}> <div className={style.timelineEvents}>
{rundown.map((event) => { {rundown.map((event) => {
// for now we dont render delays and blocks // for now we dont render delays and blocks
if (!isOntimeEvent(event)) { if (!isOntimeEvent(event) || !isPlayableEvent(event)) {
return null; return null;
} }
@@ -56,17 +55,14 @@ function Timeline(props: TimelineProps) {
eventStatus = 'live'; eventStatus = 'live';
} }
if (!hasTimelinePassedMidnight) { // we only need to check for next day if we have a previous event
// we need to offset the start to account for midnight if (
hasTimelinePassedMidnight = previousEventStartTime !== null && event.timeStart < previousEventStartTime; previousEventStartTime !== null &&
checkIsNextDay(previousEventStartTime, event.timeStart, event.duration)
) {
elapsedDays++;
} }
// TODO: timeline must accumulate normalised time over days const normalisedStart = event.timeStart + elapsedDays * dayInMs;
const isNextDay =
previousEventStartTime !== null
? checkIsNextDay(previousEventStartTime, event.timeStart, event.duration)
: false;
const normalisedStart = hasTimelinePassedMidnight || isNextDay ? event.timeStart + dayInMs : event.timeStart;
previousEventStartTime = normalisedStart;
const { left: elementLeftPosition, width: elementWidth } = getElementPosition( const { left: elementLeftPosition, width: elementWidth } = getElementPosition(
startHour * MILLIS_PER_HOUR, startHour * MILLIS_PER_HOUR,
@@ -76,6 +72,9 @@ function Timeline(props: TimelineProps) {
screenWidth, screenWidth,
); );
// prepare values for next iteration
previousEventStartTime = normalisedStart;
return ( return (
<TimelineEntry <TimelineEntry
key={event.id} key={event.id}
@@ -1,4 +1,4 @@
import { isOntimeEvent, MaybeString, OntimeEvent } from 'ontime-types'; import { isOntimeEvent, MaybeString, OntimeEvent, OntimeRundown } from 'ontime-types';
import { import {
dayInMs, dayInMs,
getEventWithId, getEventWithId,
@@ -87,7 +87,7 @@ export function getStatusLabel(timeToStart: number, status: ProgressStatus): str
return formatDuration(timeToStart); return formatDuration(timeToStart);
} }
export function getScopedRundown(rundown: OntimeEvent[], selectedEventId: MaybeString): OntimeEvent[] { export function getScopedRundown(rundown: OntimeRundown, selectedEventId: MaybeString): OntimeRundown {
if (rundown.length === 0) { if (rundown.length === 0) {
return []; return [];
} }
@@ -106,7 +106,7 @@ export function getScopedRundown(rundown: OntimeEvent[], selectedEventId: MaybeS
} }
if (hideBackstage) { if (hideBackstage) {
scopedRundown = scopedRundown.filter((event) => event.isPublic); scopedRundown = scopedRundown.filter((event) => !isOntimeEvent(event) || event.isPublic);
} }
return scopedRundown; return scopedRundown;
@@ -121,7 +121,7 @@ type UpcomingEvents = {
/** /**
* Returns upcoming events from current: now, next and followedBy * Returns upcoming events from current: now, next and followedBy
*/ */
export function getUpcomingEvents(events: OntimeEvent[], selectedId: MaybeString): UpcomingEvents { export function getUpcomingEvents(events: OntimeRundown, selectedId: MaybeString): UpcomingEvents {
if (events.length === 0) { if (events.length === 0) {
return { now: null, next: null, followedBy: null }; return { now: null, next: null, followedBy: null };
} }
+1 -1
View File
@@ -11,7 +11,7 @@ export function isOntimeEvent(event: MaybeEvent): event is OntimeEvent {
} }
export function isPlayableEvent(event: OntimeEvent): event is PlayableEvent { export function isPlayableEvent(event: OntimeEvent): event is PlayableEvent {
return !event.skip; return !event?.skip;
} }
export function isOntimeDelay(event: MaybeEvent): event is OntimeDelay { export function isOntimeDelay(event: MaybeEvent): event is OntimeDelay {
@@ -57,4 +57,11 @@ describe('checkIsNextDay', () => {
const timeStart = 2 * MILLIS_PER_HOUR; const timeStart = 2 * MILLIS_PER_HOUR;
expect(checkIsNextDay(previousStart, timeStart, previousDuration)).toBeTruthy(); expect(checkIsNextDay(previousStart, timeStart, previousDuration)).toBeTruthy();
}); });
it('should account for normalised start over multiple days', () => {
const previousStart = 90000000; // 25:00:00
const previousDuration = 1 * MILLIS_PER_HOUR;
const timeStart = 0;
expect(checkIsNextDay(previousStart, timeStart, previousDuration)).toBeTruthy();
});
}); });
@@ -24,8 +24,9 @@ export function checkIsNextDay(previousStart: number, timeStart: number, previou
return false; return false;
} }
if (timeStart <= previousStart) { const cappedStart = previousStart % dayInMs;
const normalisedPreviousEnd = previousStart + previousDuration; if (timeStart <= cappedStart) {
const normalisedPreviousEnd = cappedStart + previousDuration;
if (normalisedPreviousEnd === dayInMs) { if (normalisedPreviousEnd === dayInMs) {
return true; return true;
} }