feat: operator view (#440)

* feat: operator view

* chore: smoke test operator

* refactor: small improvements from deepsource

---------

Co-authored-by: arihanv <arihanvaranasi@gmail.com>
Co-authored-by: arihanv <63890951+arihanv@users.noreply.github.com>
This commit is contained in:
Carlos Valente
2023-09-11 21:03:11 +02:00
committed by GitHub
parent 1de3e01216
commit 93fb48ea1c
53 changed files with 1100 additions and 157 deletions
@@ -0,0 +1,111 @@
@use '../../../../src/theme/v2Styles' as *;
@use '../../../../src/theme/ontimeColours' as *;
@import '../Operator.module.scss';
@mixin clock-size {
font-size: calc(1rem - 2px);
@media (min-width: $min-tablet) {
font-size: 1rem;
}
}
.event {
opacity: 1;
border-top: 1px solid $white-1;
padding-right: 0.5rem;
color: $white-90;
background-color: $gray-1300;
display: grid;
align-items: center;
grid-template-columns: 1.25rem 1fr auto;
grid-template-rows: auto auto auto;
column-gap: 0.5rem;
grid-template-areas:
"binder main schedule"
"binder secondary running"
"binder fields fields";
&.subscribed {
background-color: $gray-1250;
}
&.running {
border-top: 1px solid $gray-1300;
background-color: var(--operator-running-bg-override, $red-700);
}
&.past {
border-top: 1px solid transparent;
opacity: 0.2;
}
}
.binder {
grid-area: binder;
color: $section-white;
height: 100%;
display: grid;
place-content: center;
position: relative;
background-color: $gray-1050; // to override inline
.cue {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
width: 6em;
rotate: -90deg;
letter-spacing: 0.5px;
}
}
.mainField {
grid-area: main;
font-size: 1.5rem;
letter-spacing: 0.5px;
color: $ui-white;
}
.secondaryField {
grid-area: secondary;
font-size: 1.25rem;
letter-spacing: 0.5px;
}
.schedule {
@include clock-size;
grid-area: schedule;
justify-self: end;
}
.running {
@include clock-size;
grid-area: running;
justify-self: end;
}
.fields {
grid-area: fields;
font-size: 1.25rem;
font-weight: 400;
color: $ui-black;
margin: 0.25rem 0;
.field {
font-weight: 600;
padding: 0 0.25rem;
background-color: var(--operator-highlight-override, $orange-600);
margin-right: 0.5rem;
}
.value {
color: $orange-500
}
}
.fields::after {
content: '\200b';
}
@@ -0,0 +1,92 @@
import { memo, RefObject } from 'react';
import DelayIndicator from '../../../common/components/delay-indicator/DelayIndicator';
import { useTimer } from '../../../common/hooks/useSocket';
import { cx, getAccessibleColour } from '../../../common/utils/styleUtils';
import { formatTime } from '../../../common/utils/time';
import style from './OperatorEvent.module.scss';
interface OperatorEventProps {
colour: string;
cue: string;
main: string;
secondary: string;
timeStart: number;
timeEnd: number;
duration: number;
delay?: number;
isSelected: boolean;
subscribed?: string;
subscribedAlias: string;
showSeconds: boolean;
isPast: boolean;
selectedRef?: RefObject<HTMLDivElement>;
}
// extract this to contain re-renders
function RollingTime() {
const timer = useTimer();
return <>{formatTime(timer.current, { showSeconds: true, format: 'hh:mm:ss' })}</>;
}
function OperatorEvent(props: OperatorEventProps) {
const {
colour,
cue,
main,
secondary,
timeStart,
timeEnd,
duration,
delay,
isSelected,
subscribed,
subscribedAlias,
showSeconds,
isPast,
selectedRef,
} = props;
const start = formatTime(timeStart, { showSeconds });
const end = formatTime(timeEnd, { showSeconds });
const cueColours = colour && getAccessibleColour(colour);
const operatorClasses = cx([
style.event,
isSelected ? style.running : null,
subscribed ? style.subscribed : null,
isPast ? style.past : null,
]);
return (
<div className={operatorClasses} ref={selectedRef}>
<div className={style.binder} style={{ ...cueColours }}>
<span className={style.cue}>{cue}</span>
</div>
<span className={style.mainField}>{main}</span>
<span className={style.schedule}>
{start} - {end}
</span>
<span className={style.secondaryField}>{secondary}</span>
<span className={style.running}>
<DelayIndicator delayValue={delay} />
{isSelected ? <RollingTime /> : formatTime(duration, { showSeconds: true, format: 'hh:mm:ss' })}
</span>
<div className={style.fields}>
{subscribed && (
<>
<span className={style.field}>{subscribedAlias}</span>
<span className={style.value}>{subscribed}</span>
</>
)}
</div>
</div>
);
}
export default memo(OperatorEvent);