From c75d8502b06dcb228427b07809ae29b70cfb88c1 Mon Sep 17 00:00:00 2001
From: cv <34649812+cpvalente@users.noreply.github.com>
Date: Tue, 29 Aug 2023 14:19:46 +0200
Subject: [PATCH] feat: operator view
---
.../client/src/features/operator/Operator.tsx | 26 +++++-
.../operator/status-bar/StatusBar.module.scss | 75 +++++++++++++---
.../operator/status-bar/StatusBar.tsx | 89 ++++++++++++-------
3 files changed, 140 insertions(+), 50 deletions(-)
diff --git a/apps/client/src/features/operator/Operator.tsx b/apps/client/src/features/operator/Operator.tsx
index 93a707d53..91b210382 100644
--- a/apps/client/src/features/operator/Operator.tsx
+++ b/apps/client/src/features/operator/Operator.tsx
@@ -9,6 +9,7 @@ import { getOperatorOptions } from '../../common/components/view-params-editor/c
import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor';
import useFollowComponent from '../../common/hooks/useFollowComponent';
import { useOperator } from '../../common/hooks/useSocket';
+import useEventData from '../../common/hooks-query/useEventData';
import useRundown from '../../common/hooks-query/useRundown';
import useUserFields from '../../common/hooks-query/useUserFields';
import { isStringBoolean } from '../../common/utils/viewUtils';
@@ -25,6 +26,8 @@ const selectedOffset = 50;
export default function Operator() {
const { data, status } = useRundown();
const { data: userFields, status: userFieldsStatus } = useUserFields();
+ const { data: projectData, status: projectDataStatus } = useEventData();
+
const featureData = useOperator();
const [searchParams] = useSearchParams();
@@ -69,7 +72,14 @@ export default function Operator() {
}
};
- if (!data || status === 'loading' || !userFields || userFieldsStatus === 'loading') {
+ if (
+ !data ||
+ status === 'loading' ||
+ !userFields ||
+ userFieldsStatus === 'loading' ||
+ !projectData ||
+ projectDataStatus === 'loading'
+ ) {
return ;
}
@@ -77,12 +87,14 @@ export default function Operator() {
const subscribe = searchParams.get('subscribe') as keyof UserFields | null;
const subscribedAlias = subscribe ? userFields[subscribe] : '';
const showSeconds = isStringBoolean(searchParams.get('showseconds'));
- const lastEvent = getLastEvent(data);
const operatorOptions = getOperatorOptions(userFields);
let isPast = Boolean(featureData.selectedEventId);
const hidePast = isStringBoolean(searchParams.get('hidepast'));
+ const firstEvent = getLastEvent(data);
+ const lastEvent = getLastEvent(data);
+
return (
@@ -124,7 +136,15 @@ export default function Operator() {
-
+
);
}
diff --git a/apps/client/src/features/operator/status-bar/StatusBar.module.scss b/apps/client/src/features/operator/status-bar/StatusBar.module.scss
index 7eb5f072a..d17ee2a62 100644
--- a/apps/client/src/features/operator/status-bar/StatusBar.module.scss
+++ b/apps/client/src/features/operator/status-bar/StatusBar.module.scss
@@ -1,6 +1,13 @@
@use '../../../../src/theme/ontimeColours' as *;
@use '../../../../src/theme/v2Styles' as *;
+@mixin column {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+}
+
.statusBar {
position: absolute;
bottom: 0;
@@ -9,28 +16,55 @@
z-index: 2;
padding: 0.5rem 1rem;
- display: flex;
- justify-content: space-between;
- align-items: center;
border-top: 1px solid $white-10;
box-shadow: $large-bottom-drawer-shadow;
+
+ display: grid;
+ grid-template-areas:
+ "playback timer1B timer2B timer3B";
+ grid-template-columns: 1fr auto auto auto;
+ column-gap: 1.5rem;
+ align-items: center;
}
.playbackIcon {
+ grid-area: playback;
font-size: 2rem;
color: $gray-700;
}
-.column {
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
+.timeNow {
+ grid-area: timer1B;
+ @include column;
}
-.clock {
- display: flex;
- gap: 1.5rem;
+.elapsedTime {
+ grid-area: timer2B;
+ @include column;
+}
+
+.runningTime {
+ grid-area: timer3B;
+ @include column;
+}
+
+.title {
+ grid-area: title;
+ font-size: 1.5rem;
+ padding-left: 0.5rem;
+ display: none;
+}
+
+.startTime {
+ grid-area: timer2A;
+ @include column;
+ display: none;
+}
+
+.endTime {
+ grid-area: timer3A;
+ @include column;
+ display: none;
}
.label {
@@ -44,8 +78,23 @@
// tablet
@media (min-width: $min-tablet) {
- .clock {
+ .statusBar {
+ grid-template-areas:
+ "playback timer1B timer2B timer3B"
+ "title timer1A timer2A timer3A";
+ row-gap: 0.25rem;
+ column-gap: 2rem;
+ }
+
+ .title {
+ display: block;
+ }
+
+ .startTime {
+ display: flex;
+ }
+
+ .endTime {
display: flex;
- gap: 1.5rem;
}
}
diff --git a/apps/client/src/features/operator/status-bar/StatusBar.tsx b/apps/client/src/features/operator/status-bar/StatusBar.tsx
index 0b6919a97..dc29e2817 100644
--- a/apps/client/src/features/operator/status-bar/StatusBar.tsx
+++ b/apps/client/src/features/operator/status-bar/StatusBar.tsx
@@ -1,33 +1,52 @@
import { useMemo } from 'react';
-import { OntimeEvent, Playback } from 'ontime-types';
+import { Playback } from 'ontime-types';
import { millisToString } from 'ontime-utils';
import PlaybackIcon from '../../../common/components/playback-icon/PlaybackIcon';
-import useMediaQuery from '../../../common/context/useMediaQuery';
import { useTimer } from '../../../common/hooks/useSocket';
import { formatTime } from '../../../common/utils/time';
import styles from './StatusBar.module.scss';
-export default function StatusBar({
- playback,
- lastEvent,
- selectedEventId,
-}: {
+interface StatusBarProps {
+ projectTitle: string;
playback: Playback;
- lastEvent: OntimeEvent | null;
selectedEventId: string | null;
-}) {
- const timer = useTimer();
- const isMobile = useMediaQuery('(max-width: 450px)');
+ firstStart?: number;
+ firstId?: string;
+ lastEnd?: number;
+ lastId?: string;
+}
- const getTimeEnd = () => {
- if (lastEvent === null) {
+export default function StatusBar(props: StatusBarProps) {
+ const { projectTitle, playback, selectedEventId, firstStart, firstId, lastEnd, lastId } = props;
+
+ const timer = useTimer();
+
+ const getTimeStart = () => {
+ if (firstStart === undefined) {
return '...';
}
- const timeEnd = lastEvent.id === selectedEventId ? timer.expectedFinish : lastEvent.timeEnd;
- return millisToString(timeEnd);
+ if (selectedEventId) {
+ if (firstId === selectedEventId) {
+ return millisToString(timer.expectedFinish);
+ }
+ }
+ return millisToString(firstStart);
+ };
+
+ const getTimeEnd = () => {
+ if (lastEnd === undefined) {
+ return '...';
+ }
+
+ if (selectedEventId) {
+ if (lastId === selectedEventId) {
+ return millisToString(timer.expectedFinish);
+ }
+ }
+ return millisToString(lastEnd);
};
// use user defined format
@@ -44,26 +63,28 @@ export default function StatusBar({
return (
+
{projectTitle}
+
+ Scheduled start
+ {getTimeStart()}
+
+
+ Scheduled end
+ {getTimeEnd()}
+
+
{PlaybackIconComponent}
-
-
- Time now
- {timeNow}
-
- {!isMobile && (
-
- Last end
- {getTimeEnd()}
-
- )}
-
- Elapsed time
- {elapsedTime}
-
-
- Running timer
- {runningTime}
-
+
+ Time now
+ {timeNow}
+
+
+ Elapsed time
+ {elapsedTime}
+
+
+ Running timer
+ {runningTime}
);