From 3c7e061e515db18c5f2bee3b2688ee264b38926b Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 10 May 2024 21:35:12 +0200 Subject: [PATCH] refactor: improve detection of day after fix: prevent mutation of initial object refactor: download project file Update apps/client/src/features/rundown/event-block/EventBlock.utils.ts Co-authored-by: Alex Christoffer Rasmussen Update apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts Co-authored-by: Alex Christoffer Rasmussen --- .../rundown/event-block/EventBlock.tsx | 8 +-- .../rundown/event-block/EventBlock.utils.ts | 35 +++++++++--- .../rundown/event-block/RundownIndicators.tsx | 5 +- .../__tests__/EventBlock.utils.test.ts | 56 ++++++++++++------- 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/apps/client/src/features/rundown/event-block/EventBlock.tsx b/apps/client/src/features/rundown/event-block/EventBlock.tsx index 0e005b00c..8e3fb9e85 100644 --- a/apps/client/src/features/rundown/event-block/EventBlock.tsx +++ b/apps/client/src/features/rundown/event-block/EventBlock.tsx @@ -242,13 +242,7 @@ export default function EventBlock(props: EventBlockProps) { onContextMenu={onContextMenu} id='event-block' > - +
diff --git a/apps/client/src/features/rundown/event-block/EventBlock.utils.ts b/apps/client/src/features/rundown/event-block/EventBlock.utils.ts index 6213f2f87..86ddce331 100644 --- a/apps/client/src/features/rundown/event-block/EventBlock.utils.ts +++ b/apps/client/src/features/rundown/event-block/EventBlock.utils.ts @@ -10,24 +10,41 @@ export function formatDelay(timeStart: number, delay: number): string | undefine return `New start ${timeTag}`; } +/** + * Utility function checks whether a given event is the day after from its predecessor + * We consider an event to be the day after, if it begins before the start of the previous + * @example day after + * // 09:00 - 10:00 + * // 08:00 - 10:30 <--- day after + * @example same day + * // 09:00 - 10:00 + * // 09:30 - 10:30 <--- same day + */ +function checkIsNextDay(previousStart: number, timeStart: number): boolean { + return timeStart < previousStart; +} + export function formatOverlap( previousStart: MaybeNumber, previousEnd: MaybeNumber, timeStart: number, - timeEnd: number, ): string | undefined { - if (previousEnd === null) return; + const noPreviousElement = previousEnd === null || previousStart === null; + if (noPreviousElement) return; const overlap = previousEnd - timeStart; if (overlap === 0) return; - if (previousStart && timeStart < previousEnd) { - const overlap = timeEnd - previousStart; - if (overlap > 0) { - const overlapString = removeLeadingZero(millisToString(Math.abs(overlap))); - return `Overlap ${overlapString}`; - } - const gap = timeStart + dayInMs - previousEnd; + const previousCrossMidnight = previousStart > previousEnd; + const isNextDay = previousCrossMidnight + ? checkIsNextDay(previousEnd, timeStart) || previousEnd == 0 // exception for when previousEnd is precisely midnight + : checkIsNextDay(previousStart, timeStart); + + const correctedPreviousEnd = previousCrossMidnight ? previousEnd + dayInMs : previousEnd; + + if (isNextDay) { + const gap = dayInMs - correctedPreviousEnd + timeStart; + if (gap === 0) return; const gapString = removeLeadingZero(millisToString(Math.abs(gap))); return `Gap ${gapString} (next day)`; } diff --git a/apps/client/src/features/rundown/event-block/RundownIndicators.tsx b/apps/client/src/features/rundown/event-block/RundownIndicators.tsx index 5f3120cbb..9cfa7afae 100644 --- a/apps/client/src/features/rundown/event-block/RundownIndicators.tsx +++ b/apps/client/src/features/rundown/event-block/RundownIndicators.tsx @@ -6,16 +6,15 @@ import style from './RundownIndicators.module.scss'; interface RundownIndicatorProps { timeStart: number; - timeEnd: number; previousStart: MaybeNumber; previousEnd: MaybeNumber; delay: number; } export default function RundownIndicators(props: RundownIndicatorProps) { - const { timeStart, timeEnd, previousStart, previousEnd, delay } = props; + const { timeStart, previousStart, previousEnd, delay } = props; - const hasOverlap = formatOverlap(previousStart, previousEnd, timeStart, timeEnd); + const hasOverlap = formatOverlap(previousStart, previousEnd, timeStart); const hasDelay = formatDelay(timeStart, delay); return ( diff --git a/apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts b/apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts index ae3ff002e..cc5982646 100644 --- a/apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts +++ b/apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts @@ -1,3 +1,5 @@ +import { MILLIS_PER_HOUR } from 'ontime-utils'; + import { formatDelay, formatOverlap } from '../EventBlock.utils'; describe('formatDelay()', () => { @@ -14,35 +16,47 @@ describe('formatOverlap()', () => { const previousStart = 0; const previousEnd = 60000; // 1 min const timeStart = 30000; // 30 sec - const timeEnd = 90000; // 1:30 min - const result = formatOverlap(previousStart, previousEnd, timeStart, timeEnd); + const result = formatOverlap(previousStart, previousEnd, timeStart); expect(result).toEqual('Overlap 0:30'); }); + it('bug #949 recognises an overlap between two times', () => { + const previousStart = 46800000; // 13:00:00 + const previousEnd = 48600000; // 13:30:00 + const timeStart = 48300000; // 13:25:00 + const result = formatOverlap(previousStart, previousEnd, timeStart); + expect(result).toEqual('Overlap 5:00'); + }); + it('handles events the day after, without overlap', () => { - const previousStart = new Date(0).setUTCHours(11); - const previousEnd = new Date(0).setUTCHours(12); - const timeStart = new Date(0).setUTCHours(6); - const timeEnd = new Date(0).setUTCHours(10); - const result = formatOverlap(previousStart, previousEnd, timeStart, timeEnd); + const previousStart = 11 * MILLIS_PER_HOUR; + const previousEnd = 12 * MILLIS_PER_HOUR; + const timeStart = 6 * MILLIS_PER_HOUR; + const result = formatOverlap(previousStart, previousEnd, timeStart); expect(result).toBe('Gap 18:00:00 (next day)'); }); - it('handles events the day after, with overlap', () => { - const previousStart = new Date(0).setUTCHours(9); - const previousEnd = new Date(0).setUTCHours(10); - const timeStart = new Date(0).setUTCHours(6); - const timeEnd = new Date(0).setUTCHours(11); - const result = formatOverlap(previousStart, previousEnd, timeStart, timeEnd); - expect(result).toBe('Overlap 02:00:00'); - }); - it('handles events the day after, with gap', () => { - const previousStart = new Date(0).setUTCHours(17); - const previousEnd = new Date(0).setUTCHours(23); - const timeStart = new Date(0).setUTCHours(9); - const timeEnd = new Date(0).setUTCHours(11); - const result = formatOverlap(previousStart, previousEnd, timeStart, timeEnd); + const previousStart = 17 * MILLIS_PER_HOUR; + const previousEnd = 23 * MILLIS_PER_HOUR; + const timeStart = 9 * MILLIS_PER_HOUR; + const result = formatOverlap(previousStart, previousEnd, timeStart); expect(result).toBe('Gap 10:00:00 (next day)'); }); + + it('handles events the day after, with previous ending at midnight', () => { + const previousStart = 23 * MILLIS_PER_HOUR; // 23:00:00 + const previousEnd = 0; // 00:00:00 + const timeStart = 1 * MILLIS_PER_HOUR; // 01:00:00 + const result = formatOverlap(previousStart, previousEnd, timeStart); + expect(result).toBe('Gap 01:00:00 (next day)'); + }); + + it('handles events the day after, with previous ending over midnight', () => { + const previousStart = 23 * MILLIS_PER_HOUR; + const previousEnd = 1 * MILLIS_PER_HOUR; + const timeStart = 2 * MILLIS_PER_HOUR; + const result = formatOverlap(previousStart, previousEnd, timeStart); + expect(result).toBe('Gap 01:00:00'); + }); });