refactor: improve performance on EventBlock

This commit is contained in:
cv
2023-04-06 14:42:34 +02:00
parent 4c4b83979d
commit ba62276951
5 changed files with 126 additions and 69 deletions
@@ -4,26 +4,21 @@ import { IoCaretDownCircle } from '@react-icons/all-files/io5/IoCaretDownCircle'
import { IoCaretUpCircle } from '@react-icons/all-files/io5/IoCaretUpCircle';
import { IoOptions } from '@react-icons/all-files/io5/IoOptions';
import { IoPeople } from '@react-icons/all-files/io5/IoPeople';
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
import { IoPlayCircle } from '@react-icons/all-files/io5/IoPlayCircle';
import { IoPlayForwardCircle } from '@react-icons/all-files/io5/IoPlayForwardCircle';
import { IoPlayOutline } from '@react-icons/all-files/io5/IoPlayOutline';
import { IoPlaySkipForwardCircle } from '@react-icons/all-files/io5/IoPlaySkipForwardCircle';
import { IoReload } from '@react-icons/all-files/io5/IoReload';
import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle';
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
import { IoStopCircle } from '@react-icons/all-files/io5/IoStopCircle';
import { IoTime } from '@react-icons/all-files/io5/IoTime';
import { EndAction, Playback, TimerType } from 'ontime-types';
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
import { setEventPlayback } from '../../../common/hooks/useSocket';
import { useEventEditorStore } from '../../../common/stores/eventEditor';
import { tooltipDelayMid } from '../../../ontimeConfig';
import EditableBlockTitle from '../common/EditableBlockTitle';
import { EventItemActions } from '../RundownEntry';
import BlockActionMenu from './composite/BlockActionMenu';
import EventBlockPlayback from './composite/EventBlockPlayback';
import EventBlockProgressBar from './composite/EventBlockProgressBar';
import EventBlockTimers from './composite/EventBlockTimers';
@@ -104,49 +99,13 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
return !renderInner ? null : (
<>
<div className={style.playbackActions}>
<TooltipActionBtn
variant='ontime-subtle-white'
aria-label='Skip event'
tooltip='Skip event'
icon={skip ? <IoRemoveCircle /> : <IoRemoveCircleOutline />}
{...tooltipProps}
{...blockBtnStyle}
clickHandler={() => actionHandler('update', { field: 'skip', value: !skip })}
tabIndex={-1}
disabled={selected}
/>
<TooltipActionBtn
variant='ontime-subtle-white'
aria-label='Load event'
tooltip='Load event'
icon={<IoReload className={style.flip} />}
disabled={skip}
{...tooltipProps}
{...blockBtnStyle}
clickHandler={() => setEventPlayback.loadEvent(eventId)}
tabIndex={-1}
/>
<TooltipActionBtn
variant='ontime-subtle-white'
aria-label='Start event'
tooltip='Start event'
icon={eventIsPlaying ? <IoPlay /> : <IoPlayOutline />}
disabled={skip}
{...tooltipProps}
{...blockBtnStyle}
clickHandler={() => setEventPlayback.startEvent(eventId)}
backgroundColor={eventIsPlaying ? '#58A151' : undefined}
_hover={{ backgroundColor: eventIsPlaying ? '#58A151' : undefined }}
tabIndex={-1}
/>
</div>
<EventBlockPlayback eventId={eventId} skip={skip} isPlaying={eventIsPlaying} selected={selected} />
<EventBlockTimers
eventId={eventId}
timeStart={timeStart}
timeEnd={timeEnd}
duration={duration}
delay={delay}
actionHandler={actionHandler}
previousEnd={previousEnd}
/>
<EditableBlockTitle title={title} eventId={eventId} placeholder='Event title' className={style.eventTitle} />
@@ -0,0 +1,79 @@
import { memo } from 'react';
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
import { IoPlayOutline } from '@react-icons/all-files/io5/IoPlayOutline';
import { IoReload } from '@react-icons/all-files/io5/IoReload';
import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle';
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
import TooltipActionBtn from '../../../../common/components/buttons/TooltipActionBtn';
import { useEventAction } from '../../../../common/hooks/useEventAction';
import { setEventPlayback } from '../../../../common/hooks/useSocket';
import { tooltipDelayMid } from '../../../../ontimeConfig';
import style from '../EventBlock.module.scss';
const blockBtnStyle = {
size: 'sm',
};
const tooltipProps = {
openDelay: tooltipDelayMid,
};
interface EventBlockPlaybackProps {
eventId: string;
skip: boolean;
isPlaying: boolean;
selected: boolean;
}
const EventBlockPlayback = (props: EventBlockPlaybackProps) => {
const { eventId, skip, isPlaying, selected } = props;
const { updateEvent } = useEventAction();
const toggleSkip = () => {
updateEvent({ id: eventId, skip: !skip });
};
return (
<div className={style.playbackActions}>
<TooltipActionBtn
variant='ontime-subtle-white'
aria-label='Skip event'
tooltip='Skip event'
icon={skip ? <IoRemoveCircle /> : <IoRemoveCircleOutline />}
{...tooltipProps}
{...blockBtnStyle}
clickHandler={toggleSkip}
tabIndex={-1}
isDisabled={selected}
/>
<TooltipActionBtn
variant='ontime-subtle-white'
aria-label='Load event'
tooltip='Load event'
icon={<IoReload className={style.flip} />}
isDisabled={skip}
{...tooltipProps}
{...blockBtnStyle}
clickHandler={() => setEventPlayback.loadEvent(eventId)}
tabIndex={-1}
/>
<TooltipActionBtn
variant='ontime-subtle-white'
aria-label='Start event'
tooltip='Start event'
icon={isPlaying ? <IoPlay /> : <IoPlayOutline />}
isDisabled={skip}
{...tooltipProps}
{...blockBtnStyle}
clickHandler={() => setEventPlayback.startEvent(eventId)}
backgroundColor={isPlaying ? '#58A151' : undefined}
_hover={{ backgroundColor: isPlaying ? '#58A151' : undefined }}
tabIndex={-1}
/>
</div>
);
};
export default memo(EventBlockPlayback);
@@ -1,28 +1,53 @@
import { useCallback, useState } from 'react';
import { memo, useCallback, useState } from 'react';
import { OntimeEvent } from 'ontime-types';
import { millisToString } from 'ontime-utils';
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
import { useEventAction } from '../../../../common/hooks/useEventAction';
import { millisToMinutes } from '../../../../common/utils/dateConfig';
import { TimeEntryField, validateEntry } from '../../../../common/utils/timesManager';
import { EventItemActions } from '../../RundownEntry';
import { calculateDuration, TimeEntryField, validateEntry } from '../../../../common/utils/timesManager';
import style from '../EventBlock.module.scss';
interface EventBlockTimerProps {
eventId: string;
timeStart: number;
timeEnd: number;
duration: number;
delay: number;
actionHandler: (action: EventItemActions, payload?: any) => void;
previousEnd: number;
}
export default function EventBlockTimers(props: EventBlockTimerProps) {
const { timeStart, timeEnd, duration, delay, actionHandler, previousEnd } = props;
type TimeActions = 'timeStart' | 'timeEnd' | 'durationOverride';
const EventBlockTimers = (props: EventBlockTimerProps) => {
const { eventId, timeStart, timeEnd, duration, delay, previousEnd } = props;
const { updateEvent } = useEventAction();
const [warning, setWarnings] = useState({ start: '', end: '', duration: '' });
const delayTime = `${delay >= 0 ? '+' : '-'} ${millisToMinutes(Math.abs(delay))}`;
const newTime = millisToString(timeStart + delay);
const handleSubmit = (field: TimeActions, value: number) => {
const newEventData: Partial<OntimeEvent> = { id: eventId };
switch (field) {
case 'durationOverride': {
// duration defines timeEnd
newEventData.duration = value;
newEventData.timeEnd = timeStart + value;
break;
}
case 'timeStart': {
newEventData.duration = calculateDuration(value, timeEnd);
newEventData.timeStart = value;
break;
}
case 'timeEnd': {
newEventData.duration = calculateDuration(timeStart, value);
newEventData.timeEnd = value;
break;
}
}
updateEvent(newEventData);
};
/**
* @description Validates a time input against its pair
@@ -39,12 +64,8 @@ export default function EventBlockTimers(props: EventBlockTimerProps) {
[timeEnd, timeStart],
);
const handleSubmit = useCallback(
(field: TimeEntryField, value: number) => {
actionHandler('update', { field, value });
},
[actionHandler],
);
const delayTime = `${delay >= 0 ? '+' : '-'} ${millisToMinutes(Math.abs(delay))}`;
const newTime = millisToString(timeStart + delay);
return (
<div className={style.eventTimers}>
@@ -86,4 +107,6 @@ export default function EventBlockTimers(props: EventBlockTimerProps) {
)}
</div>
);
}
};
export default memo(EventBlockTimers);
@@ -1,4 +1,4 @@
import { useCallback, useRef } from 'react';
import { memo, useCallback, useRef } from 'react';
import { Button, Checkbox, Tooltip } from '@chakra-ui/react';
import { SupportedEvent } from 'ontime-types';
@@ -17,7 +17,7 @@ interface QuickAddBlockProps {
disableAddBlock: boolean;
}
export default function QuickAddBlock(props: QuickAddBlockProps) {
const QuickAddBlock = (props: QuickAddBlockProps) => {
const { showKbd, eventId, previousEventId, disableAddDelay = true, disableAddBlock } = props;
const { addEvent } = useEventAction();
const { emitError } = useEmitLog();
@@ -117,4 +117,6 @@ export default function QuickAddBlock(props: QuickAddBlockProps) {
</div>
</div>
);
}
};
export default memo(QuickAddBlock);