mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-13 03:13:47 +00:00
fix: format clock from preset (#2066)
* fix: format clock from preset * fix: add to all views * chore: format * refactor: return flat value from common.options.ts
This commit is contained in:
committed by
GitHub
parent
1a08b39b8b
commit
a5e733246d
@@ -26,3 +26,14 @@ export const showLeadingZeros: ParamField = {
|
||||
type: 'boolean',
|
||||
defaultValue: false,
|
||||
};
|
||||
|
||||
export type TimeOptions = {
|
||||
timeformat: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to get value of 'timeformat' from either source, prioritizing defaultValues
|
||||
*/
|
||||
export function getTimeOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URLSearchParams) {
|
||||
return defaultValues?.get('timeformat') ?? searchParams.get('timeformat');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MaybeNumber, OntimeEvent, Settings, TimeFormat } from 'ontime-types';
|
||||
import { MaybeNumber, MaybeString, OntimeEvent, Settings, TimeFormat } from 'ontime-types';
|
||||
import {
|
||||
MILLIS_PER_HOUR,
|
||||
MILLIS_PER_MINUTE,
|
||||
@@ -75,8 +75,9 @@ function resolveTimeFormat(fallback12: string, fallback24: string): string {
|
||||
}
|
||||
|
||||
type FormatOptions = {
|
||||
format12: string;
|
||||
format24: string;
|
||||
format12?: string;
|
||||
format24?: string;
|
||||
override?: MaybeString;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -97,7 +98,7 @@ export const formatTime = (
|
||||
return '...';
|
||||
}
|
||||
|
||||
const timeFormat = resolver(options?.format12 ?? FORMAT_12, options?.format24 ?? FORMAT_24);
|
||||
const timeFormat = options?.override ?? resolver(options?.format12 ?? FORMAT_12, options?.format24 ?? FORMAT_24);
|
||||
const display = formatFromMillis(Math.abs(milliseconds), timeFormat);
|
||||
|
||||
const isNegative = milliseconds < 0;
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function BackstageLoader() {
|
||||
|
||||
function Backstage({ events, customFields, projectData, isMirrored, settings }: BackstageData) {
|
||||
const { getLocalizedString } = useTranslation();
|
||||
const { mainSource, secondarySource, extraInfo } = useBackstageOptions();
|
||||
const { mainSource, secondarySource, extraInfo, timeformat } = useBackstageOptions();
|
||||
const { eventNext, eventNow, rundown, selectedEventId, time } = useBackstageSocket();
|
||||
const [blinkClass, setBlinkClass] = useState(false);
|
||||
const { height: screenHeight } = useViewportSize();
|
||||
@@ -71,18 +71,20 @@ function Backstage({ events, customFields, projectData, isMirrored, settings }:
|
||||
|
||||
// gather timer data
|
||||
const isPendingStart = getIsPendingStart(time.playback, time.phase);
|
||||
const startedAt = isPendingStart ? formatTime(time.secondaryTimer) : formatTime(time.startedAt);
|
||||
const startedAt = isPendingStart
|
||||
? formatTime(time.secondaryTimer, { override: timeformat })
|
||||
: formatTime(time.startedAt, { override: timeformat });
|
||||
|
||||
const scheduledStart = (() => {
|
||||
if (showNow) return undefined;
|
||||
if (!hasEvents) return undefined;
|
||||
return formatTime(rundown.plannedStart, { format12: 'h:mm a', format24: 'HH:mm' });
|
||||
return formatTime(rundown.plannedStart, { format12: 'h:mm a', format24: 'HH:mm', override: timeformat });
|
||||
})();
|
||||
|
||||
const scheduledEnd = (() => {
|
||||
if (showNow) return undefined;
|
||||
if (!hasEvents) return undefined;
|
||||
return formatTime(rundown.plannedEnd, { format12: 'h:mm a', format24: 'HH:mm' });
|
||||
return formatTime(rundown.plannedEnd, { format12: 'h:mm a', format24: 'HH:mm', override: timeformat });
|
||||
})();
|
||||
|
||||
let displayTimer = millisToString(time.current, { fallback: timerPlaceholderMin });
|
||||
@@ -107,7 +109,7 @@ function Backstage({ events, customFields, projectData, isMirrored, settings }:
|
||||
<div className='project-header'>
|
||||
{projectData?.logo && <ViewLogo name={projectData.logo} className='logo' />}
|
||||
<div className='title'>{projectData.title}</div>
|
||||
<BackstageClock />
|
||||
<BackstageClock timeformat={timeformat} />
|
||||
</div>
|
||||
|
||||
{showProgress && <ProgressBar className='progress-container' current={time.current} duration={time.duration} />}
|
||||
@@ -131,7 +133,10 @@ function Backstage({ events, customFields, projectData, isMirrored, settings }:
|
||||
{isOvertime(time.current) ? (
|
||||
<div className='time-entry__value'>{getLocalizedString('countdown.overtime')}</div>
|
||||
) : (
|
||||
<SuperscriptTime time={formatTime(time.expectedFinish)} className='time-entry__value' />
|
||||
<SuperscriptTime
|
||||
time={formatTime(time.expectedFinish, { override: timeformat })}
|
||||
className='time-entry__value'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className='timer-gap' />
|
||||
@@ -213,12 +218,12 @@ function ExtraInfo({ projectData, size, source }: ExtraInfoProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function BackstageClock() {
|
||||
function BackstageClock({ timeformat }: { timeformat: string | null }) {
|
||||
const { getLocalizedString } = useTranslation();
|
||||
const clock = useAutoTickingClock();
|
||||
|
||||
// gather timer data
|
||||
const formattedClock = formatTime(clock);
|
||||
const formattedClock = formatTime(clock, { override: timeformat });
|
||||
|
||||
return (
|
||||
<div className='clock-container'>
|
||||
|
||||
@@ -2,7 +2,11 @@ import { CustomFields, OntimeEvent, ProjectData } from 'ontime-types';
|
||||
import { use, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router';
|
||||
|
||||
import { getTimeOption } from '../../common/components/view-params-editor/common.options';
|
||||
import {
|
||||
getTimeOption,
|
||||
getTimeOptionsFromParams,
|
||||
TimeOptions,
|
||||
} from '../../common/components/view-params-editor/common.options';
|
||||
import { OptionTitle } from '../../common/components/view-params-editor/constants';
|
||||
import { ViewOption } from '../../common/components/view-params-editor/viewParams.types';
|
||||
import {
|
||||
@@ -71,7 +75,7 @@ type BackstageOptions = {
|
||||
mainSource: keyof OntimeEvent | null;
|
||||
secondarySource: keyof OntimeEvent | null;
|
||||
extraInfo: string | null;
|
||||
};
|
||||
} & TimeOptions;
|
||||
|
||||
/**
|
||||
* Utility extract the view options from URL Params
|
||||
@@ -85,6 +89,7 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
|
||||
mainSource: getValue('main') as keyof OntimeEvent | null,
|
||||
secondarySource: getValue('secondary-src') as keyof OntimeEvent | null,
|
||||
extraInfo: getValue('extra-info'),
|
||||
timeformat: getTimeOptionsFromParams(searchParams, defaultValues),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ export function getPropertyValue(
|
||||
type FormattingOptions = {
|
||||
removeSeconds: boolean;
|
||||
removeLeadingZero: boolean;
|
||||
clockFormat?: MaybeString;
|
||||
};
|
||||
|
||||
export function getFormattedTimer(
|
||||
@@ -114,7 +115,7 @@ export function getFormattedTimer(
|
||||
}
|
||||
|
||||
if (timerType === TimerType.Clock) {
|
||||
return formatTime(timer);
|
||||
return formatTime(timer, { override: options?.clockFormat });
|
||||
}
|
||||
|
||||
let timeToParse = timer;
|
||||
|
||||
@@ -139,11 +139,12 @@ function CountdownContents({ playableEvents, subscriptions, goToEditMode }: Coun
|
||||
}
|
||||
|
||||
function CountdownClock() {
|
||||
const { timeformat } = useCountdownOptions();
|
||||
const { getLocalizedString } = useTranslation();
|
||||
const clock = useAutoTickingClock();
|
||||
|
||||
// gather timer data
|
||||
const formattedClock = formatTime(clock);
|
||||
const formattedClock = formatTime(clock, { override: timeformat });
|
||||
|
||||
return (
|
||||
<div className='clock-container'>
|
||||
|
||||
@@ -2,7 +2,11 @@ import { CustomFields, EntryId, OntimeEvent } from 'ontime-types';
|
||||
import { use, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router';
|
||||
|
||||
import { getTimeOption } from '../../common/components/view-params-editor/common.options';
|
||||
import {
|
||||
getTimeOption,
|
||||
getTimeOptionsFromParams,
|
||||
TimeOptions,
|
||||
} from '../../common/components/view-params-editor/common.options';
|
||||
import { OptionTitle } from '../../common/components/view-params-editor/constants';
|
||||
import { ViewOption } from '../../common/components/view-params-editor/viewParams.types';
|
||||
import { makeOptionsFromCustomFields } from '../../common/components/view-params-editor/viewParams.utils';
|
||||
@@ -91,7 +95,7 @@ type CountdownOptions = {
|
||||
secondarySource: keyof OntimeEvent | null;
|
||||
showExpected: boolean;
|
||||
hidePast: boolean;
|
||||
};
|
||||
} & TimeOptions;
|
||||
|
||||
/**
|
||||
* Utility extract the view options from URL Params
|
||||
@@ -115,6 +119,7 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
|
||||
secondarySource: getValue('secondary-src') as keyof OntimeEvent | null,
|
||||
showExpected: isStringBoolean(getValue('showExpected')),
|
||||
hidePast: isStringBoolean(getValue('hidePast')),
|
||||
timeformat: getTimeOptionsFromParams(searchParams, defaultValues),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useStudioClockSocket } from '../../common/hooks/useSocket';
|
||||
import { cx } from '../../common/utils/styleUtils';
|
||||
import { formatTime } from '../../common/utils/time';
|
||||
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
||||
import { useStudioOptions } from './studio.options';
|
||||
import { getLargeClockData } from './studioClock.utils';
|
||||
|
||||
import './StudioClock.scss';
|
||||
@@ -18,6 +19,7 @@ interface StudioClockProps {
|
||||
}
|
||||
|
||||
export default function StudioClock({ hideCards }: StudioClockProps) {
|
||||
const { timeformat } = useStudioOptions();
|
||||
const isSmallScreen = useIsSmallScreen();
|
||||
const clock = useAutoTickingClock();
|
||||
const { playback } = useStudioClockSocket();
|
||||
@@ -25,10 +27,10 @@ export default function StudioClock({ hideCards }: StudioClockProps) {
|
||||
|
||||
// if we are on mobile and have to show the cards
|
||||
if (isSmallScreen && !hideCards) {
|
||||
return <StudioClockMobile clock={clock} onAir={onAir} />;
|
||||
return <StudioClockMobile clock={clock} onAir={onAir} timeformat={timeformat} />;
|
||||
}
|
||||
|
||||
const { seconds, display, meridian } = getLargeClockData(clock);
|
||||
const { seconds, display, meridian } = getLargeClockData(clock, timeformat);
|
||||
|
||||
return (
|
||||
<div className='studio__clock'>
|
||||
@@ -62,10 +64,11 @@ export default function StudioClock({ hideCards }: StudioClockProps) {
|
||||
interface StudioClockMobileProps {
|
||||
clock: number;
|
||||
onAir: boolean;
|
||||
timeformat: string | null;
|
||||
}
|
||||
|
||||
function StudioClockMobile({ clock, onAir }: StudioClockMobileProps) {
|
||||
const displayClock = formatTime(clock);
|
||||
function StudioClockMobile({ clock, onAir, timeformat }: StudioClockMobileProps) {
|
||||
const displayClock = formatTime(clock, { override: timeformat });
|
||||
|
||||
return (
|
||||
<div className='studio__clock studio__clock--small'>
|
||||
|
||||
@@ -2,7 +2,11 @@ import { CustomFields, OntimeEvent } from 'ontime-types';
|
||||
import { use, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router';
|
||||
|
||||
import { getTimeOption } from '../../common/components/view-params-editor/common.options';
|
||||
import {
|
||||
getTimeOption,
|
||||
getTimeOptionsFromParams,
|
||||
TimeOptions,
|
||||
} from '../../common/components/view-params-editor/common.options';
|
||||
import { OptionTitle } from '../../common/components/view-params-editor/constants';
|
||||
import { ViewOption } from '../../common/components/view-params-editor/viewParams.types';
|
||||
import { makeOptionsFromCustomFields } from '../../common/components/view-params-editor/viewParams.utils';
|
||||
@@ -47,7 +51,7 @@ export const getStudioOptions = (timeFormat: string, customFields: CustomFields)
|
||||
type StudioOptions = {
|
||||
mainSource: keyof OntimeEvent | null;
|
||||
hideCards: boolean;
|
||||
};
|
||||
} & TimeOptions;
|
||||
|
||||
/**
|
||||
* Utility extract the view options from URL Params
|
||||
@@ -60,6 +64,7 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
|
||||
return {
|
||||
mainSource: getValue('main') as keyof OntimeEvent | null,
|
||||
hideCards: isStringBoolean(getValue('hideCards')),
|
||||
timeformat: getTimeOptionsFromParams(searchParams, defaultValues),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import { formatTime } from '../../common/utils/time';
|
||||
/**
|
||||
* Gathers display elements for the large studio clock
|
||||
*/
|
||||
export function getLargeClockData(clock: number) {
|
||||
export function getLargeClockData(clock: number, timeformat: string | null) {
|
||||
const [display, meridian] = (() => {
|
||||
const formatted = formatTime(clock);
|
||||
const formatted = formatTime(clock, { override: timeformat });
|
||||
if (formatted.endsWith('AM')) {
|
||||
return [formatted.slice(0, -2), 'AM'];
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function TimelinePageLoader() {
|
||||
|
||||
function TimelinePage({ events, customFields, projectData, settings }: TimelineData) {
|
||||
const selectedEventId = useSelectedEventId();
|
||||
const { mainSource } = useTimelineOptions();
|
||||
const { mainSource, timeformat } = useTimelineOptions();
|
||||
// holds copy of the rundown with only relevant events
|
||||
const { scopedRundown, firstStart, totalDuration } = useScopedRundown(events, selectedEventId);
|
||||
|
||||
@@ -56,7 +56,7 @@ function TimelinePage({ events, customFields, projectData, settings }: TimelineD
|
||||
<div className='project-header'>
|
||||
{projectData?.logo && <ViewLogo name={projectData.logo} className='logo' />}
|
||||
<div className='title'>{projectData.title}</div>
|
||||
<TimelineClock />
|
||||
<TimelineClock timeformat={timeformat} />
|
||||
</div>
|
||||
|
||||
<TimelineSections now={now} next={next} followedBy={followedBy} mainSource={mainSource} />
|
||||
@@ -71,12 +71,12 @@ function TimelinePage({ events, customFields, projectData, settings }: TimelineD
|
||||
);
|
||||
}
|
||||
|
||||
function TimelineClock() {
|
||||
function TimelineClock({ timeformat }: { timeformat: string | null }) {
|
||||
const { getLocalizedString } = useTranslation();
|
||||
const clock = useAutoTickingClock();
|
||||
|
||||
// gather timer data
|
||||
const formattedClock = formatTime(clock);
|
||||
const formattedClock = formatTime(clock, { override: timeformat });
|
||||
|
||||
return (
|
||||
<div className='clock-container'>
|
||||
|
||||
@@ -2,7 +2,11 @@ import { CustomFields, OntimeEvent } from 'ontime-types';
|
||||
import { use, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router';
|
||||
|
||||
import { getTimeOption } from '../../common/components/view-params-editor/common.options';
|
||||
import {
|
||||
getTimeOption,
|
||||
getTimeOptionsFromParams,
|
||||
TimeOptions,
|
||||
} from '../../common/components/view-params-editor/common.options';
|
||||
import { OptionTitle } from '../../common/components/view-params-editor/constants';
|
||||
import { ViewOption } from '../../common/components/view-params-editor/viewParams.types';
|
||||
import { makeOptionsFromCustomFields } from '../../common/components/view-params-editor/viewParams.utils';
|
||||
@@ -55,7 +59,7 @@ type TimelineOptions = {
|
||||
mainSource: keyof OntimeEvent | null;
|
||||
hidePast: boolean;
|
||||
fixedSize: boolean;
|
||||
};
|
||||
} & TimeOptions;
|
||||
|
||||
/**
|
||||
* Utility extract the view options from URL Params
|
||||
@@ -69,6 +73,7 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
|
||||
mainSource: getValue('main') as keyof OntimeEvent | null,
|
||||
hidePast: isStringBoolean(getValue('hidePast')),
|
||||
fixedSize: isStringBoolean(getValue('fixedSize')),
|
||||
timeformat: getTimeOptionsFromParams(searchParams, defaultValues),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OntimeView, TimerType } from 'ontime-types';
|
||||
import { MaybeString, OntimeView, TimerType } from 'ontime-types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { FitText } from '../../common/components/fit-text/FitText';
|
||||
@@ -69,6 +69,7 @@ function Timer({ customFields, projectData, isMirrored, settings, viewSettings,
|
||||
font,
|
||||
keyColour,
|
||||
timerColour,
|
||||
timeformat,
|
||||
} = useTimerOptions();
|
||||
|
||||
const { getLocalizedString } = useTranslation();
|
||||
@@ -106,6 +107,7 @@ function Timer({ customFields, projectData, isMirrored, settings, viewSettings,
|
||||
const display = getFormattedTimer(stageTimer, viewTimerType, localisedMinutes, {
|
||||
removeSeconds: hideTimerSeconds,
|
||||
removeLeadingZero: removeLeadingZeros,
|
||||
clockFormat: timeformat,
|
||||
});
|
||||
|
||||
const currentAux = (() => {
|
||||
@@ -164,7 +166,7 @@ function Timer({ customFields, projectData, isMirrored, settings, viewSettings,
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showClock && <TimerAutoTickingClock />}
|
||||
{showClock && <TimerAutoTickingClock clockFormat={timeformat} />}
|
||||
|
||||
<div className={cx(['timer-container', message.timer.blink && !showOverlay && 'blink'])}>
|
||||
{showEndMessage ? (
|
||||
@@ -212,9 +214,9 @@ function Timer({ customFields, projectData, isMirrored, settings, viewSettings,
|
||||
);
|
||||
}
|
||||
|
||||
function TimerAutoTickingClock() {
|
||||
function TimerAutoTickingClock({ clockFormat }: { clockFormat: MaybeString }) {
|
||||
const autoTickingClock = useAutoTickingClock();
|
||||
const formattedClock = formatTime(autoTickingClock);
|
||||
const formattedClock = formatTime(autoTickingClock, { override: clockFormat });
|
||||
const { getLocalizedString } = useTranslation();
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,8 +6,10 @@ import { useSearchParams } from 'react-router';
|
||||
import type { SelectOption } from '../../common/components/select/Select';
|
||||
import {
|
||||
getTimeOption,
|
||||
getTimeOptionsFromParams,
|
||||
hideTimerSeconds,
|
||||
showLeadingZeros,
|
||||
TimeOptions,
|
||||
} from '../../common/components/view-params-editor/common.options';
|
||||
import { OptionTitle } from '../../common/components/view-params-editor/constants';
|
||||
import { ViewOption } from '../../common/components/view-params-editor/viewParams.types';
|
||||
@@ -194,7 +196,7 @@ type TimerOptions = {
|
||||
font?: string;
|
||||
keyColour?: string;
|
||||
timerColour?: string;
|
||||
};
|
||||
} & TimeOptions;
|
||||
|
||||
/**
|
||||
* Utility extract the view options from URL Params
|
||||
@@ -229,6 +231,7 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
|
||||
font: getValue('font') ?? undefined,
|
||||
keyColour: makeColourString(getValue('keyColour')),
|
||||
timerColour: makeColourString(getValue('timerColour')),
|
||||
timeformat: getTimeOptionsFromParams(searchParams, defaultValues),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user