import { Day } from 'ontime-types'; import { CSSProperties, RefObject } from 'react'; import { useExpectedStartData, useTimer } from '../../common/hooks/useSocket'; import { getProgress } from '../../common/utils/getProgress'; import { alpha, cx } from '../../common/utils/styleUtils'; import { formatDuration, formatTime, getExpectedTimesFromExtendedEvent } from '../../common/utils/time'; import { useTranslation } from '../../translation/TranslationProvider'; import { getStatusLabel } from './timeline.utils'; import style from './Timeline.module.scss'; export type ProgressStatus = 'done' | 'live' | 'future'; interface TimelineEntryProps { colour: string; delay: number; duration: number; hasLink: boolean; left: number; status: ProgressStatus; start: number; dayOffset: Day; totalGap: number; isLinkedToLoaded: boolean; title: string; width: number; cue: string; ref?: RefObject; } const formatOptions = { format12: 'h:mm a', format24: 'HH:mm', }; export function TimelineEntry({ colour, delay, duration, hasLink, left, status, start, dayOffset, totalGap, isLinkedToLoaded, title, width, cue, ref, }: TimelineEntryProps) { const formattedStartTime = formatTime(start, formatOptions); const formattedDuration = formatDuration(duration); const delayedStart = start + delay; const hasDelay = delay > 0; const lighterColour = alpha(colour, 0.7); const showTitle = width > 20; const smallArea = width < 40; return (
{status === 'live' ? :
}
{formattedStartTime}
{hasDelay &&
{formatTime(delayedStart, formatOptions)}
} {smallArea && ( )} {smallArea &&
{title}
}
{showTitle && ( <> {!smallArea && ( )} {!smallArea &&
{title}
} )}
{status !== 'done' &&
{formattedDuration}
}
); } interface TimelineEntryStatusProps { delay: number; start: number; dayOffset: Day; totalGap: number; isLinkedToLoaded: boolean; status: ProgressStatus; } // extract component to isolate re-renders provoked by the clock changes function TimelineEntryStatus({ delay, start, dayOffset, totalGap, isLinkedToLoaded, status, }: TimelineEntryStatusProps) { const state = useExpectedStartData(); const { getLocalizedString } = useTranslation(); const { timeToStart } = getExpectedTimesFromExtendedEvent( { timeStart: start, delay, dayOffset, totalGap, isLinkedToLoaded, countToEnd: false, duration: 0 }, state, ); let statusText = getStatusLabel(timeToStart, status); if (statusText === 'live') { statusText = getLocalizedString('timeline.live'); } else if (statusText === 'pending') { statusText = getLocalizedString('timeline.due'); } const isDue = status === 'future' && timeToStart <= 0; return
{statusText}
; } /** Generates a block level progress bar */ function ActiveBlock() { const { current, duration } = useTimer(); const progress = getProgress(current, duration); return (
); }