mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-19 14:14:17 +00:00
Expected time for views (#1798)
* refactor: use correct metadata in op view * refactor: use correct metadata in backstage view * remove uneeded test * fix: correct offset colour * refactor: use correct metadata in timline view * refactor: schedule item dont pass the whole event * chore: lint
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
|
||||
import { getScheduledTimes } from './schedule.utils';
|
||||
import { useSchedule } from './ScheduleContext';
|
||||
import ScheduleItem from './ScheduleItem';
|
||||
|
||||
@@ -20,17 +19,20 @@ export default function Schedule({ className }: ScheduleProps) {
|
||||
return (
|
||||
<ul className={cx(['schedule', className])} ref={containerRef}>
|
||||
{events.map((event) => {
|
||||
const { timeStart, timeEnd, delay } = getScheduledTimes(event);
|
||||
|
||||
return (
|
||||
<ScheduleItem
|
||||
key={event.id}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
title={event.title}
|
||||
timeStart={event.timeStart}
|
||||
dayOffset={event.dayOffset}
|
||||
delay={event.delay}
|
||||
totalGap={event.totalGap}
|
||||
isLinkedToLoaded={event.isLinkedToLoaded}
|
||||
countToEnd={event.countToEnd}
|
||||
duration={event.duration}
|
||||
colour={event.colour}
|
||||
skip={event.skip}
|
||||
delay={delay}
|
||||
title={event.title}
|
||||
timeEnd={event.timeEnd}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -2,11 +2,12 @@ import { createContext, PropsWithChildren, RefObject, use, useEffect, useLayoutE
|
||||
import { EntryId, isOntimeEvent, OntimeEntry, OntimeEvent } from 'ontime-types';
|
||||
|
||||
import { usePartialRundown } from '../../../common/hooks-query/useRundown';
|
||||
import { ExtendedEntry } from '../../../common/utils/rundownMetadata';
|
||||
|
||||
import { useScheduleOptions } from './schedule.options';
|
||||
|
||||
interface ScheduleContextState {
|
||||
events: OntimeEvent[];
|
||||
events: ExtendedEntry<OntimeEvent>[];
|
||||
selectedEventId: string | null;
|
||||
numPages: number;
|
||||
visiblePage: number;
|
||||
@@ -21,7 +22,7 @@ interface ScheduleProviderProps {
|
||||
|
||||
export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildren<ScheduleProviderProps>) => {
|
||||
const { cycleInterval, stopCycle, filter } = useScheduleOptions();
|
||||
const { data: events } = usePartialRundown((entry: OntimeEntry) => {
|
||||
const { data: events } = usePartialRundown((entry: ExtendedEntry<OntimeEntry>) => {
|
||||
if (filter) {
|
||||
// custom keys are prepended with custom-
|
||||
const customKey = filter.startsWith('custom-') ? filter.slice('custom-'.length) : filter;
|
||||
@@ -133,7 +134,7 @@ export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildre
|
||||
return (
|
||||
<ScheduleContext
|
||||
value={{
|
||||
events: viewEvents as OntimeEvent[],
|
||||
events: viewEvents as ExtendedEntry<OntimeEvent>[],
|
||||
selectedEventId,
|
||||
numPages,
|
||||
visiblePage,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { useRuntimeOffset } from '../../../common/hooks/useSocket';
|
||||
import { OntimeEvent } from 'ontime-types';
|
||||
|
||||
import { useExpectedStartData } from '../../../common/hooks/useSocket';
|
||||
import { getOffsetState } from '../../../common/utils/offset';
|
||||
import { ExtendedEntry } from '../../../common/utils/rundownMetadata';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
import { formatTime } from '../../../common/utils/time';
|
||||
import { formatTime, getExpectedTimesFromExtendedEvent } from '../../../common/utils/time';
|
||||
import SuperscriptTime from '../../../features/viewers/common/superscript-time/SuperscriptTime';
|
||||
|
||||
import { useScheduleOptions } from './schedule.options';
|
||||
@@ -13,27 +16,49 @@ const formatOptions = {
|
||||
format24: 'HH:mm',
|
||||
};
|
||||
|
||||
interface ScheduleItemProps {
|
||||
timeStart: number;
|
||||
timeEnd: number;
|
||||
title: string;
|
||||
colour?: string;
|
||||
skip?: boolean;
|
||||
delay: number;
|
||||
}
|
||||
type ScheduleItemProps = Pick<
|
||||
ExtendedEntry<OntimeEvent>,
|
||||
| 'timeStart'
|
||||
| 'dayOffset'
|
||||
| 'delay'
|
||||
| 'totalGap'
|
||||
| 'isLinkedToLoaded'
|
||||
| 'countToEnd'
|
||||
| 'duration'
|
||||
| 'colour'
|
||||
| 'skip'
|
||||
| 'title'
|
||||
| 'timeEnd'
|
||||
>;
|
||||
|
||||
export default function ScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }: ScheduleItemProps) {
|
||||
export default function ScheduleItem({
|
||||
timeStart,
|
||||
dayOffset,
|
||||
delay,
|
||||
totalGap,
|
||||
isLinkedToLoaded,
|
||||
countToEnd,
|
||||
colour,
|
||||
duration,
|
||||
skip,
|
||||
title,
|
||||
timeEnd,
|
||||
}: ScheduleItemProps) {
|
||||
const { showExpected } = useScheduleOptions();
|
||||
|
||||
if (showExpected) {
|
||||
return (
|
||||
<ExpectedScheduleItem
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
title={title}
|
||||
dayOffset={dayOffset}
|
||||
delay={delay}
|
||||
totalGap={totalGap}
|
||||
isLinkedToLoaded={isLinkedToLoaded}
|
||||
countToEnd={countToEnd}
|
||||
duration={duration}
|
||||
colour={colour}
|
||||
skip={skip}
|
||||
delay={delay}
|
||||
title={title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -42,11 +67,11 @@ export default function ScheduleItem({ timeStart, timeEnd, title, colour, skip,
|
||||
return (
|
||||
<DelayedScheduleItem
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
title={title}
|
||||
delay={delay}
|
||||
colour={colour}
|
||||
skip={skip}
|
||||
delay={delay}
|
||||
timeEnd={timeEnd}
|
||||
title={title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -66,7 +91,14 @@ export default function ScheduleItem({ timeStart, timeEnd, title, colour, skip,
|
||||
);
|
||||
}
|
||||
|
||||
function DelayedScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }: ScheduleItemProps) {
|
||||
function DelayedScheduleItem({
|
||||
timeStart,
|
||||
timeEnd,
|
||||
title,
|
||||
colour,
|
||||
skip,
|
||||
delay,
|
||||
}: Pick<ScheduleItemProps, 'timeStart' | 'timeEnd' | 'title' | 'colour' | 'skip' | 'delay'>) {
|
||||
const start = formatTime(timeStart, formatOptions);
|
||||
const end = formatTime(timeEnd, formatOptions);
|
||||
const delayedStart = formatTime(timeStart + delay, formatOptions);
|
||||
@@ -92,14 +124,39 @@ function DelayedScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }:
|
||||
);
|
||||
}
|
||||
|
||||
function ExpectedScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }: ScheduleItemProps) {
|
||||
function ExpectedScheduleItem({
|
||||
timeStart,
|
||||
dayOffset,
|
||||
delay,
|
||||
totalGap,
|
||||
isLinkedToLoaded,
|
||||
countToEnd,
|
||||
colour,
|
||||
duration,
|
||||
skip,
|
||||
title,
|
||||
}: Omit<ScheduleItemProps, 'timeEnd'>) {
|
||||
const expectedStartData = useExpectedStartData();
|
||||
const { expectedStart, expectedEnd, plannedEnd } = getExpectedTimesFromExtendedEvent(
|
||||
{
|
||||
timeStart,
|
||||
dayOffset,
|
||||
delay,
|
||||
totalGap,
|
||||
isLinkedToLoaded,
|
||||
countToEnd,
|
||||
duration,
|
||||
},
|
||||
expectedStartData,
|
||||
);
|
||||
|
||||
return (
|
||||
<li className={cx(['entry', skip && 'entry--skip'])}>
|
||||
<div className='entry-times'>
|
||||
<span className='entry-colour' style={{ backgroundColor: colour }} />
|
||||
<ExpectedTime time={timeStart} delay={delay} />
|
||||
<ExpectedTime expectedTime={expectedStart} plannedTime={timeStart} />
|
||||
→
|
||||
<ExpectedTime time={timeEnd} delay={delay} />
|
||||
<ExpectedTime expectedTime={expectedEnd} plannedTime={plannedEnd} />
|
||||
</div>
|
||||
<div className='entry-title'>{title}</div>
|
||||
</li>
|
||||
@@ -107,16 +164,12 @@ function ExpectedScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }
|
||||
}
|
||||
|
||||
interface ExpectedTimeProps {
|
||||
time: number;
|
||||
delay: number;
|
||||
expectedTime: number;
|
||||
plannedTime: number;
|
||||
}
|
||||
|
||||
function ExpectedTime({ time, delay }: ExpectedTimeProps) {
|
||||
const { offset } = useRuntimeOffset();
|
||||
|
||||
const expectedOffset = offset - delay;
|
||||
const expectedTime = formatTime(time + offset, formatOptions);
|
||||
const expectedState = getOffsetState(expectedOffset);
|
||||
|
||||
return <SuperscriptTime className={`entry-times--${expectedState}`} time={expectedTime} />;
|
||||
function ExpectedTime({ expectedTime, plannedTime }: ExpectedTimeProps) {
|
||||
const timeDisplay = formatTime(expectedTime);
|
||||
const expectedState = getOffsetState(expectedTime - plannedTime);
|
||||
return <SuperscriptTime className={`entry-times--${expectedState}`} time={timeDisplay} />;
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { OntimeEvent } from 'ontime-types';
|
||||
|
||||
/**
|
||||
* Gather rules for how to present scheduled times
|
||||
*/
|
||||
export function getScheduledTimes(event: OntimeEvent) {
|
||||
return {
|
||||
timeStart: event.timeStart,
|
||||
timeEnd: event.timeEnd,
|
||||
delay: event.skip ? 0 : event.delay,
|
||||
};
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { isOntimeEvent, isPlayableEvent, OntimeEntry, PlayableEvent } from 'onti
|
||||
import { dayInMs, getLastEvent, MILLIS_PER_HOUR } from 'ontime-utils';
|
||||
|
||||
import useHorizontalFollowComponent from '../../common/hooks/useHorizontalFollowComponent';
|
||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||
import { cx } from '../../common/utils/styleUtils';
|
||||
|
||||
import TimelineMarkers from './timeline-markers/TimelineMarkers';
|
||||
@@ -15,7 +16,7 @@ import style from './Timeline.module.scss';
|
||||
|
||||
interface TimelineProps {
|
||||
firstStart: number;
|
||||
rundown: OntimeEntry[];
|
||||
rundown: ExtendedEntry<OntimeEntry>[];
|
||||
selectedEventId: string | null;
|
||||
totalDuration: number;
|
||||
}
|
||||
@@ -45,7 +46,7 @@ function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: Timel
|
||||
|
||||
const { positions, totalWidth } = useMemo(() => {
|
||||
const playableEvents = rundown
|
||||
.filter((event): event is PlayableEvent => isOntimeEvent(event) && isPlayableEvent(event))
|
||||
.filter((event): event is ExtendedEntry<PlayableEvent> => isOntimeEvent(event) && isPlayableEvent(event))
|
||||
.map((event) => ({
|
||||
start: event.timeStart + (event.dayOffset ?? 0) * dayInMs + (event.delay ?? 0),
|
||||
duration: event.duration,
|
||||
@@ -96,6 +97,9 @@ function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: Timel
|
||||
left={position.left}
|
||||
status={statusMap[event.id]}
|
||||
start={event.timeStart + (event.dayOffset ?? 0) * dayInMs}
|
||||
totalGap={event.totalGap}
|
||||
isLinkedToLoaded={event.isLinkedToLoaded}
|
||||
dayOffset={event.dayOffset}
|
||||
title={event.title}
|
||||
width={position.width}
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { RefObject } from 'react';
|
||||
|
||||
import { useTimelineStatus, useTimer } from '../../common/hooks/useSocket';
|
||||
import { useExpectedStartData, useTimer } from '../../common/hooks/useSocket';
|
||||
import { getProgress } from '../../common/utils/getProgress';
|
||||
import { alpha, cx } from '../../common/utils/styleUtils';
|
||||
import { formatDuration, formatTime } from '../../common/utils/time';
|
||||
import { formatDuration, formatTime, getExpectedTimesFromExtendedEvent } from '../../common/utils/time';
|
||||
import { useTranslation } from '../../translation/TranslationProvider';
|
||||
|
||||
import { getStatusLabel, getTimeToStart } from './timeline.utils';
|
||||
import { getStatusLabel } from './timeline.utils';
|
||||
|
||||
import style from './Timeline.module.scss';
|
||||
|
||||
@@ -20,6 +20,9 @@ interface TimelineEntryProps {
|
||||
left: number;
|
||||
status: ProgressStatus;
|
||||
start: number;
|
||||
dayOffset: number;
|
||||
totalGap: number;
|
||||
isLinkedToLoaded: boolean;
|
||||
title: string;
|
||||
width: number;
|
||||
ref?: RefObject<HTMLDivElement | null>;
|
||||
@@ -38,6 +41,9 @@ export function TimelineEntry({
|
||||
left,
|
||||
status,
|
||||
start,
|
||||
dayOffset,
|
||||
totalGap,
|
||||
isLinkedToLoaded,
|
||||
title,
|
||||
width,
|
||||
ref,
|
||||
@@ -73,11 +79,29 @@ export function TimelineEntry({
|
||||
<div className={style.maybeInline}>
|
||||
<div className={cx([hasDelay && style.cross])}>{formattedStartTime}</div>
|
||||
{hasDelay && <div className={style.delay}>{formatTime(delayedStart, formatOptions)}</div>}
|
||||
{smallArea && <TimelineEntryStatus delay={delay} start={start} status={status} />}
|
||||
{smallArea && (
|
||||
<TimelineEntryStatus
|
||||
delay={delay}
|
||||
start={start}
|
||||
dayOffset={dayOffset}
|
||||
totalGap={totalGap}
|
||||
isLinkedToLoaded={isLinkedToLoaded}
|
||||
status={status}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{showTitle && (
|
||||
<>
|
||||
{!smallArea && <TimelineEntryStatus delay={delay} start={start} status={status} />}
|
||||
{!smallArea && (
|
||||
<TimelineEntryStatus
|
||||
delay={delay}
|
||||
start={start}
|
||||
dayOffset={dayOffset}
|
||||
totalGap={totalGap}
|
||||
isLinkedToLoaded={isLinkedToLoaded}
|
||||
status={status}
|
||||
/>
|
||||
)}
|
||||
<div>{title}</div>
|
||||
</>
|
||||
)}
|
||||
@@ -92,16 +116,31 @@ export function TimelineEntry({
|
||||
interface TimelineEntryStatusProps {
|
||||
delay: number;
|
||||
start: number;
|
||||
dayOffset: number;
|
||||
totalGap: number;
|
||||
isLinkedToLoaded: boolean;
|
||||
status: ProgressStatus;
|
||||
}
|
||||
|
||||
// extract component to isolate re-renders provoked by the clock changes
|
||||
function TimelineEntryStatus({ delay, start, status }: TimelineEntryStatusProps) {
|
||||
const { clock, offset } = useTimelineStatus();
|
||||
function TimelineEntryStatus({
|
||||
delay,
|
||||
start,
|
||||
dayOffset,
|
||||
totalGap,
|
||||
isLinkedToLoaded,
|
||||
status,
|
||||
}: TimelineEntryStatusProps) {
|
||||
const state = useExpectedStartData();
|
||||
|
||||
const { getLocalizedString } = useTranslation();
|
||||
|
||||
// start times need to be normalised in a rundown that crosses midnight
|
||||
let statusText = getStatusLabel(getTimeToStart(clock, start, delay, offset), status);
|
||||
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') {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { OntimeEvent } from 'ontime-types';
|
||||
|
||||
import { useTimelineSocket } from '../../common/hooks/useSocket';
|
||||
import { formatDuration } from '../../common/utils/time';
|
||||
import { useExpectedStartData } from '../../common/hooks/useSocket';
|
||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||
import { formatDuration, getExpectedTimesFromExtendedEvent } from '../../common/utils/time';
|
||||
import { useTranslation } from '../../translation/TranslationProvider';
|
||||
|
||||
import TimelineSection from './timeline-section/TimelineSection';
|
||||
import { getTimeToStart } from './timeline.utils';
|
||||
|
||||
interface TimelineSectionsProps {
|
||||
now: OntimeEvent | null;
|
||||
next: OntimeEvent | null;
|
||||
followedBy: OntimeEvent | null;
|
||||
now: ExtendedEntry<OntimeEvent> | null;
|
||||
next: ExtendedEntry<OntimeEvent> | null;
|
||||
followedBy: ExtendedEntry<OntimeEvent> | null;
|
||||
}
|
||||
|
||||
export default function TimelineSections({ now, next, followedBy }: TimelineSectionsProps) {
|
||||
const { getLocalizedString } = useTranslation();
|
||||
const { clock, offset } = useTimelineSocket();
|
||||
const state = useExpectedStartData();
|
||||
|
||||
// gather card data
|
||||
const titleNow = now?.title ?? '-';
|
||||
@@ -26,20 +26,20 @@ export default function TimelineSections({ now, next, followedBy }: TimelineSect
|
||||
let followedByStatus: string | undefined;
|
||||
|
||||
if (next !== null) {
|
||||
const timeToStart = getTimeToStart(clock, next.timeStart, next?.delay ?? 0, offset);
|
||||
if (timeToStart < 0) {
|
||||
const { timeToStart } = getExpectedTimesFromExtendedEvent(next, state);
|
||||
if (timeToStart <= 0) {
|
||||
nextStatus = dueText;
|
||||
} else {
|
||||
nextStatus = `T - ${formatDuration(timeToStart)}`;
|
||||
nextStatus = formatDuration(timeToStart);
|
||||
}
|
||||
}
|
||||
|
||||
if (followedBy !== null) {
|
||||
const timeToStart = getTimeToStart(clock, followedBy.timeStart, followedBy?.delay ?? 0, offset);
|
||||
if (timeToStart < 0) {
|
||||
const { timeToStart } = getExpectedTimesFromExtendedEvent(followedBy, state);
|
||||
if (timeToStart <= 0) {
|
||||
followedByStatus = dueText;
|
||||
} else {
|
||||
followedByStatus = `T - ${formatDuration(timeToStart)}`;
|
||||
followedByStatus = formatDuration(timeToStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
MILLIS_PER_HOUR,
|
||||
} from 'ontime-utils';
|
||||
|
||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||
import { formatDuration } from '../../common/utils/time';
|
||||
|
||||
import { useTimelineOptions } from './timeline.options';
|
||||
@@ -76,7 +77,7 @@ export function getStatusLabel(timeToStart: number, status: ProgressStatus): str
|
||||
return status;
|
||||
}
|
||||
|
||||
if (timeToStart < 0) {
|
||||
if (timeToStart <= 0) {
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
@@ -84,12 +85,15 @@ export function getStatusLabel(timeToStart: number, status: ProgressStatus): str
|
||||
}
|
||||
|
||||
interface ScopedRundownData {
|
||||
scopedRundown: PlayableEvent[];
|
||||
scopedRundown: ExtendedEntry<PlayableEvent>[];
|
||||
firstStart: number;
|
||||
totalDuration: number;
|
||||
}
|
||||
|
||||
export function useScopedRundown(rundown: OntimeEntry[], selectedEventId: MaybeString): ScopedRundownData {
|
||||
export function useScopedRundown(
|
||||
rundown: ExtendedEntry<OntimeEntry>[],
|
||||
selectedEventId: MaybeString,
|
||||
): ScopedRundownData {
|
||||
const { hidePast } = useTimelineOptions();
|
||||
|
||||
const data = useMemo(() => {
|
||||
@@ -97,11 +101,11 @@ export function useScopedRundown(rundown: OntimeEntry[], selectedEventId: MaybeS
|
||||
return { scopedRundown: [], firstStart: 0, totalDuration: 0 };
|
||||
}
|
||||
|
||||
const scopedRundown: PlayableEvent[] = [];
|
||||
const scopedRundown: ExtendedEntry<PlayableEvent>[] = [];
|
||||
let selectedIndex = selectedEventId ? Infinity : -1;
|
||||
let firstStart = null;
|
||||
let totalDuration = 0;
|
||||
let lastEntry: PlayableEvent | null = null;
|
||||
let lastEntry: ExtendedEntry<PlayableEvent> | null = null;
|
||||
|
||||
for (let i = 0; i < rundown.length; i++) {
|
||||
const currentEntry = rundown[i];
|
||||
@@ -150,26 +154,28 @@ export function useScopedRundown(rundown: OntimeEntry[], selectedEventId: MaybeS
|
||||
}
|
||||
|
||||
type UpcomingEvents = {
|
||||
now: OntimeEvent | null;
|
||||
next: OntimeEvent | null;
|
||||
followedBy: OntimeEvent | null;
|
||||
now: ExtendedEntry<OntimeEvent> | null;
|
||||
next: ExtendedEntry<OntimeEvent> | null;
|
||||
followedBy: ExtendedEntry<OntimeEvent> | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns upcoming events from current: now, next and followedBy
|
||||
*/
|
||||
export function getUpcomingEvents(events: PlayableEvent[], selectedId: MaybeString): UpcomingEvents {
|
||||
export function getUpcomingEvents(events: ExtendedEntry<PlayableEvent>[], selectedId: MaybeString): UpcomingEvents {
|
||||
if (events.length === 0) {
|
||||
return { now: null, next: null, followedBy: null };
|
||||
}
|
||||
|
||||
let now = selectedId ? getEventWithId(events, selectedId) : null;
|
||||
let now = selectedId ? (getEventWithId(events, selectedId) as ExtendedEntry<OntimeEvent>) : null;
|
||||
if (!isOntimeEvent(now)) {
|
||||
now = null;
|
||||
}
|
||||
|
||||
const next = now ? getNextEvent(events, now.id)?.nextEvent : getFirstEvent(events).firstEvent;
|
||||
const followedBy = next ? getNextEvent(events, next.id)?.nextEvent : null;
|
||||
const next = now
|
||||
? (getNextEvent(events, now.id)?.nextEvent as ExtendedEntry<OntimeEvent> | null)
|
||||
: (getFirstEvent(events).firstEvent as ExtendedEntry<OntimeEvent> | null);
|
||||
const followedBy = next ? (getNextEvent(events, next.id)?.nextEvent as ExtendedEntry<OntimeEvent> | null) : null;
|
||||
|
||||
// Return the titles, handling nulls appropriately
|
||||
return {
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import { OntimeEntry, ProjectData, Settings } from 'ontime-types';
|
||||
|
||||
import useProjectData from '../../common/hooks-query/useProjectData';
|
||||
import { useFlatRundown } from '../../common/hooks-query/useRundown';
|
||||
import { useFlatRundownWithMetadata } from '../../common/hooks-query/useRundown';
|
||||
import useSettings from '../../common/hooks-query/useSettings';
|
||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||
import { aggregateQueryStatus, ViewData } from '../utils/viewLoader.utils';
|
||||
|
||||
export interface TimelineData {
|
||||
events: OntimeEntry[];
|
||||
events: ExtendedEntry<OntimeEntry>[];
|
||||
projectData: ProjectData;
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
export function useTimelineData(): ViewData<TimelineData> {
|
||||
// HTTP API data
|
||||
const { data: rundownData, status: rundownStatus } = useFlatRundown();
|
||||
const { data: rundownData, status: rundownStatus } = useFlatRundownWithMetadata();
|
||||
const { data: projectData, status: projectDataStatus } = useProjectData();
|
||||
const { data: settings, status: settingsStatus } = useSettings();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user