mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 06:59:09 +00:00
V2 socket store (#254)
* refactor: create socket utility * refactor: ensure a single subscription to topics * refactor: replace usages of socket object with subscription store handler
This commit is contained in:
+16
-19
@@ -6,7 +6,6 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
|||||||
import ErrorBoundary from 'common/components/errorBoundary/ErrorBoundary';
|
import ErrorBoundary from 'common/components/errorBoundary/ErrorBoundary';
|
||||||
import { AppContextProvider } from 'common/context/AppContext';
|
import { AppContextProvider } from 'common/context/AppContext';
|
||||||
import { LoggingProvider } from 'common/context/LoggingContext';
|
import { LoggingProvider } from 'common/context/LoggingContext';
|
||||||
import SocketProvider from 'common/context/socketContext';
|
|
||||||
|
|
||||||
import { ontimeQueryClient } from './common/queryClient';
|
import { ontimeQueryClient } from './common/queryClient';
|
||||||
import theme from './theme/theme';
|
import theme from './theme/theme';
|
||||||
@@ -45,24 +44,22 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ChakraProvider resetCSS theme={theme}>
|
<ChakraProvider resetCSS theme={theme}>
|
||||||
<SocketProvider>
|
<LoggingProvider>
|
||||||
<LoggingProvider>
|
<QueryClientProvider client={ontimeQueryClient}>
|
||||||
<QueryClientProvider client={ontimeQueryClient}>
|
<AppContextProvider>
|
||||||
<AppContextProvider>
|
<BrowserRouter>
|
||||||
<BrowserRouter>
|
<div className='App'>
|
||||||
<div className='App'>
|
<ErrorBoundary>
|
||||||
<ErrorBoundary>
|
<Suspense fallback={null}>
|
||||||
<Suspense fallback={null}>
|
<AppRouter />
|
||||||
<AppRouter />
|
</Suspense>
|
||||||
</Suspense>
|
</ErrorBoundary>
|
||||||
</ErrorBoundary>
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
</div>
|
||||||
</div>
|
</BrowserRouter>
|
||||||
</BrowserRouter>
|
</AppContextProvider>
|
||||||
</AppContextProvider>
|
</QueryClientProvider>
|
||||||
</QueryClientProvider>
|
</LoggingProvider>
|
||||||
</LoggingProvider>
|
|
||||||
</SocketProvider>
|
|
||||||
</ChakraProvider>
|
</ChakraProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { lazy, useEffect } from 'react';
|
import { lazy, useEffect } from 'react';
|
||||||
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useSocketProvider } from './common/hooks/useSocketProvider';
|
|
||||||
import useAliases from './common/hooks-query/useAliases';
|
import useAliases from './common/hooks-query/useAliases';
|
||||||
import withSocket from './features/viewers/ViewWrapper';
|
import withSocket from './features/viewers/ViewWrapper';
|
||||||
|
|
||||||
@@ -36,7 +35,6 @@ const MessageControl = lazy(() => import('features/control/message/MessageContro
|
|||||||
const Info = lazy(() => import('features/info/InfoExport'));
|
const Info = lazy(() => import('features/info/InfoExport'));
|
||||||
|
|
||||||
export default function AppRouter() {
|
export default function AppRouter() {
|
||||||
useSocketProvider();
|
|
||||||
const { data } = useAliases();
|
const { data } = useAliases();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
export const STATIC_PORT = 4001;
|
export const STATIC_PORT = 4001;
|
||||||
|
|
||||||
|
// REST stuff
|
||||||
export const EVENT_TABLE = ['event'];
|
export const EVENT_TABLE = ['event'];
|
||||||
export const ALIASES = ['aliases'];
|
export const ALIASES = ['aliases'];
|
||||||
export const USERFIELDS = ['userFields'];
|
export const USERFIELDS = ['userFields'];
|
||||||
@@ -9,12 +11,13 @@ export const OSC_SETTINGS = ['oscSettings'];
|
|||||||
export const APP_SETTINGS = ['appSettings'];
|
export const APP_SETTINGS = ['appSettings'];
|
||||||
export const VIEW_SETTINGS = ['viewSettings'];
|
export const VIEW_SETTINGS = ['viewSettings'];
|
||||||
|
|
||||||
export const FEAT_RUNDOWN = ['feat-rundown'];
|
// websocket stuff
|
||||||
export const FEAT_MESSAGECONTROL = ['feat-messagecontrol'];
|
export const FEAT_CUESHEET = 'feat-cuesheet';
|
||||||
export const FEAT_PLAYBACKCONTROL = ['feat-playbackcontrol'];
|
export const FEAT_INFO = 'feat-info';
|
||||||
export const FEAT_INFO = ['feat-info'];
|
export const FEAT_MESSAGECONTROL = 'feat-messagecontrol';
|
||||||
export const FEAT_CUESHEET = ['feat-cuesheet'];
|
export const FEAT_PLAYBACKCONTROL = 'feat-playbackcontrol';
|
||||||
export const TIMER = ['ontime-timer'];
|
export const FEAT_RUNDOWN = 'feat-rundown';
|
||||||
|
export const TIMER = 'ontime-timer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description finds server path given the current location, it
|
* @description finds server path given the current location, it
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { createContext, ReactNode, useCallback, useEffect, useState } from 'reac
|
|||||||
import { generateId } from '../utils/generate_id';
|
import { generateId } from '../utils/generate_id';
|
||||||
import { nowInMillis, stringFromMillis } from '../utils/time';
|
import { nowInMillis, stringFromMillis } from '../utils/time';
|
||||||
|
|
||||||
import { useSocket } from './socketContext';
|
import socket from '../utils/socket';
|
||||||
|
|
||||||
type LOG_LEVEL = 'INFO' | 'WARN' | 'ERROR';
|
type LOG_LEVEL = 'INFO' | 'WARN' | 'ERROR';
|
||||||
type Log = {
|
type Log = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -40,15 +39,13 @@ export const LoggingContext = createContext<LoggingProviderState>({
|
|||||||
|
|
||||||
export const LoggingProvider = ({ children }: LoggingProviderProps) => {
|
export const LoggingProvider = ({ children }: LoggingProviderProps) => {
|
||||||
const MAX_MESSAGES = 100;
|
const MAX_MESSAGES = 100;
|
||||||
const socket = useSocket();
|
|
||||||
const [logData, setLogData] = useState<Log[]>([]);
|
const [logData, setLogData] = useState<Log[]>([]);
|
||||||
const origin = 'USER';
|
const origin = 'USER';
|
||||||
|
|
||||||
|
// todo: use react-query store
|
||||||
|
// todo: useSubscription or feature
|
||||||
// handle incoming messages
|
// handle incoming messages
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket == null) return;
|
|
||||||
|
|
||||||
// Ask for log data
|
|
||||||
socket.emit('get-logger');
|
socket.emit('get-logger');
|
||||||
|
|
||||||
socket.on('logger', (data: Log) => {
|
socket.on('logger', (data: Log) => {
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import { createContext, ReactNode, useContext, useEffect, useState } from 'react';
|
|
||||||
import { serverURL } from 'common/api/apiConstants';
|
|
||||||
import io, { Socket } from 'socket.io-client';
|
|
||||||
|
|
||||||
interface SocketProviderState {
|
|
||||||
socket: Socket | null;
|
|
||||||
emit: <T>(topic: string, payload?: T) => void;
|
|
||||||
on: <T>(topic: string, callback: (data: T) => void) => void;
|
|
||||||
off: (topic: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
type SocketProviderProps = {
|
|
||||||
children: ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SocketContext = createContext<SocketProviderState>({
|
|
||||||
socket: null,
|
|
||||||
emit: () => {},
|
|
||||||
on: () => {},
|
|
||||||
off: () => {}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const useSocket = () => {
|
|
||||||
return useContext(SocketContext);
|
|
||||||
};
|
|
||||||
|
|
||||||
function SocketProvider({ children }: SocketProviderProps) {
|
|
||||||
const [socket, setSocket] = useState<Socket | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const socketInstance = io(serverURL, { transports: ["websocket"] });
|
|
||||||
setSocket(socketInstance);
|
|
||||||
return () => {
|
|
||||||
socketInstance.disconnect();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SocketContext.Provider value={socket}>{children}</SocketContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SocketProvider;
|
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { ontimeQueryClient as queryClient } from 'common/queryClient';
|
||||||
|
import socket, { subscribeOnce } from 'common/utils/socket';
|
||||||
|
|
||||||
|
import {
|
||||||
|
FEAT_CUESHEET,
|
||||||
|
FEAT_INFO,
|
||||||
|
FEAT_MESSAGECONTROL,
|
||||||
|
FEAT_PLAYBACKCONTROL,
|
||||||
|
FEAT_RUNDOWN,
|
||||||
|
TIMER,
|
||||||
|
} from '../api/apiConstants';
|
||||||
|
|
||||||
|
function createSocketHook<T>(key: string, defaultValue: T | null = null) {
|
||||||
|
subscribeOnce<T>(key, (data) => queryClient.setQueryData([key], data));
|
||||||
|
|
||||||
|
// retrieves data from the cache or null if non-existent
|
||||||
|
// we need the null because useQuery can't receive undefined
|
||||||
|
const fetcher = () => (queryClient.getQueryData([key]) ?? defaultValue) as T | null;
|
||||||
|
|
||||||
|
return () => useQuery([key], fetcher, { placeholderData: defaultValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyRundown = {
|
||||||
|
selectEventId: null,
|
||||||
|
nextEventId: null,
|
||||||
|
playback: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRundownEditor = createSocketHook(FEAT_RUNDOWN, emptyRundown);
|
||||||
|
|
||||||
|
const emptyMessageControl = {
|
||||||
|
presenter: {
|
||||||
|
text: '',
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
public: {
|
||||||
|
text: '',
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
lower: {
|
||||||
|
text: '',
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
onAir: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMessageControl = createSocketHook(FEAT_MESSAGECONTROL, emptyMessageControl);
|
||||||
|
export const setMessage = () => ({
|
||||||
|
presenterText: (payload: string) => socket.emit('set-timer-message-text', payload),
|
||||||
|
presenterVisible: (payload: boolean) => socket.emit('set-timer-message-visible', payload),
|
||||||
|
publicText: (payload: string) => socket.emit('set-public-message-text', payload),
|
||||||
|
publicVisible: (payload: boolean) => socket.emit('set-public-message-visible', payload),
|
||||||
|
lowerText: (payload: string) => socket.emit('set-lower-message-text', payload),
|
||||||
|
lowerVisible: (payload: boolean) => socket.emit('set-lower-message-visible', payload),
|
||||||
|
onAir: (payload: boolean) => socket.emit('set-onAir', payload),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const emptyPlaybackControl = {
|
||||||
|
playback: 'stop',
|
||||||
|
selectedEventId: null,
|
||||||
|
numEvents: 0,
|
||||||
|
};
|
||||||
|
export const usePlaybackControl = createSocketHook(FEAT_PLAYBACKCONTROL, emptyPlaybackControl);
|
||||||
|
export const resetPlayback = () => {
|
||||||
|
const cacheData = queryClient.getQueryData([FEAT_PLAYBACKCONTROL]) as Record<string, unknown>;
|
||||||
|
|
||||||
|
queryClient.setQueryData([FEAT_PLAYBACKCONTROL], {
|
||||||
|
...cacheData,
|
||||||
|
playback: 'stop',
|
||||||
|
selectedEventId: null,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const setPlayback = {
|
||||||
|
start: () => socket.emit('set-start'),
|
||||||
|
pause: () => socket.emit('set-pause'),
|
||||||
|
roll: () => socket.emit('set-roll'),
|
||||||
|
previous: () => {
|
||||||
|
socket.emit('set-previous');
|
||||||
|
resetPlayback();
|
||||||
|
},
|
||||||
|
next: () => {
|
||||||
|
socket.emit('set-next');
|
||||||
|
resetPlayback();
|
||||||
|
},
|
||||||
|
stop: () => {
|
||||||
|
socket.emit('set-stop');
|
||||||
|
resetPlayback();
|
||||||
|
},
|
||||||
|
reload: () => {
|
||||||
|
socket.emit('set-reload');
|
||||||
|
resetPlayback();
|
||||||
|
},
|
||||||
|
delay: (amount: number) => {
|
||||||
|
socket.emit('set-delay', amount);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const emptyInfo = {
|
||||||
|
titles: {
|
||||||
|
titleNow: '',
|
||||||
|
subtitleNow: '',
|
||||||
|
presenterNow: '',
|
||||||
|
noteNow: '',
|
||||||
|
titleNext: '',
|
||||||
|
subtitleNext: '',
|
||||||
|
presenterNext: '',
|
||||||
|
noteNext: '',
|
||||||
|
},
|
||||||
|
playback: 'stop',
|
||||||
|
selectedEventId: null,
|
||||||
|
selectedEventIndex: null,
|
||||||
|
numEvents: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useInfoPanel = createSocketHook(FEAT_INFO, emptyInfo);
|
||||||
|
|
||||||
|
export const emptyCuesheet = {
|
||||||
|
selectedEventId: null,
|
||||||
|
titleNow: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCuesheet = createSocketHook(FEAT_CUESHEET, emptyCuesheet);
|
||||||
|
|
||||||
|
|
||||||
|
export const setEventPlayback = {
|
||||||
|
loadEvent: (eventId: string) => socket.emit('set-loadid', eventId),
|
||||||
|
startEvent: (eventId: string) => socket.emit('set-startid', eventId),
|
||||||
|
pause: () => socket.emit('set-pause'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const emptyTimer = {
|
||||||
|
clock: 0,
|
||||||
|
running: 0,
|
||||||
|
isNegative: false,
|
||||||
|
startedAt: null,
|
||||||
|
expectedFinish: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useTimer = createSocketHook(TIMER, emptyTimer);
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
import { useCallback, useEffect, useMemo } from 'react';
|
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
||||||
|
|
||||||
import {
|
|
||||||
FEAT_CUESHEET,
|
|
||||||
FEAT_INFO,
|
|
||||||
FEAT_MESSAGECONTROL,
|
|
||||||
FEAT_PLAYBACKCONTROL,
|
|
||||||
FEAT_RUNDOWN,
|
|
||||||
TIMER,
|
|
||||||
} from '../api/apiConstants';
|
|
||||||
import { useSocket } from '../context/socketContext';
|
|
||||||
|
|
||||||
export const useRundownProvider = () => {
|
|
||||||
const { data } = useQuery(FEAT_RUNDOWN, () => undefined, {
|
|
||||||
cacheTime: Infinity,
|
|
||||||
staleTime: Infinity,
|
|
||||||
});
|
|
||||||
const placeholder = useMemo(
|
|
||||||
() => ({
|
|
||||||
selectedEventId: null,
|
|
||||||
nextEventId: null,
|
|
||||||
playback: null,
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
return data ?? placeholder;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useMessageControlProvider = () => {
|
|
||||||
const socket = useSocket();
|
|
||||||
const { data } = useQuery(FEAT_MESSAGECONTROL, () => undefined, {
|
|
||||||
cacheTime: Infinity,
|
|
||||||
staleTime: Infinity,
|
|
||||||
});
|
|
||||||
const placeholder = useMemo(
|
|
||||||
() => ({
|
|
||||||
presenter: {
|
|
||||||
text: '',
|
|
||||||
visible: false,
|
|
||||||
},
|
|
||||||
public: {
|
|
||||||
text: '',
|
|
||||||
visible: false,
|
|
||||||
},
|
|
||||||
lower: {
|
|
||||||
text: '',
|
|
||||||
visible: false,
|
|
||||||
},
|
|
||||||
onAir: false,
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const returnData = data ?? placeholder;
|
|
||||||
|
|
||||||
const setMessage = useMemo(
|
|
||||||
() => ({
|
|
||||||
presenterText: (payload) => socket.emit('set-timer-message-text', payload),
|
|
||||||
presenterVisible: (payload) => socket.emit('set-timer-message-visible', payload),
|
|
||||||
publicText: (payload) => socket.emit('set-public-message-text', payload),
|
|
||||||
publicVisible: (payload) => socket.emit('set-public-message-visible', payload),
|
|
||||||
lowerText: (payload) => socket.emit('set-lower-message-text', payload),
|
|
||||||
lowerVisible: (payload) => socket.emit('set-lower-message-visible', payload),
|
|
||||||
onAir: (payload) => socket.emit('set-onAir', payload),
|
|
||||||
}),
|
|
||||||
[socket],
|
|
||||||
);
|
|
||||||
|
|
||||||
return { data: returnData, setMessage };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const usePlaybackControlProvider = () => {
|
|
||||||
const socket = useSocket();
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const { data } = useQuery(FEAT_PLAYBACKCONTROL, () => undefined, {
|
|
||||||
cacheTime: Infinity,
|
|
||||||
staleTime: Infinity,
|
|
||||||
});
|
|
||||||
const placeholder = useMemo(
|
|
||||||
() => ({
|
|
||||||
playback: 'stop',
|
|
||||||
selectedEventId: null,
|
|
||||||
numEvents: 0,
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const resetData = useCallback(() => {
|
|
||||||
queryClient.setQueryData(FEAT_PLAYBACKCONTROL, (data) => ({
|
|
||||||
...data,
|
|
||||||
playback: 'stop',
|
|
||||||
selectedEventId: null,
|
|
||||||
}));
|
|
||||||
}, [queryClient]);
|
|
||||||
|
|
||||||
const setPlayback = useMemo(
|
|
||||||
() => ({
|
|
||||||
start: () => socket.emit('set-start'),
|
|
||||||
pause: () => socket.emit('set-pause'),
|
|
||||||
roll: () => socket.emit('set-roll'),
|
|
||||||
previous: () => {
|
|
||||||
socket.emit('set-previous');
|
|
||||||
resetData();
|
|
||||||
},
|
|
||||||
next: () => {
|
|
||||||
socket.emit('set-next');
|
|
||||||
resetData();
|
|
||||||
},
|
|
||||||
stop: () => {
|
|
||||||
socket.emit('set-stop');
|
|
||||||
resetData();
|
|
||||||
},
|
|
||||||
reload: () => {
|
|
||||||
socket.emit('set-reload');
|
|
||||||
resetData();
|
|
||||||
},
|
|
||||||
delay: (amount) => {
|
|
||||||
socket.emit('set-delay', amount);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[resetData, socket],
|
|
||||||
);
|
|
||||||
|
|
||||||
const returnData = data ?? placeholder;
|
|
||||||
|
|
||||||
return { data: returnData, resetData, setPlayback };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useInfoProvider = () => {
|
|
||||||
const { data } = useQuery(FEAT_INFO, () => undefined, {
|
|
||||||
cacheTime: Infinity,
|
|
||||||
staleTime: Infinity,
|
|
||||||
});
|
|
||||||
const placeholder = useMemo(
|
|
||||||
() => ({
|
|
||||||
titles: {
|
|
||||||
titleNow: '',
|
|
||||||
subtitleNow: '',
|
|
||||||
presenterNow: '',
|
|
||||||
noteNow: '',
|
|
||||||
titleNext: '',
|
|
||||||
subtitleNext: '',
|
|
||||||
presenterNext: '',
|
|
||||||
noteNext: '',
|
|
||||||
},
|
|
||||||
playback: 'stop',
|
|
||||||
selectedEventId: null,
|
|
||||||
selectedEventIndex: null,
|
|
||||||
numEvents: 0,
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
return data ?? placeholder;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useCuesheetProvider = () => {
|
|
||||||
const { data } = useQuery(FEAT_CUESHEET, () => undefined, {
|
|
||||||
cacheTime: Infinity,
|
|
||||||
staleTime: Infinity,
|
|
||||||
});
|
|
||||||
const placeholder = useMemo(
|
|
||||||
() => ({
|
|
||||||
selectedEventId: null,
|
|
||||||
titleNow: '',
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return data ?? placeholder;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useTimerProvider = () => {
|
|
||||||
const { data } = useQuery(TIMER, () => undefined, {
|
|
||||||
cacheTime: Infinity,
|
|
||||||
staleTime: Infinity,
|
|
||||||
});
|
|
||||||
const placeholder = useMemo(
|
|
||||||
() => ({
|
|
||||||
clock: 0,
|
|
||||||
current: null,
|
|
||||||
secondaryTimer: null,
|
|
||||||
duration: null,
|
|
||||||
expectedFinish: null,
|
|
||||||
startedAt: null,
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
return data ?? placeholder;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useEventProvider = (eventId) => {
|
|
||||||
const socket = useSocket();
|
|
||||||
|
|
||||||
const setPlayback = useMemo(() => ({
|
|
||||||
loadEvent: () => socket.emit('set-loadid', eventId),
|
|
||||||
startEvent: () => socket.emit('set-startid', eventId),
|
|
||||||
pause: () => socket.emit('set-pause'),
|
|
||||||
}), [socket]);
|
|
||||||
|
|
||||||
return { setPlayback };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useSocketProvider = () => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const socket = useSocket();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!socket) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.emit('get-ontime-feat-eventlist');
|
|
||||||
socket.on('ontime-feat-rundown', (featureData) => {
|
|
||||||
queryClient.setQueryData(FEAT_RUNDOWN, () => featureData);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit('get-ontime-feat-messagecontrol');
|
|
||||||
socket.on('ontime-feat-messagecontrol', (featureData) => {
|
|
||||||
queryClient.setQueryData(FEAT_MESSAGECONTROL, () => featureData);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit('get-ontime-feat-playbackcontrol');
|
|
||||||
socket.on('ontime-feat-playbackcontrol', (featureData) => {
|
|
||||||
queryClient.setQueryData(FEAT_PLAYBACKCONTROL, () => featureData);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit('get-ontime-feat-info');
|
|
||||||
socket.on('ontime-feat-info', (featureData) => {
|
|
||||||
queryClient.setQueryData(FEAT_INFO, () => featureData);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit('get-ontime-feat-cuesheet');
|
|
||||||
socket.on('ontime-feat-cuesheet', (featureData) => {
|
|
||||||
queryClient.setQueryData(FEAT_CUESHEET, () => featureData);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit('get-ontime-timer');
|
|
||||||
socket.on('ontime-timer', (featureData) => {
|
|
||||||
queryClient.setQueryData(TIMER, () => featureData);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
socket.off('ontime-feat-rundown');
|
|
||||||
socket.off('ontime-feat-messagecontrol');
|
|
||||||
socket.off('ontime-feat-playbackcontrol');
|
|
||||||
socket.off('ontime-feat-info');
|
|
||||||
socket.off('ontime-feat-cuesheet');
|
|
||||||
socket.off('ontime-timer');
|
|
||||||
};
|
|
||||||
}, [queryClient, socket]);
|
|
||||||
};
|
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { useSocket } from '../context/socketContext';
|
import socket from '../utils/socket';
|
||||||
|
|
||||||
export default function useSubscription<T>(topic: string, initialState: T, requestString?: string) {
|
export default function useSubscription<T>(topic: string, initialState: T, requestString?: string) {
|
||||||
const socket = useSocket();
|
|
||||||
const [state, setState] = useState<T>(initialState);
|
const [state, setState] = useState<T>(initialState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!socket) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestString) {
|
if (requestString) {
|
||||||
socket.emit(requestString);
|
socket.emit(requestString);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { serverURL } from 'common/api/apiConstants';
|
||||||
|
import { io } from 'socket.io-client';
|
||||||
|
|
||||||
|
const socket = io(serverURL, { transports: ['websocket'] });
|
||||||
|
const subscriptions = new Set();
|
||||||
|
|
||||||
|
export function subscribeOnce<T>(key: string, callback: (data: T) => void, requestString?: string) {
|
||||||
|
if (subscriptions.has(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
subscriptions.add(key);
|
||||||
|
|
||||||
|
requestString ? socket.emit(requestString) : socket.emit(`get-${key}`);
|
||||||
|
socket.on(key, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default socket;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import SocketProvider from 'common/context/socketContext';
|
|
||||||
|
|
||||||
import { queryClientMock } from '../../../__mocks__/QueryClient.mock';
|
import { queryClientMock } from '../../../__mocks__/QueryClient.mock';
|
||||||
import MessageControl from '../message/MessageControl';
|
import MessageControl from '../message/MessageControl';
|
||||||
@@ -11,9 +10,7 @@ import MessageControl from '../message/MessageControl';
|
|||||||
const MockMessageControl = () => {
|
const MockMessageControl = () => {
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClientMock}>
|
<QueryClientProvider client={queryClientMock}>
|
||||||
<SocketProvider>
|
<MessageControl />
|
||||||
<MessageControl />
|
|
||||||
</SocketProvider>
|
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import SocketProvider from 'common/context/socketContext';
|
|
||||||
|
|
||||||
import { queryClientMock } from '../../../__mocks__/QueryClient.mock';
|
import { queryClientMock } from '../../../__mocks__/QueryClient.mock';
|
||||||
import PlaybackControl from '../playback/PlaybackControl';
|
import PlaybackControl from '../playback/PlaybackControl';
|
||||||
@@ -11,10 +10,8 @@ test('check that playback control renders', async () => {
|
|||||||
// render without failing
|
// render without failing
|
||||||
render(
|
render(
|
||||||
<QueryClientProvider client={queryClientMock}>
|
<QueryClientProvider client={queryClientMock}>
|
||||||
<SocketProvider>
|
<PlaybackControl />
|
||||||
<PlaybackControl />
|
</QueryClientProvider>,
|
||||||
</SocketProvider>
|
|
||||||
</QueryClientProvider>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Text labels for times
|
// Text labels for times
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { IoMicOffOutline } from '@react-icons/all-files/io5/IoMicOffOutline';
|
|||||||
import { IoMicSharp } from '@react-icons/all-files/io5/IoMicSharp';
|
import { IoMicSharp } from '@react-icons/all-files/io5/IoMicSharp';
|
||||||
|
|
||||||
import CopyTag from '../../../common/components/osc-tag/CopyTag';
|
import CopyTag from '../../../common/components/osc-tag/CopyTag';
|
||||||
import { useMessageControlProvider } from '../../../common/hooks/useSocketProvider';
|
import { setMessage, useMessageControl } from '../../../common/hooks/useSocket';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
import InputRow from './InputRow';
|
import InputRow from './InputRow';
|
||||||
@@ -11,7 +11,7 @@ import InputRow from './InputRow';
|
|||||||
import style from './MessageControl.module.scss';
|
import style from './MessageControl.module.scss';
|
||||||
|
|
||||||
export default function MessageControl() {
|
export default function MessageControl() {
|
||||||
const { data, setMessage } = useMessageControlProvider();
|
const { data } = useMessageControl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { IoPause } from '@react-icons/all-files/io5/IoPause';
|
|||||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||||
import { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline';
|
import { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline';
|
||||||
|
|
||||||
import { usePlaybackControlProvider } from '../../../common/hooks/useSocketProvider';
|
import { setPlayback } from '../../../common/hooks/useSocket';
|
||||||
import { Playstate } from '../../../common/models/OntimeTypes';
|
import { Playstate } from '../../../common/models/OntimeTypes';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
@@ -20,7 +20,6 @@ interface PlaybackProps {
|
|||||||
export default function Playback(props: PlaybackProps) {
|
export default function Playback(props: PlaybackProps) {
|
||||||
const { playback, selectedId, noEvents } = props;
|
const { playback, selectedId, noEvents } = props;
|
||||||
const isRolling = playback === 'roll';
|
const isRolling = playback === 'roll';
|
||||||
const { setPlayback } = usePlaybackControlProvider();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.playbackContainer}>
|
<div className={style.playbackContainer}>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { usePlaybackControlProvider } from '../../../common/hooks/useSocketProvider';
|
import { usePlaybackControl } from '../../../common/hooks/useSocket';
|
||||||
import { Playstate } from '../../../common/models/OntimeTypes';
|
import { Playstate } from '../../../common/models/OntimeTypes';
|
||||||
|
|
||||||
import PlaybackButtons from './PlaybackButtons';
|
import PlaybackButtons from './PlaybackButtons';
|
||||||
@@ -7,7 +7,7 @@ import PlaybackTimer from './PlaybackTimer';
|
|||||||
import style from './PlaybackControl.module.scss';
|
import style from './PlaybackControl.module.scss';
|
||||||
|
|
||||||
export default function PlaybackControl() {
|
export default function PlaybackControl() {
|
||||||
const { data } = usePlaybackControlProvider();
|
const { data } = usePlaybackControl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.mainContainer}>
|
<div className={style.mainContainer}>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import { Tooltip } from '@chakra-ui/react';
|
import { Tooltip } from '@chakra-ui/react';
|
||||||
import TimerDisplay from 'common/components/countdown/TimerDisplay';
|
import TimerDisplay from 'common/components/countdown/TimerDisplay';
|
||||||
|
|
||||||
import {
|
import { setPlayback, useTimer } from '../../../common/hooks/useSocket';
|
||||||
usePlaybackControlProvider,
|
|
||||||
useTimerProvider,
|
|
||||||
} from '../../../common/hooks/useSocketProvider';
|
|
||||||
import { Playstate } from '../../../common/models/OntimeTypes';
|
import { Playstate } from '../../../common/models/OntimeTypes';
|
||||||
import { millisToSeconds } from '../../../common/utils/dateConfig';
|
import { millisToSeconds } from '../../../common/utils/dateConfig';
|
||||||
import { stringFromMillis } from '../../../common/utils/time';
|
import { stringFromMillis } from '../../../common/utils/time';
|
||||||
@@ -21,8 +18,7 @@ interface PlaybackTimerProps {
|
|||||||
|
|
||||||
export default function PlaybackTimer(props: PlaybackTimerProps) {
|
export default function PlaybackTimer(props: PlaybackTimerProps) {
|
||||||
const { playback, selectedId } = props;
|
const { playback, selectedId } = props;
|
||||||
const { setPlayback } = usePlaybackControlProvider();
|
const { data: timerData } = useTimer();
|
||||||
const timerData = useTimerProvider();
|
|
||||||
const started = stringFromMillis(timerData.startedAt, true);
|
const started = stringFromMillis(timerData.startedAt, true);
|
||||||
const finish = stringFromMillis(timerData.expectedFinish, true);
|
const finish = stringFromMillis(timerData.expectedFinish, true);
|
||||||
const isRolling = playback === 'roll';
|
const isRolling = playback === 'roll';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { IoPlaySkipBack } from '@react-icons/all-files/io5/IoPlaySkipBack';
|
|||||||
import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward';
|
import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward';
|
||||||
import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
||||||
|
|
||||||
import { usePlaybackControlProvider } from '../../../common/hooks/useSocketProvider';
|
import { setPlayback } from '../../../common/hooks/useSocket';
|
||||||
import { Playstate } from '../../../common/models/OntimeTypes';
|
import { Playstate } from '../../../common/models/OntimeTypes';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
@@ -20,7 +20,6 @@ interface TransportProps {
|
|||||||
|
|
||||||
export default function Transport(props: TransportProps) {
|
export default function Transport(props: TransportProps) {
|
||||||
const { playback, selectedId, noEvents } = props;
|
const { playback, selectedId, noEvents } = props;
|
||||||
const { setPlayback } = usePlaybackControlProvider();
|
|
||||||
const isRolling = playback === 'roll';
|
const isRolling = playback === 'roll';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useInfoProvider } from '../../common/hooks/useSocketProvider';
|
import { useInfoPanel } from '../../common/hooks/useSocket';
|
||||||
|
|
||||||
import InfoLogger from './InfoLogger';
|
import InfoLogger from './InfoLogger';
|
||||||
import InfoNif from './InfoNif';
|
import InfoNif from './InfoNif';
|
||||||
@@ -7,7 +7,7 @@ import InfoTitle from './InfoTitle';
|
|||||||
import style from './Info.module.scss';
|
import style from './Info.module.scss';
|
||||||
|
|
||||||
export default function Info() {
|
export default function Info() {
|
||||||
const data = useInfoProvider();
|
const { data } = useInfoPanel();
|
||||||
|
|
||||||
const titlesNow = {
|
const titlesNow = {
|
||||||
title: data.titles.titleNow,
|
title: data.titles.titleNow,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import SocketProvider from 'common/context/socketContext';
|
|
||||||
|
|
||||||
import { queryClientMock } from '../../../__mocks__/QueryClient.mock';
|
import { queryClientMock } from '../../../__mocks__/QueryClient.mock';
|
||||||
import Info from '../Info';
|
import Info from '../Info';
|
||||||
@@ -10,10 +9,8 @@ test('check static info render', async () => {
|
|||||||
// render without failing
|
// render without failing
|
||||||
render(
|
render(
|
||||||
<QueryClientProvider client={queryClientMock}>
|
<QueryClientProvider client={queryClientMock}>
|
||||||
<SocketProvider>
|
<Info />
|
||||||
<Info />
|
</QueryClientProvider>,
|
||||||
</SocketProvider>
|
|
||||||
</QueryClientProvider>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Info titles
|
// Info titles
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import Empty from 'common/components/state/Empty';
|
import Empty from 'common/components/state/Empty';
|
||||||
import { CursorContext } from 'common/context/CursorContext';
|
import { CursorContext } from 'common/context/CursorContext';
|
||||||
import { useEventAction } from 'common/hooks/useEventAction';
|
import { useEventAction } from 'common/hooks/useEventAction';
|
||||||
import { useRundownProvider } from 'common/hooks/useSocketProvider';
|
import { useRundownEditor } from 'common/hooks/useSocket';
|
||||||
import { duplicateEvent } from 'common/utils/eventsManager';
|
import { duplicateEvent } from 'common/utils/eventsManager';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
@@ -23,6 +23,8 @@ import style from './Rundown.module.scss';
|
|||||||
|
|
||||||
export default function Rundown(props) {
|
export default function Rundown(props) {
|
||||||
const { entries } = props;
|
const { entries } = props;
|
||||||
|
// Todo: add selectedId and nextId to rundown editor hook
|
||||||
|
const { data } = useRundownEditor();
|
||||||
const { cursor, moveCursorUp, moveCursorDown, moveCursorTo, isCursorLocked } =
|
const { cursor, moveCursorUp, moveCursorDown, moveCursorTo, isCursorLocked } =
|
||||||
useContext(CursorContext);
|
useContext(CursorContext);
|
||||||
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
||||||
@@ -30,7 +32,6 @@ export default function Rundown(props) {
|
|||||||
const { addEvent, reorderEvent } = useEventAction();
|
const { addEvent, reorderEvent } = useEventAction();
|
||||||
const cursorRef = createRef();
|
const cursorRef = createRef();
|
||||||
const showQuickEntry = useAtomValue(showQuickEntryAtom);
|
const showQuickEntry = useAtomValue(showQuickEntryAtom);
|
||||||
const data = useRundownProvider();
|
|
||||||
const [selectedId] = useSubscription('selected-id', null);
|
const [selectedId] = useSubscription('selected-id', null);
|
||||||
const [nextId] = useSubscription('next-id', null);
|
const [nextId] = useSubscription('next-id', null);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import TooltipActionBtn from 'common/components/buttons/TooltipActionBtn';
|
|||||||
import { getAccessibleColour } from 'common/utils/styleUtils';
|
import { getAccessibleColour } from 'common/utils/styleUtils';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
|
||||||
import { useEventProvider } from '../../../common/hooks/useSocketProvider';
|
import { setEventPlayback } from '../../../common/hooks/useSocket';
|
||||||
import { Playstate } from '../../../common/models/OntimeTypes';
|
import { Playstate } from '../../../common/models/OntimeTypes';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
import { EventItemActions } from '../RundownEntry';
|
import { EventItemActions } from '../RundownEntry';
|
||||||
@@ -80,7 +80,6 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [openId, setOpenId] = useAtom(editorEventId);
|
const [openId, setOpenId] = useAtom(editorEventId);
|
||||||
const { setPlayback } = useEventProvider(eventId);
|
|
||||||
const [blockTitle, setBlockTitle] = useState<string>(title || '');
|
const [blockTitle, setBlockTitle] = useState<string>(title || '');
|
||||||
|
|
||||||
const binderColours = colour && getAccessibleColour(colour);
|
const binderColours = colour && getAccessibleColour(colour);
|
||||||
@@ -157,7 +156,7 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
icon={selected ? <IoPlayBackOutline /> : <IoReload />}
|
icon={selected ? <IoPlayBackOutline /> : <IoReload />}
|
||||||
disabled={skip}
|
disabled={skip}
|
||||||
{...blockBtnStyle}
|
{...blockBtnStyle}
|
||||||
clickHandler={() => setPlayback.loadEvent()}
|
clickHandler={() => setEventPlayback.loadEvent(eventId)}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
/>
|
/>
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
@@ -168,7 +167,7 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
disabled={skip}
|
disabled={skip}
|
||||||
{...blockBtnStyle}
|
{...blockBtnStyle}
|
||||||
variant={eventIsPlaying ? 'solid' : 'ghost'}
|
variant={eventIsPlaying ? 'solid' : 'ghost'}
|
||||||
clickHandler={() => setPlayback.startEvent()}
|
clickHandler={() => setEventPlayback.startEvent(eventId)}
|
||||||
backgroundColor={eventIsPlaying ? '#58A151' : undefined}
|
backgroundColor={eventIsPlaying ? '#58A151' : undefined}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import PropTypes from 'prop-types';
|
|||||||
|
|
||||||
import { TableSettingsContext } from '../../common/context/TableSettingsContext';
|
import { TableSettingsContext } from '../../common/context/TableSettingsContext';
|
||||||
import useFullscreen from '../../common/hooks/useFullscreen';
|
import useFullscreen from '../../common/hooks/useFullscreen';
|
||||||
import { useTimerProvider } from '../../common/hooks/useSocketProvider';
|
import { useTimer } from '../../common/hooks/useSocket';
|
||||||
import useEvent from '../../common/hooks-query/useEvent';
|
import useEvent from '../../common/hooks-query/useEvent';
|
||||||
import { formatDisplay, millisToSeconds } from '../../common/utils/dateConfig';
|
import { formatDisplay, millisToSeconds } from '../../common/utils/dateConfig';
|
||||||
import { formatTime } from '../../common/utils/time';
|
import { formatTime } from '../../common/utils/time';
|
||||||
@@ -22,7 +22,7 @@ import style from './Table.module.scss';
|
|||||||
export default function TableHeader({ handleCSVExport, featureData }) {
|
export default function TableHeader({ handleCSVExport, featureData }) {
|
||||||
const { followSelected, showSettings, toggleTheme, toggleSettings, toggleFollow } =
|
const { followSelected, showSettings, toggleTheme, toggleSettings, toggleFollow } =
|
||||||
useContext(TableSettingsContext);
|
useContext(TableSettingsContext);
|
||||||
const timer = useTimerProvider();
|
const { data: timer } = useTimer();
|
||||||
const { isFullScreen, toggleFullScreen } = useFullscreen();
|
const { isFullScreen, toggleFullScreen } = useFullscreen();
|
||||||
const { data: event } = useEvent();
|
const { data: event } = useEvent();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useCallback, useContext, useEffect } from 'react';
|
|||||||
import { requestPatchEvent } from '../../common/api/eventsApi';
|
import { requestPatchEvent } from '../../common/api/eventsApi';
|
||||||
import { TableSettingsContext } from '../../common/context/TableSettingsContext';
|
import { TableSettingsContext } from '../../common/context/TableSettingsContext';
|
||||||
import useMutateEvents from '../../common/hooks/useMutateEvents';
|
import useMutateEvents from '../../common/hooks/useMutateEvents';
|
||||||
import { useCuesheetProvider } from '../../common/hooks/useSocketProvider';
|
import { useCuesheet } from '../../common/hooks/useSocket';
|
||||||
import useRundown from '../../common/hooks-query/useRundown';
|
import useRundown from '../../common/hooks-query/useRundown';
|
||||||
import useUserFields from '../../common/hooks-query/useUserFields';
|
import useUserFields from '../../common/hooks-query/useUserFields';
|
||||||
|
|
||||||
@@ -16,10 +16,10 @@ import style from './Table.module.scss';
|
|||||||
export default function TableWrapper() {
|
export default function TableWrapper() {
|
||||||
const { data: events } = useRundown();
|
const { data: events } = useRundown();
|
||||||
const { data: userFields } = useUserFields();
|
const { data: userFields } = useUserFields();
|
||||||
|
const { data: featureData } = useCuesheet();
|
||||||
|
|
||||||
const mutation = useMutateEvents(requestPatchEvent);
|
const mutation = useMutateEvents(requestPatchEvent);
|
||||||
const { theme } = useContext(TableSettingsContext);
|
const { theme } = useContext(TableSettingsContext);
|
||||||
const featureData = useCuesheetProvider();
|
|
||||||
|
|
||||||
// Set window title
|
// Set window title
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'ontime - Cuesheet';
|
document.title = 'ontime - Cuesheet';
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { useSocket } from '../../common/context/socketContext';
|
import { useMessageControl } from '../../common/hooks/useSocket';
|
||||||
import { useMessageControlProvider } from '../../common/hooks/useSocketProvider';
|
|
||||||
import useSubscription from '../../common/hooks/useSubscription';
|
import useSubscription from '../../common/hooks/useSubscription';
|
||||||
import useEvent from '../../common/hooks-query/useEvent';
|
import useEvent from '../../common/hooks-query/useEvent';
|
||||||
import useRundown from '../../common/hooks-query/useRundown';
|
import useRundown from '../../common/hooks-query/useRundown';
|
||||||
import useViewSettings from '../../common/hooks-query/useViewSettings';
|
import useViewSettings from '../../common/hooks-query/useViewSettings';
|
||||||
|
import socket from '../../common/utils/socket';
|
||||||
|
|
||||||
const withSocket = (Component) => {
|
const withSocket = (Component) => {
|
||||||
return (props) => {
|
return (props) => {
|
||||||
const { data: eventsData } = useRundown();
|
const { data: eventsData } = useRundown();
|
||||||
const { data: genData } = useEvent();
|
const { data: genData } = useEvent();
|
||||||
const { data: viewSettings } = useViewSettings();
|
const { data: viewSettings } = useViewSettings();
|
||||||
const { data: messages } = useMessageControlProvider();
|
const { data: messages } = useMessageControl();
|
||||||
|
|
||||||
const socket = useSocket();
|
|
||||||
const [publicSelectedId, setPublicSelectedId] = useState(null);
|
const [publicSelectedId, setPublicSelectedId] = useState(null);
|
||||||
|
|
||||||
const [timer] = useSubscription('timer', {
|
const [timer] = useSubscription('timer', {
|
||||||
@@ -44,13 +43,9 @@ const withSocket = (Component) => {
|
|||||||
const [selectedId] = useSubscription('selected-id', null);
|
const [selectedId] = useSubscription('selected-id', null);
|
||||||
const [nextId] = useSubscription('next-id', null);
|
const [nextId] = useSubscription('next-id', null);
|
||||||
const [playback] = useSubscription('playstate', null);
|
const [playback] = useSubscription('playstate', null);
|
||||||
const [onAir] = useSubscription('onAir', false);
|
|
||||||
|
|
||||||
// Ask for update on load
|
// Ask for update on load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!socket) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// todo: remove
|
// todo: remove
|
||||||
socket.on('publicselected-id', (data) => {
|
socket.on('publicselected-id', (data) => {
|
||||||
setPublicSelectedId(data);
|
setPublicSelectedId(data);
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export class EventTimer extends Timer {
|
|||||||
nextEventId: this.nextEventId,
|
nextEventId: this.nextEventId,
|
||||||
playback: this.state,
|
playback: this.state,
|
||||||
};
|
};
|
||||||
this.socket.send('ontime-feat-rundown', featureData);
|
this.socket.send('feat-rundown', featureData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,7 +149,7 @@ export class EventTimer extends Timer {
|
|||||||
selectedEventId: this.selectedEventId,
|
selectedEventId: this.selectedEventId,
|
||||||
numEvents: this.rundown.length,
|
numEvents: this.rundown.length,
|
||||||
};
|
};
|
||||||
this.socket.send('ontime-feat-playbackcontrol', featureData);
|
this.socket.send('feat-playbackcontrol', featureData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -164,7 +164,7 @@ export class EventTimer extends Timer {
|
|||||||
selectedEventIndex: this.selectedEventIndex,
|
selectedEventIndex: this.selectedEventIndex,
|
||||||
numEvents: this.rundown.length,
|
numEvents: this.rundown.length,
|
||||||
};
|
};
|
||||||
this.socket.send('ontime-feat-info', featureData);
|
this.socket.send('feat-info', featureData);
|
||||||
}
|
}
|
||||||
|
|
||||||
_broadcastFeatureCuesheet() {
|
_broadcastFeatureCuesheet() {
|
||||||
@@ -175,7 +175,7 @@ export class EventTimer extends Timer {
|
|||||||
numEvents: this.rundown.length,
|
numEvents: this.rundown.length,
|
||||||
titleNow: this.titles.titleNow,
|
titleNow: this.titles.titleNow,
|
||||||
};
|
};
|
||||||
this.socket.send('ontime-feat-cuesheet', featureData);
|
this.socket.send('feat-cuesheet', featureData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user