import { useMemo } from 'react'; import { MaybeString, OntimeEvent, ProjectData, Runtime, Settings } from 'ontime-types'; import ViewLogo from '../../common/components/view-logo/ViewLogo'; import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor'; import { useWindowTitle } from '../../common/hooks/useWindowTitle'; import { ViewExtendedTimer } from '../../common/models/TimeManager.type'; import { formatDuration, formatTime, getDefaultFormat } from '../../common/utils/time'; import SuperscriptTime from '../../features/viewers/common/superscript-time/SuperscriptTime'; import { useTranslation } from '../../translation/TranslationProvider'; import Section from './timeline-section/TimelineSection'; import Timeline from './Timeline'; import { getTimelineOptions } from './timeline.options'; import { getTimeToStart, getUpcomingEvents, useScopedRundown } from './timeline.utils'; import './TimelinePage.scss'; interface TimelinePageProps { events: OntimeEvent[]; general: ProjectData; runtime: Runtime; selectedId: MaybeString; settings: Settings | undefined; time: ViewExtendedTimer; } /** * since we inherit from viewPage * which refreshes at least once a second * There is little point splitting or memoising top level elements */ export default function TimelinePage({ events, general, runtime, selectedId, settings, time }: TimelinePageProps) { // holds copy of the rundown with only relevant events const { scopedRundown, firstStart, totalDuration } = useScopedRundown(events, selectedId); const { getLocalizedString } = useTranslation(); const clock = formatTime(time.clock); const { now, next, followedBy } = useMemo(() => { return getUpcomingEvents(scopedRundown, selectedId); }, [scopedRundown, selectedId]); useWindowTitle('Timeline'); // populate options const defaultFormat = getDefaultFormat(settings?.timeFormat); const progressOptions = useMemo(() => getTimelineOptions(defaultFormat), [defaultFormat]); const titleNow = now?.title ?? '-'; const dueText = getLocalizedString('timeline.due').toUpperCase(); const nextText = next !== null ? next.title : '-'; const followedByText = followedBy !== null ? followedBy.title : '-'; let nextStatus: string | undefined; let followedByStatus: string | undefined; if (next !== null) { const timeToStart = getTimeToStart(time.clock, next.timeStart, next?.delay ?? 0, runtime.offset); if (timeToStart < 0) { nextStatus = dueText; } else { nextStatus = `T - ${formatDuration(timeToStart)}`; } } if (followedBy !== null) { const timeToStart = getTimeToStart(time.clock, followedBy.timeStart, followedBy?.delay ?? 0, runtime.offset); if (timeToStart < 0) { followedByStatus = dueText; } else { followedByStatus = `T - ${formatDuration(timeToStart)}`; } } return (