diff --git a/client/src/common/components/countdown/Countdown.jsx b/client/src/common/components/countdown/Countdown.jsx index 8f1f3a3e9..8fcb76316 100644 --- a/client/src/common/components/countdown/Countdown.jsx +++ b/client/src/common/components/countdown/Countdown.jsx @@ -1,9 +1,8 @@ -import { useEffect, useState } from 'react'; +import { memo, useEffect, useState } from 'react'; import { formatDisplay } from '../../dateConfig'; import styles from './Countdown.module.css'; -export default function Countdown(props) { - const { time, small, hideZeroHours } = props; +const Countdown = ({ time, small, hideZeroHours }) => { const [clock, setClock] = useState(time); let display = '-- : -- : --'; @@ -20,4 +19,6 @@ export default function Countdown(props) { {display} ); -} +}; + +export default memo(Countdown); diff --git a/client/src/common/components/views/Paginator.module.css b/client/src/common/components/views/Paginator.module.css index de283765e..e52e2dcfc 100644 --- a/client/src/common/components/views/Paginator.module.css +++ b/client/src/common/components/views/Paginator.module.css @@ -1,5 +1,3 @@ -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;800&display=swap'); - .entries { display: flex; flex-direction: column; diff --git a/client/src/features/control/PlaybackButtons.jsx b/client/src/features/control/PlaybackButtons.jsx new file mode 100644 index 000000000..a25a783da --- /dev/null +++ b/client/src/features/control/PlaybackButtons.jsx @@ -0,0 +1,73 @@ +import { memo } from 'react'; +import style from './PlaybackControl.module.css'; +import StartIconBtn from '../../common/components/buttons/StartIconBtn'; +import PauseIconBtn from '../../common/components/buttons/PauseIconBtn'; +import PrevIconBtn from '../../common/components/buttons/PrevIconBtn'; +import NextIconBtn from '../../common/components/buttons/NextIconBtn'; +import RollIconBtn from '../../common/components/buttons/RollIconBtn'; +import UnloadIconBtn from '../../common/components/buttons/UnloadIconBtn'; +import ReloadIconButton from '../../common/components/buttons/ReloadIconBtn'; + +const areEqual = (prevProps, nextProps) => { + return ( + prevProps.playback === nextProps.playback && + prevProps.selectedId === nextProps.selectedId + ); +}; + +const Playback = ({ playback, selectedId, playbackControl }) => { + return ( +
+ playbackControl('start')} + disabled={!selectedId} + /> + playbackControl('pause')} + disabled={!selectedId} + /> + playbackControl('roll')} + /> +
+ ); +}; + +const Transport = ({ selectedId, playbackControl }) => { + return ( +
+ playbackControl('previous')} /> + playbackControl('next')} /> + playbackControl('unload')} + disabled={!selectedId} + /> + playbackControl('reload')} + disabled={!selectedId} + /> +
+ ); +}; + +const PlaybackButtons = (props) => { + const { playback, selectedId } = props; + return ( + <> + + + + ); +}; + +export default memo(PlaybackButtons, areEqual); diff --git a/client/src/features/control/PlaybackControl.jsx b/client/src/features/control/PlaybackControl.jsx index 36947fc76..3d74e69f8 100644 --- a/client/src/features/control/PlaybackControl.jsx +++ b/client/src/features/control/PlaybackControl.jsx @@ -4,13 +4,7 @@ import { stringFromMillis } from '../../common/dateConfig'; import { useEffect, useState } from 'react'; import { useSocket } from '../../app/context/socketContext'; import { Button } from '@chakra-ui/button'; -import StartIconBtn from '../../common/components/buttons/StartIconBtn'; -import PauseIconBtn from '../../common/components/buttons/PauseIconBtn'; -import PrevIconBtn from '../../common/components/buttons/PrevIconBtn'; -import NextIconBtn from '../../common/components/buttons/NextIconBtn'; -import RollIconBtn from '../../common/components/buttons/RollIconBtn'; -import UnloadIconBtn from '../../common/components/buttons/UnloadIconBtn'; -import ReloadIconButton from '../../common/components/buttons/ReloadIconBtn'; +import PlaybackButtons from './PlaybackButtons'; export default function PlaybackControl() { const socket = useSocket(); @@ -146,35 +140,11 @@ export default function PlaybackControl() { - -
- playbackControl('start')} - disabled={!selectedId} - /> - playbackControl('pause')} - disabled={!selectedId} - /> - playbackControl('roll')} - /> -
-
- playbackControl('previous')} /> - playbackControl('next')} /> - playbackControl('unload')} - disabled={!selectedId} - /> - playbackControl('reload')} - disabled={!selectedId} - /> -
+ ); } diff --git a/client/src/features/editors/Editor.jsx b/client/src/features/editors/Editor.jsx index b47a7636e..6b062a9ae 100644 --- a/client/src/features/editors/Editor.jsx +++ b/client/src/features/editors/Editor.jsx @@ -40,7 +40,7 @@ export default function Editor() {
- + {/* */}
diff --git a/client/src/features/editors/list/EventBlock.jsx b/client/src/features/editors/list/EventBlock.jsx index dc16ad949..1914af8a8 100644 --- a/client/src/features/editors/list/EventBlock.jsx +++ b/client/src/features/editors/list/EventBlock.jsx @@ -1,5 +1,5 @@ import { FiChevronDown, FiChevronUp, FiMoreVertical } from 'react-icons/fi'; -import { useState } from 'react'; +import { memo, useEffect, useState } from 'react'; import EventTimes from '../../../common/components/eventTimes/EventTimes'; import { showErrorToast } from '../../../common/helpers/toastManager'; import style from './Block.module.css'; @@ -9,13 +9,30 @@ import ActionButtons from './ActionButtons'; import VisibleIconBtn from '../../../common/components/buttons/VisibleIconBtn'; import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn'; -export default function EventBlock(props) { +const areEqual = (prevProps, nextProps) => { + let shouldNotRerender = + prevProps.data.revision === nextProps.data.revision && + prevProps.selected === nextProps.selected && + prevProps.next === nextProps.next; + console.log('debug memo2', shouldNotRerender); + return ( + prevProps.data.revision === nextProps.data.revision && + prevProps.selected === nextProps.selected && + prevProps.next === nextProps.next + ); +}; + +const EventBlock = (props) => { const { data, selected, next, delay, index, eventsHandler } = props; const [more, setMore] = useState(false); - // NOTE: cheating to add responsiveness const [visible, setVisible] = useState(data.isPublic || false); + // Set visibility indicator + useEffect(() => { + setVisible(data.isPublic); + }, [data.isPublic]); + const updateValues = (field, value) => { // validate field if (field in data) { @@ -56,7 +73,6 @@ export default function EventBlock(props) { const handleVisibleToggle = () => { let viz = !data.isPublic || !visible; - setVisible(viz); updateValues('isPublic', viz); }; @@ -85,13 +101,6 @@ export default function EventBlock(props) { submitHandler={handleTitleSubmit} underlined /> - + ) : (
@@ -129,4 +145,6 @@ export default function EventBlock(props) {
); -} +}; + +export default memo(EventBlock, areEqual); diff --git a/client/src/features/editors/list/EventList.jsx b/client/src/features/editors/list/EventList.jsx index edfe79a44..dfe2c8ccd 100644 --- a/client/src/features/editors/list/EventList.jsx +++ b/client/src/features/editors/list/EventList.jsx @@ -1,6 +1,6 @@ import style from './List.module.css'; -import { useEffect, useState } from 'react'; +import { Fragment, useEffect, useState } from 'react'; import { useSocket } from '../../../app/context/socketContext'; import tinykeys from 'tinykeys'; import Empty from '../../../common/state/Empty'; @@ -111,7 +111,7 @@ export default function EventList(props) { if (e.type === 'delay') cumulativeDelay += e.duration; else if (e.type === 'block') cumulativeDelay = 0; return ( -
+ )} -
+ ); })} diff --git a/client/src/features/menu/EventListMenu.jsx b/client/src/features/menu/EventListMenu.jsx index 8baf11a93..29aed0d5c 100644 --- a/client/src/features/menu/EventListMenu.jsx +++ b/client/src/features/menu/EventListMenu.jsx @@ -1,3 +1,4 @@ +import { memo, useCallback } from 'react'; import { FiChevronDown } from 'react-icons/fi'; import { Button, @@ -9,9 +10,9 @@ import { } from '@chakra-ui/react'; import AddIconBtn from '../../common/components/buttons/AddIconBtn'; import style from './EventListMenu.module.css'; +import MenuActionButtons from '../editors/list/MenuActionButtons'; -export default function EventListMenu(props) { - const { eventsHandler } = props; +const EventListMenu = ({ eventsHandler }) => { const buttonProps = { size: 'sm', variant: 'outline', @@ -27,9 +28,9 @@ export default function EventListMenu(props) { backgroundColor: 'rgba(255,255,255,0.67)', }; - const addHandler = () => { + const addHandler = useCallback(() => { eventsHandler('add', { type: 'event', order: 0 }); - }; + }, [eventsHandler]); return (
@@ -58,6 +59,9 @@ export default function EventListMenu(props) { + {/* */}
); -} +}; + +export default memo(EventListMenu); diff --git a/server/classes/EventTimer.js b/server/classes/EventTimer.js index 92ac96ab5..53153b225 100644 --- a/server/classes/EventTimer.js +++ b/server/classes/EventTimer.js @@ -1,5 +1,7 @@ const Timer = require('./Timer'); const socketIo = require('socket.io'); +// DEBUG +const { instrument } = require("@socket.io/admin-ui"); /* * EventTimer adds functions specific to APP @@ -71,6 +73,11 @@ class EventTimer extends Timer { }, }); + // DEBUG + instrument(this.io, { + auth: false + }); + // set recurrent emits this._interval = setInterval( () => this.broadcastTimer(), diff --git a/server/controllers/eventsController.js b/server/controllers/eventsController.js index 8d009a444..ac7b4196f 100644 --- a/server/controllers/eventsController.js +++ b/server/controllers/eventsController.js @@ -14,6 +14,7 @@ function incrementFrom(start, incr = 1) { db.get('events') .find({ id: e.id }) .assign({ order: e.order + incr }) + .update('revision', (n) => n + 1) .write(); }); } @@ -163,6 +164,7 @@ exports.eventsPatch = async (req, res) => { db.get('events') .find({ id: req.body.id }) .assign({ ...req.body }) + .update('revision', (n) => n + 1) .write(); // update timer diff --git a/server/data/eventsDefinition.js b/server/data/eventsDefinition.js index 8f4acd1f5..2599f7330 100644 --- a/server/data/eventsDefinition.js +++ b/server/data/eventsDefinition.js @@ -7,6 +7,7 @@ const event = { timeEnd: 0, isPublic: false, type: 'event', + revision: 0, }; const delay = {