Files
ontime/apps/client/src/views/studio/StudioTimers.tsx
T
Carlos Valente 1849b4d39f Deps migration (#1988)
* chore: migrate eslint to oxlint

* chore: migrate prettier to oxfmt

* chore: migrate typescript

* chore: toThrow should have a expected value

* chore: cast test value as Day

* chore: small title fix

* chore: mocks should be hoisted

* chore: incorrect async useage

* chore: test should be inside description

* chore: test sohuld include an expeced

* chore: oxfmt

---------

Co-authored-by: alex-Arc <omnivox@LAPTOP-RC5SNBVV.localdomain>
2026-03-08 16:22:12 +01:00

146 lines
5.1 KiB
TypeScript

import { Playback, TimerPhase, ViewSettings } from 'ontime-types';
import { millisToString } from 'ontime-utils';
import { useAuxTimersTime, useStudioTimersSocket } from '../../common/hooks/useSocket';
import { getOffsetState } from '../../common/utils/offset';
import { cx } from '../../common/utils/styleUtils';
import { useTranslation } from '../../translation/TranslationProvider';
import { getPropertyValue } from '../common/viewUtils';
import { getTimerColour } from '../utils/presentation.utils';
import { useStudioOptions } from './studio.options';
import { getFormattedEventData, getFormattedScheduleTimes } from './studioTimers.utils';
import './StudioTimers.scss';
interface StudioTimersProps {
viewSettings: ViewSettings;
}
export default function StudioTimers({ viewSettings }: StudioTimersProps) {
const { getLocalizedString } = useTranslation();
const { mainSource } = useStudioOptions();
const { eventNow, eventNext, message, time, offset, rundown, expectedRundownEnd } = useStudioTimersSocket();
const schedule = getFormattedScheduleTimes({
offset: offset,
actualStart: rundown.actualStart,
expectedEnd: expectedRundownEnd,
});
const event = getFormattedEventData(eventNow, time, mainSource);
const eventNextTitle = getPropertyValue(eventNext, mainSource ?? 'title') || '-';
const formattedTimerMessage = (message.timer.visible && message.timer.text) || '-';
const formattedSecondaryMessage = message.timer.secondarySource === 'secondary' ? message.secondary || '-' : '-';
// gather presentation styles
const timerColour = getTimerColour(
viewSettings,
undefined,
time.phase === TimerPhase.Warning,
time.phase === TimerPhase.Danger,
);
const offsetState = getOffsetState(offset);
return (
<div className='studio__timers'>
<div className='card' id='card-schedule'>
<div className='card__row'>
<div>
<div className='label'>{getLocalizedString('common.started_at')}</div>
<div className='runtime-timer'>{schedule.actualStart}</div>
</div>
<div>
<div className='label center'>Over / under</div>
<div className={cx(['runtime-timer', 'center', !eventNow && 'muted', offsetState])}>{schedule.offset}</div>
</div>
<div>
<div className='label right'>{getLocalizedString('common.expected_end')}</div>
<div className='runtime-timer right'>{schedule.expectedEnd}</div>
</div>
</div>
</div>
<div className='card' id='card-event-now'>
<div className='card__row'>
<div>
<div className='label'>{getLocalizedString('common.now')}</div>
<div className='title'>{event.title}</div>
</div>
<div>
<div className='label right'>{getLocalizedString('common.next')}</div>
<div className='title right'>{eventNextTitle}</div>
</div>
</div>
<div className='card__row'>
<div>
<div className='label'>{getLocalizedString('common.started_at')}</div>
<div className='runtime-timer'>{event.startedAt}</div>
</div>
<div>
<div className='label' />
<div
className={cx([
'event-timer',
time.phase === TimerPhase.Overtime && 'event-timer--finished',
time.playback === Playback.Pause && 'event-timer--paused',
])}
style={{
'--phase-color': timerColour,
}}
data-phase={time.phase}
>
{event.timer}
</div>
</div>
<div>
<div className='label right'>{getLocalizedString('common.expected_end')}</div>
<div className='runtime-timer right'>{event.expectedEnd}</div>
</div>
</div>
</div>
<StudioTimersAux />
<div className='card' id='card-timer-message'>
<div>
<div className='label'>{getLocalizedString('common.timer_message')}</div>
<div className={cx(['extra', !formattedTimerMessage && 'muted'])}>{formattedTimerMessage}</div>
</div>
</div>
<div className='card' id='card-secondary-message'>
<div>
<div className='label'>{getLocalizedString('common.secondary_message')}</div>
<div className={cx(['extra', !formattedSecondaryMessage && 'muted'])}>{formattedSecondaryMessage}</div>
</div>
</div>
</div>
);
}
function StudioTimersAux() {
const auxTimer = useAuxTimersTime();
return (
<div className='card' id='card-aux'>
<div className='card__row'>
<div>
<div className='label'>Aux 1</div>
<div className='extra'>{millisToString(auxTimer.aux1)}</div>
</div>
<div>
<div className='label center'>Aux 2</div>
<div className='extra center'>{millisToString(auxTimer.aux2)}</div>
</div>
<div>
<div className='label right'>Aux 3</div>
<div className='extra right'>{millisToString(auxTimer.aux3)}</div>
</div>
</div>
</div>
);
}