Files
ontime/apps/client/src/views/countdown/SingleEventCountdown.tsx
T
Alex Christoffer Rasmussen 2a890cf2b3 fix: issue where a countToEnd would lead to incorrect expected times (#2149)
* fix: issue where a count-to-end would lead to incorrect expected times

* fix: include add time in overtime when countToEnd

* fix: ui and server use same calculation for expected end
2026-07-25 11:22:24 +02:00

84 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { getExpectedEnd, getExpectedStart } from 'ontime-utils';
import { IoPencil } from 'react-icons/io5';
import Button from '../../common/components/buttons/Button';
import useReport from '../../common/hooks-query/useReport';
import { useFadeOutOnInactivity } from '../../common/hooks/useFadeOutOnInactivity';
import { useExpectedStartData } from '../../common/hooks/useSocket';
import { cx } from '../../common/utils/styleUtils';
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
import { getPropertyValue } from '../common/viewUtils';
import { useCountdownOptions } from './countdown.options';
import { CountdownEvent, CountdownTarget, useSubscriptionDisplayData } from './countdown.utils';
import { ScheduleTime } from './CountdownSubscriptions';
import './SingleEventCountdown.scss';
interface SingleEventCountdownProps {
subscribedEvent: CountdownTarget;
goToEditMode: () => void;
}
export default function SingleEventCountdown({ subscribedEvent, goToEditMode }: SingleEventCountdownProps) {
const { mainSource, secondarySource, showExpected } = useCountdownOptions();
const showFab = useFadeOutOnInactivity(true);
const { data: reportData } = useReport();
const { offset, currentDay, actualStart, plannedStart, mode } = useExpectedStartData();
const { totalGap, isLinkedToLoaded } = subscribedEvent;
const expectedStart = getExpectedStart(subscribedEvent, {
currentDay,
totalGap,
actualStart,
plannedStart,
isLinkedToLoaded,
offset,
mode,
});
const expectedEnd = getExpectedEnd(subscribedEvent, expectedStart, currentDay);
const { endedAt } = reportData[subscribedEvent.reportId ?? subscribedEvent.id] ?? { endedAt: null };
const countdownEvent = { ...subscribedEvent, expectedStart, endedAt, expectedEnd };
const titleTmp = getPropertyValue(subscribedEvent, mainSource ?? 'title');
const title = titleTmp?.length ? titleTmp : ' '; // insert utf-8 empty space to avoid the line collapsing;
// while a group is live, surface the running event's title as the secondary line
const liveTitle = subscribedEvent.isGroup && subscribedEvent.liveEntry ? subscribedEvent.liveEntry.title : undefined;
const secondaryData = liveTitle ?? getPropertyValue(subscribedEvent, secondarySource);
return (
<div className='single-container' data-testid='countdown-event'>
<SubscriptionStatus event={countdownEvent} />
<div className='event__title' style={{ borderColor: countdownEvent.colour }}>
<ScheduleTime event={countdownEvent} showExpected={showExpected} />
{title}
{secondaryData && <div className='secondary'>{secondaryData}</div>}
</div>
<div className={cx(['fab-container', !showFab && 'fab-container--hidden'])}>
<Button variant='primary' size='xlarge' onClick={goToEditMode}>
<IoPencil /> Edit
</Button>
</div>
</div>
);
}
interface SubscriptionStatusProps {
event: CountdownEvent;
}
function SubscriptionStatus({ event }: SubscriptionStatusProps) {
const { status, statusDisplay, timeDisplay } = useSubscriptionDisplayData(event);
return (
<>
<div className='event__status'>{statusDisplay}</div>
{status === 'done' ? (
<SuperscriptTime className='event__timer' time={timeDisplay} />
) : (
<div className='event__timer'>{timeDisplay}</div>
)}
</>
);
}