diff --git a/src/components/App.jsx b/src/components/App.jsx
index 05df8b6..75256a6 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -19,8 +19,8 @@ import WindowManager from './WindowManager';
const iconContextValue = { style: { verticalAlign: 'middle' } };
-const App = ({ store }) => (
-
+const App = () => (
+ <>
@@ -32,12 +32,16 @@ const App = ({ store }) => (
-
+ >
);
function renderApp(domParent, store) {
const root = createRoot(domParent);
- root.render();
+ root.render(
+
+
+ ,
+ );
}
export default renderApp;
diff --git a/src/components/AppWin.jsx b/src/components/AppWin.jsx
index 7cd6f7b..ea9838a 100644
--- a/src/components/AppWin.jsx
+++ b/src/components/AppWin.jsx
@@ -12,18 +12,22 @@ import UIWin from './UIWin';
const iconContextValue = { style: { verticalAlign: 'middle' } };
-const AppWin = ({ store }) => (
-
+const AppWin = () => (
+ <>
-
+ >
);
function renderAppWin(domParent, store) {
const root = createRoot(domParent);
- root.render();
+ root.render(
+
+
+ ,
+ );
}
export default renderAppWin;
diff --git a/src/components/ChatMessage.jsx b/src/components/ChatMessage.jsx
index c3b77fc..d3bc685 100644
--- a/src/components/ChatMessage.jsx
+++ b/src/components/ChatMessage.jsx
@@ -1,7 +1,6 @@
import React, { useRef } from 'react';
-import { useSelector, useDispatch } from 'react-redux';
+import { useSelector } from 'react-redux';
-import { showContextMenu } from '../store/actions';
import { MarkdownParagraph } from './Markdown';
import {
colorFromText,
@@ -11,19 +10,20 @@ import {
import { parseParagraph } from '../core/MarkdownParser';
+const selectStyle = (state) => state.gui.style.indexOf('dark') !== -1;
+
function ChatMessage({
name,
uid,
country,
- windowId,
msg,
ts,
+ openCm,
}) {
- const dispatch = useDispatch();
const isDarkMode = useSelector(
- (state) => state.gui.style.indexOf('dark') !== -1,
+ selectStyle,
);
- const refEmbed = useRef(null);
+ const refEmbed = useRef();
const isInfo = (name === 'info');
const isEvent = (name === 'event');
@@ -66,15 +66,7 @@ function ChatMessage({
title={name}
tabIndex={-1}
onClick={(event) => {
- const {
- clientX,
- clientY,
- } = event;
- dispatch(showContextMenu('USER', clientX, clientY, {
- windowId,
- uid,
- name,
- }));
+ openCm(event.clientX, event.clientY, name, uid);
}}
>
{name}
diff --git a/src/components/MdLink.jsx b/src/components/MdLink.jsx
index 15f1e64..bc26e0f 100644
--- a/src/components/MdLink.jsx
+++ b/src/components/MdLink.jsx
@@ -89,7 +89,7 @@ const MdLink = ({ href, title, refEmbed }) => {
>
)}
{showEmbed && embedAvailable && (
- (refEmbed)
+ (refEmbed && refEmbed.current)
? ReactDOM.createPortal(
,
refEmbed.current,
diff --git a/src/components/UI.jsx b/src/components/UI.jsx
index b8aaf63..8b1d480 100644
--- a/src/components/UI.jsx
+++ b/src/components/UI.jsx
@@ -13,25 +13,18 @@ import Palette from './Palette';
import Alert from './Alert';
import HistorySelect from './HistorySelect';
import Mobile3DControls from './Mobile3DControls';
-import ContextMenues from './contextmenus';
const UI = () => {
const [
isHistoricalView,
is3D,
isOnMobile,
- menuOpen,
- menuType,
] = useSelector((state) => [
state.canvas.isHistoricalView,
state.canvas.is3D,
state.user.isOnMobile,
- state.contextMenu.menuOpen,
- state.contextMenu.menuType,
], shallowEqual);
- const ContextMenu = menuOpen && menuType && ContextMenues[menuType];
-
return (
<>
@@ -47,7 +40,6 @@ const UI = () => {
>
)}
- {ContextMenu && }
>
);
};
diff --git a/src/components/Window.jsx b/src/components/Window.jsx
index 127f7b9..b45b6c0 100644
--- a/src/components/Window.jsx
+++ b/src/components/Window.jsx
@@ -16,10 +16,13 @@ import {
toggleMaximizeWindow,
cloneWindow,
focusWindow,
+ setWindowTitle,
+ setWindowArgs,
} from '../store/actions/windows';
import {
makeSelectWindowById,
makeSelectWindowPosById,
+ makeSelectWindowArgs,
selectShowWindows,
} from '../store/selectors/windows';
import useDrag from './hooks/drag';
@@ -28,17 +31,26 @@ import COMPONENTS from './windows';
const Window = ({ id }) => {
const [render, setRender] = useState(false);
- const titleBarRef = useRef(null);
- const resizeRef = useRef(null);
+ const titleBarRef = useRef();
+ const resizeRef = useRef();
const selectWindowById = useMemo(() => makeSelectWindowById(id), []);
const selectWIndowPosById = useMemo(() => makeSelectWindowPosById(id), []);
+ const selectWindowArgs = useMemo(() => makeSelectWindowArgs(id), []);
const win = useSelector(selectWindowById);
const position = useSelector(selectWIndowPosById);
const showWindows = useSelector(selectShowWindows);
+ const args = useSelector(selectWindowArgs);
const dispatch = useDispatch();
+ const setArgs = useCallback(
+ (newArgs) => dispatch(setWindowArgs(id, newArgs),
+ ), [dispatch]);
+ const setTitle = useCallback(
+ (title) => dispatch(setWindowTitle(id, title),
+ ), [dispatch]);
+
const {
open,
hidden,
@@ -156,7 +168,7 @@ const Window = ({ id }) => {
className="modal-content"
key="content"
>
-
+
);
@@ -224,7 +236,7 @@ const Window = ({ id }) => {
className="win-content"
key="content"
>
-
+
);
diff --git a/src/components/buttons/ChatButton.jsx b/src/components/buttons/ChatButton.jsx
index 23f30f3..7f7cf7e 100644
--- a/src/components/buttons/ChatButton.jsx
+++ b/src/components/buttons/ChatButton.jsx
@@ -36,7 +36,7 @@ const ChatButton = () => {
shallowEqual,
);
- const chatNotify = useSelector((state) => state.audio.chatNotify);
+ const chatNotify = useSelector((state) => state.gui.chatNotify);
const channels = useSelector((state) => state.chat.channels);
const [unread, mute] = useSelector((state) => [
state.chatRead.unread,
diff --git a/src/components/contextmenus/ChannelContextMenu.jsx b/src/components/contextmenus/ChannelContextMenu.jsx
index 0eff8fa..2433ebf 100644
--- a/src/components/contextmenus/ChannelContextMenu.jsx
+++ b/src/components/contextmenus/ChannelContextMenu.jsx
@@ -2,15 +2,11 @@
*
*/
-import React, { useRef, useCallback } from 'react';
+import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { t } from 'ttag';
import {
- useClickOutside,
-} from '../hooks/clickOutside';
-import {
- hideContextMenu,
muteChatChannel,
unmuteChatChannel,
} from '../../store/actions';
@@ -18,31 +14,25 @@ import {
setLeaveChannel,
} from '../../store/actions/thunks';
-const ChannelContextMenu = () => {
- const wrapperRef = useRef(null);
-
+/*
+ * args: {
+ * cid,
+ * }
+ */
+const ChannelContextMenu = ({ args, close }) => {
const channels = useSelector((state) => state.chat.channels);
const muteArr = useSelector((state) => state.chatRead.mute);
- const { xPos, yPos, args } = useSelector((state) => state.contextMenu);
+
const { cid } = args;
const dispatch = useDispatch();
- const close = useCallback(() => dispatch(hideContextMenu()), [dispatch]);
-
- useClickOutside([wrapperRef], close);
const isMuted = muteArr.includes(cid);
return (
-
+ <>
{
if (isMuted) {
dispatch(unmuteChatChannel(cid));
@@ -58,6 +48,7 @@ const ChannelContextMenu = () => {
{(channels[cid][1] !== 0)
&& (
{
dispatch(setLeaveChannel(cid));
@@ -68,7 +59,7 @@ const ChannelContextMenu = () => {
{t`Close`}
)}
-
+ >
);
};
diff --git a/src/components/contextmenus/ChannelDropDown.jsx b/src/components/contextmenus/ChannelDropDown.jsx
index 2f11869..cfc686a 100644
--- a/src/components/contextmenus/ChannelDropDown.jsx
+++ b/src/components/contextmenus/ChannelDropDown.jsx
@@ -32,7 +32,7 @@ const ChannelDropDown = ({
const unread = useSelector((state) => state.chatRead.unread);
const mute = useSelector((state) => state.chatRead.mute);
const channels = useSelector((state) => state.chat.channels);
- const chatNotify = useSelector((state) => state.audio.chatNotify);
+ const chatNotify = useSelector((state) => state.gui.chatNotify);
useEffect(() => {
setOffset(buttonRef.current.clientHeight);
diff --git a/src/components/contextmenus/UserContextMenu.jsx b/src/components/contextmenus/UserContextMenu.jsx
index 0a57f3a..53e1884 100644
--- a/src/components/contextmenus/UserContextMenu.jsx
+++ b/src/components/contextmenus/UserContextMenu.jsx
@@ -2,57 +2,46 @@
*
*/
-import React, { useRef } from 'react';
+import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { t } from 'ttag';
-import {
- useClickOutside,
-} from '../hooks/clickOutside';
-import {
- hideContextMenu,
-} from '../../store/actions';
import {
startDm,
setUserBlock,
} from '../../store/actions/thunks';
-import {
- addToChatInputMessage,
- setWindowArgs,
-} from '../../store/actions/windows';
import { escapeMd } from '../../core/utils';
-const UserContextMenu = () => {
- const wrapperRef = useRef(null);
-
- const { xPos, yPos, args } = useSelector((state) => state.contextMenu);
- const { windowId, name, uid } = args;
-
+/*
+ * args: {
+ * name,
+ * uid,
+ * setChannel,
+ * addToInput,
+ * }
+ */
+const UserContextMenu = ({ args, close }) => {
const channels = useSelector((state) => state.chat.channels);
const fetching = useSelector((state) => state.fetching.fetchingApi);
const dispatch = useDispatch();
- const close = () => dispatch(hideContextMenu());
- useClickOutside([wrapperRef], close);
+ const {
+ name,
+ uid,
+ setChannel,
+ addToInput,
+ } = args;
return (
-
+ <>
{
const ping = `@[${escapeMd(name)}](${uid})`;
- dispatch(
- addToChatInputMessage(windowId, ping),
- );
+ addToInput(ping);
close();
}}
style={{ borderTop: 'none' }}
@@ -61,6 +50,7 @@ const UserContextMenu = () => {
{
/*
@@ -71,15 +61,13 @@ const UserContextMenu = () => {
for (let i = 0; i < cids.length; i += 1) {
const cid = cids[i];
if (channels[cid].length === 4 && channels[cid][3] === uid) {
- dispatch(setWindowArgs(windowId, {
- chatChannel: cid,
- }));
+ setChannel(cid);
close();
return;
}
}
if (!fetching) {
- dispatch(startDm(windowId, { userId: uid }));
+ dispatch(startDm({ userId: uid }, setChannel));
}
close();
}}
@@ -87,17 +75,18 @@ const UserContextMenu = () => {
{t`DM`}
{
dispatch(setUserBlock(uid, name, true));
close();
}}
- role="button"
- tabIndex={-1}
>
{t`Block`}
-
+ >
);
};
-export default UserContextMenu;
+export default React.memo(UserContextMenu);
diff --git a/src/components/contextmenus/index.js b/src/components/contextmenus/index.js
deleted file mode 100644
index 3b06c4e..0000000
--- a/src/components/contextmenus/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import UserContextMenu from './UserContextMenu';
-import ChannelContextMenu from './ChannelContextMenu';
-
-export default {
- USER: UserContextMenu,
- CHANNEL: ChannelContextMenu,
-};
diff --git a/src/components/contextmenus/index.jsx b/src/components/contextmenus/index.jsx
new file mode 100644
index 0000000..3fcc3e6
--- /dev/null
+++ b/src/components/contextmenus/index.jsx
@@ -0,0 +1,42 @@
+import React, { useRef } from 'react';
+import ReactDOM from 'react-dom';
+
+import UserContextMenu from './UserContextMenu';
+import ChannelContextMenu from './ChannelContextMenu';
+import {
+ useClickOutside,
+} from '../hooks/clickOutside';
+
+export const types = {
+ USER: UserContextMenu,
+ CHANNEL: ChannelContextMenu,
+};
+
+const ContextMenu = ({
+ type, x, y, args, close,
+}) => {
+ const wrapperRef = useRef(null);
+
+ useClickOutside([wrapperRef], close);
+
+ if (!type) {
+ return null;
+ }
+
+ const Content = types[type];
+
+ return ReactDOM.createPortal((
+
+
+
+ ), document.getElementById('app'));
+};
+
+export default React.memo(ContextMenu);
diff --git a/src/components/hooks/clickOutside.js b/src/components/hooks/clickOutside.js
index a11c23a..9288a1b 100644
--- a/src/components/hooks/clickOutside.js
+++ b/src/components/hooks/clickOutside.js
@@ -1,9 +1,9 @@
/*
- * @flex
- *
* detect click outside
*/
+/* eslint-disable consistent-return */
+
import { useEffect, useLayoutEffect, useCallback } from 'react';
/*
@@ -47,9 +47,16 @@ export function useConditionalClickOutside(insideRefs, active, callback) {
*/
export function useClickOutside(insideRefs, callback) {
useEffect(() => {
+ const insideElems = insideRefs.some((ref) => ref.current)
+ ? insideRefs.map((ref) => ref.current)
+ : null;
+
+ if (insideElems === null) {
+ return;
+ }
+
const handleClickOutside = (event) => {
- if (insideRefs.every((ref) => !ref.current
- || !ref.current.contains(event.target))) {
+ if (insideElems.every((elem) => !elem || !elem.contains(event.target))) {
callback();
}
};
@@ -62,11 +69,12 @@ export function useClickOutside(insideRefs, callback) {
capture: true,
});
window.addEventListener('resize', handleWindowResize);
+
return () => {
document.removeEventListener('mousedown', handleClickOutside, {
capture: true,
});
window.removeEventListener('resize', handleWindowResize);
};
- }, [callback]);
+ }, [insideRefs, callback]);
}
diff --git a/src/components/hooks/drag.js b/src/components/hooks/drag.js
index a2be46b..5945442 100644
--- a/src/components/hooks/drag.js
+++ b/src/components/hooks/drag.js
@@ -1,9 +1,9 @@
/*
- * @flex
- *
* mouse draging
*/
+/* eslint-disable consistent-return */
+
import { useEffect, useCallback } from 'react';
/*
@@ -49,23 +49,22 @@ function useDrag(elRef, startHandler, diffHandler) {
}, [startHandler, diffHandler]);
useEffect(() => {
- let prevCurrent = null;
+ const refElem = elRef.current;
- if (elRef.current) {
- elRef.current.addEventListener('mousedown', startDrag, {
- passive: false,
- });
- elRef.current.addEventListener('touchstart', startDrag, {
- passive: false,
- });
- prevCurrent = elRef.current;
+ if (!refElem) {
+ return;
}
+ refElem.addEventListener('mousedown', startDrag, {
+ passive: false,
+ });
+ refElem.addEventListener('touchstart', startDrag, {
+ passive: false,
+ });
+
return () => {
- if (prevCurrent) {
- prevCurrent.removeEventListener('mousedown', startDrag);
- prevCurrent.removeEventListener('touchstart', startDrag);
- }
+ refElem.removeEventListener('mousedown', startDrag);
+ refElem.removeEventListener('touchstart', startDrag);
};
}, [elRef, startDrag]);
}
diff --git a/src/components/windows/Chat.jsx b/src/components/windows/Chat.jsx
index 8cec06a..458dd74 100644
--- a/src/components/windows/Chat.jsx
+++ b/src/components/windows/Chat.jsx
@@ -9,17 +9,15 @@ import useStayScrolled from 'react-stay-scrolled';
import { useSelector, useDispatch } from 'react-redux';
import { t } from 'ttag';
+import ContextMenu from '../contextmenus';
import ChatMessage from '../ChatMessage';
import ChannelDropDown from '../contextmenus/ChannelDropDown';
import {
- showContextMenu,
markChannelAsRead,
} from '../../store/actions';
import {
showUserAreaModal,
- setWindowTitle,
- setWindowArgs,
} from '../../store/actions/windows';
import {
fetchChatMessages,
@@ -28,38 +26,66 @@ import SocketClient from '../../socket/SocketClient';
const Chat = ({
- windowId,
+ args,
+ setArgs,
+ setTitle,
}) => {
const listRef = useRef();
const targetRef = useRef();
+ const inputRef = useRef();
const [blockedIds, setBlockedIds] = useState([]);
const [btnSize, setBtnSize] = useState(20);
+ const [cmArgs, setCmArgs] = useState({});
const dispatch = useDispatch();
- const setChannel = useCallback((cid) => {
- dispatch(markChannelAsRead(cid));
- dispatch(setWindowArgs(windowId, {
- chatChannel: Number(cid),
- }));
- }, [dispatch]);
-
- const setChatInputMessage = useCallback((msg) => {
- dispatch(setWindowArgs(windowId, {
- inputMessage: msg,
- }));
- }, [dispatch]);
-
const ownName = useSelector((state) => state.user.name);
- // eslint-disable-next-line max-len
const fetching = useSelector((state) => state.fetching.fetchingChat);
const { channels, messages, blocked } = useSelector((state) => state.chat);
const {
chatChannel = 1,
- inputMessage = '',
- } = useSelector((state) => state.windows.args[windowId] || {});
+ } = args;
+
+ const setChannel = useCallback((cid) => {
+ dispatch(markChannelAsRead(cid));
+ setArgs({
+ chatChannel: Number(cid),
+ });
+ }, [dispatch]);
+
+ const addToInput = useCallback((msg) => {
+ const inputElem = inputRef.current;
+ if (!inputElem) {
+ return;
+ }
+ let newInputMessage = inputElem.value;
+ if (newInputMessage.slice(-1) !== ' ') {
+ newInputMessage += ' ';
+ }
+ newInputMessage += `${msg} `;
+ inputElem.value = newInputMessage;
+ inputRef.current.focus();
+ }, []);
+
+ const closeCm = useCallback(() => {
+ setCmArgs({});
+ }, []);
+
+ const openUserCm = useCallback((x, y, name, uid) => {
+ setCmArgs({
+ type: 'USER',
+ x,
+ y,
+ args: {
+ name,
+ uid,
+ setChannel,
+ addToInput,
+ },
+ });
+ }, [setChannel, addToInput]);
const { stayScrolled } = useStayScrolled(listRef, {
initialScroll: Infinity,
@@ -76,7 +102,7 @@ const Chat = ({
useEffect(() => {
if (channels[chatChannel]) {
const channelName = channels[chatChannel][0];
- dispatch(setWindowTitle(windowId, `Chan: ${channelName}`));
+ setTitle(`Chan: ${channelName}`);
}
}, [chatChannel]);
@@ -101,11 +127,11 @@ const Chat = ({
function handleSubmit(evt) {
evt.preventDefault();
- const inptMsg = inputMessage.trim();
+ const inptMsg = inputRef.current.value.trim();
if (!inptMsg) return;
// send message via websocket
SocketClient.sendChatMessage(inptMsg, chatChannel);
- setChatInputMessage('');
+ inputRef.current.value = '';
}
/*
@@ -127,6 +153,13 @@ const Chat = ({
ref={targetRef}
className="chat-container"
>
+
)
- }
+ }
{
channelMessages.map((message) => ((blockedIds.includes(message[3]))
? null : (
@@ -155,7 +187,7 @@ const Chat = ({
uid={message[3]}
ts={message[4]}
key={message[5]}
- windowId={windowId}
+ openCm={openUserCm}
/>
)))
}
@@ -168,15 +200,13 @@ const Chat = ({
}}
>
{(ownName) ? (
-
+
setChatInputMessage(e.target.value)}
+ ref={inputRef}
autoComplete="off"
maxLength="200"
type="text"
@@ -193,6 +223,7 @@ const Chat = ({
) : (
dispatch(showUserAreaModal())}
style={{
textAlign: 'center',
@@ -206,6 +237,7 @@ const Chat = ({
)}
@@ -219,15 +251,15 @@ const Chat = ({
{
const {
- clientX,
- clientY,
+ clientX: x,
+ clientY: y,
} = event;
- dispatch(showContextMenu(
- 'CHANNEL',
- clientX,
- clientY,
- { cid: chatChannel },
- ));
+ setCmArgs({
+ type: 'CHANNEL',
+ x,
+ y,
+ args: { cid: chatChannel },
+ });
}}
role="button"
title={t`Channel settings`}
diff --git a/src/components/windows/Settings.jsx b/src/components/windows/Settings.jsx
index 4b5f557..cffab50 100644
--- a/src/components/windows/Settings.jsx
+++ b/src/components/windows/Settings.jsx
@@ -72,8 +72,8 @@ function Settings() {
state.gui.isPotato,
state.gui.isLightGrid,
state.gui.style,
- state.audio.mute,
- state.audio.chatNotify,
+ state.gui.mute,
+ state.gui.chatNotify,
state.canvas.isHistoricalView,
], shallowEqual);
const dispatch = useDispatch();
diff --git a/src/core/adminfunctions.js b/src/core/adminfunctions.js
index be0c69b..2ce590f 100644
--- a/src/core/adminfunctions.js
+++ b/src/core/adminfunctions.js
@@ -328,7 +328,7 @@ export async function executeWatchAction(
&& Date.now() - ts > 5 * 60 * 1000
&& !iid
) {
- return { info: 'Cann not watch so many pixels' };
+ return { info: 'Can not watch so many pixels' };
}
if (action === 'summary') {
diff --git a/src/store/actions/index.js b/src/store/actions/index.js
index f1e5c56..718251e 100644
--- a/src/store/actions/index.js
+++ b/src/store/actions/index.js
@@ -419,21 +419,6 @@ export function initTimer() {
};
}
-export function showContextMenu(
- menuType,
- xPos,
- yPos,
- args,
-) {
- return {
- type: 'SHOW_CONTEXT_MENU',
- menuType,
- xPos,
- yPos,
- args,
- };
-}
-
export function openChatChannel(cid) {
return {
type: 'OPEN_CHAT_CHANNEL',
@@ -499,12 +484,6 @@ export function unmuteChatChannel(cid) {
};
}
-export function hideContextMenu() {
- return {
- type: 'HIDE_CONTEXT_MENU',
- };
-}
-
export function reloadUrl() {
return {
type: 'RELOAD_URL',
diff --git a/src/store/actions/thunks.js b/src/store/actions/thunks.js
index f901bac..317c7f9 100644
--- a/src/store/actions/thunks.js
+++ b/src/store/actions/thunks.js
@@ -10,9 +10,6 @@ import {
requestMe,
} from './fetch';
-import {
- setWindowArgs,
-} from './windows';
import {
addChatChannel,
pAlert,
@@ -52,7 +49,7 @@ function receiveChatHistory(
/*
* query with either userId or userName
*/
-export function startDm(windowId, query) {
+export function startDm(query, cb = null) {
return async (dispatch) => {
dispatch(setApiFetching(true));
const res = await requestStartDm(query);
@@ -66,9 +63,9 @@ export function startDm(windowId, query) {
} else {
const cid = Number(Object.keys(res)[0]);
dispatch(addChatChannel(res));
- dispatch(setWindowArgs(windowId, {
- chatChannel: cid,
- }));
+ if (cb) {
+ cb(cid);
+ }
}
dispatch(setApiFetching(false));
};
diff --git a/src/store/actions/windows.js b/src/store/actions/windows.js
index 18e4750..8fba0a9 100644
--- a/src/store/actions/windows.js
+++ b/src/store/actions/windows.js
@@ -126,30 +126,6 @@ export function showCanvasSelectionModal() {
);
}
-export function addToChatInputMessage(windowId, msg, focus = true) {
- return (dispatch, getState) => {
- const args = getState().windows.args[windowId];
- let inputMessage = args && args.inputMessage;
- if (!inputMessage) {
- inputMessage = '';
- } else if (inputMessage.slice(-1) !== ' ') {
- inputMessage += ' ';
- }
- inputMessage += msg;
-
- dispatch(setWindowArgs(windowId, {
- inputMessage,
- }));
-
- if (focus) {
- const inputElem = document.getElementById(`chtipt-${windowId}`);
- if (inputElem) {
- inputElem.focus();
- }
- }
- };
-}
-
export function closeWindow(windowId) {
return {
type: 'CLOSE_WIN',
diff --git a/src/store/configureStore.js b/src/store/configureStore.js
index 9e1c7af..1e3597d 100644
--- a/src/store/configureStore.js
+++ b/src/store/configureStore.js
@@ -14,7 +14,6 @@ import storage from 'redux-persist/lib/storage';
/*
* reducers
*/
-import audio from './reducers/audio';
import canvas from './reducers/canvas';
import gui from './reducers/gui';
import windows from './reducers/windows';
@@ -22,14 +21,13 @@ import user from './reducers/user';
import ranks from './reducers/ranks';
import alert from './reducers/alert';
import chat from './reducers/chat';
-import contextMenu from './reducers/contextMenu';
import chatRead from './reducers/chatRead';
import fetching from './reducers/fetching';
/*
* middleware
*/
-import audiom from './middleware/audio';
+import audio from './middleware/audio';
import socketClientHook from './middleware/socketClientHook';
import rendererHook from './middleware/rendererHook';
import array from './middleware/array';
@@ -38,7 +36,7 @@ import notifications from './middleware/notifications';
import title from './middleware/title';
import extensions from './middleware/extensions';
-const CURRENT_VERSION = 3;
+const CURRENT_VERSION = 5;
const reducers = persistReducer({
key: 'primary',
@@ -58,11 +56,9 @@ const reducers = persistReducer({
'canvas',
'alert',
'chat',
- 'contextMenu',
'fetching',
],
}, combineReducers({
- audio,
canvas,
gui,
windows,
@@ -70,7 +66,6 @@ const reducers = persistReducer({
ranks,
alert,
chat,
- contextMenu,
chatRead,
fetching,
}));
@@ -83,7 +78,7 @@ const store = createStore(
thunk,
promise,
array,
- audiom,
+ audio,
notifications,
title,
socketClientHook,
diff --git a/src/store/configureStoreWin.js b/src/store/configureStoreWin.js
index 4aff44b..2175389 100644
--- a/src/store/configureStoreWin.js
+++ b/src/store/configureStoreWin.js
@@ -14,7 +14,6 @@ import storage from 'redux-persist/lib/storage';
/*
* reducers
*/
-import audio from './reducers/audio';
import canvas from './reducers/canvas';
import gui from './reducers/gui';
import win from './reducers/win';
@@ -44,7 +43,6 @@ const reducers = persistReducer({
'win',
],
}, combineReducers({
- audio,
canvas,
gui,
win,
@@ -62,6 +60,9 @@ const store = createStore(
);
-persistStore(store);
+export const persistor = persistStore(store);
export default store;
+
+
+// persistent stores: gui, windows, ranks, chatRead;
diff --git a/src/store/middleware/audio.js b/src/store/middleware/audio.js
index 5774390..fcd34de 100644
--- a/src/store/middleware/audio.js
+++ b/src/store/middleware/audio.js
@@ -9,7 +9,7 @@ const context = AudioContext && new AudioContext();
export default (store) => (next) => (action) => {
const state = store.getState();
- const { mute, chatNotify } = state.audio;
+ const { mute, chatNotify } = state.gui;
if (!mute && context) {
switch (action.type) {
diff --git a/src/store/middleware/notifications.js b/src/store/middleware/notifications.js
index 293d479..485dac7 100644
--- a/src/store/middleware/notifications.js
+++ b/src/store/middleware/notifications.js
@@ -42,7 +42,7 @@ export default (store) => (next) => (action) => {
case 'REC_CHAT_MESSAGE': {
const state = store.getState();
- const { chatNotify } = state.audio;
+ const { chatNotify } = state.gui;
if (!chatNotify) break;
const { isPing } = action;
diff --git a/src/store/reducers/audio.js b/src/store/reducers/audio.js
deleted file mode 100644
index cf93843..0000000
--- a/src/store/reducers/audio.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const initialState = {
- mute: false,
- chatNotify: true,
-};
-
-
-export default function audio(
- state = initialState,
- action,
-) {
- switch (action.type) {
- case 'TOGGLE_MUTE':
- return {
- ...state,
- mute: !state.mute,
- };
-
- case 'TOGGLE_CHAT_NOTIFY':
- return {
- ...state,
- chatNotify: !state.chatNotify,
- };
-
- default:
- return state;
- }
-}
diff --git a/src/store/reducers/contextMenu.js b/src/store/reducers/contextMenu.js
deleted file mode 100644
index 150778e..0000000
--- a/src/store/reducers/contextMenu.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * https://stackoverflow.com/questions/35623656/how-can-i-display-a-modal-dialog-in-redux-that-performs-asynchronous-actions/35641680#35641680
- *
- */
-
-const initialState = {
- menuOpen: false,
- menuType: null,
- xPos: 0,
- yPos: 0,
- args: {},
-};
-
-
-export default function contextMenu(
- state = initialState,
- action,
-) {
- switch (action.type) {
- case 'SHOW_CONTEXT_MENU': {
- const {
- menuType, xPos, yPos, args,
- } = action;
- return {
- ...state,
- menuType,
- xPos,
- yPos,
- menuOpen: true,
- args: {
- ...args,
- },
- };
- }
-
- case 'WIN_RESIZE':
- case 'HIDE_CONTEXT_MENU': {
- return {
- ...state,
- menuOpen: false,
- };
- }
-
- default:
- return state;
- }
-}
diff --git a/src/store/reducers/gui.js b/src/store/reducers/gui.js
index f3f0614..7e45474 100644
--- a/src/store/reducers/gui.js
+++ b/src/store/reducers/gui.js
@@ -7,6 +7,8 @@ const initialState = {
isLightGrid: false,
compactPalette: false,
paletteOpen: true,
+ mute: false,
+ chatNotify: true,
// top-left button menu
menuOpen: false,
// show online users per canvas instead of total
@@ -123,6 +125,18 @@ export default function gui(
};
}
+ case 'TOGGLE_MUTE':
+ return {
+ ...state,
+ mute: !state.mute,
+ };
+
+ case 'TOGGLE_CHAT_NOTIFY':
+ return {
+ ...state,
+ chatNotify: !state.chatNotify,
+ };
+
default:
return state;
}
diff --git a/src/store/reducers/windows.js b/src/store/reducers/windows.js
index ae9cf5b..a54ca19 100644
--- a/src/store/reducers/windows.js
+++ b/src/store/reducers/windows.js
@@ -446,7 +446,7 @@ export default function windows(
};
}
- case 'REC_ME':
+ case 'persist/REHYDRATE':
case 'WIN_RESIZE': {
const {
innerWidth: width,
@@ -456,7 +456,8 @@ export default function windows(
let { windows: newWindows, args, positions } = state;
const showWindows = width > SCREEN_WIDTH_THRESHOLD;
- if (action.type === 'REC_ME') {
+ if (action.type === 'persist/REHYDRATE') {
+ console.log('persist', state, action.payload);
if (!showWindows) {
// reset on phones on every refresh
return initialState;
diff --git a/src/store/selectors/windows.js b/src/store/selectors/windows.js
index 6fff03b..a5eac19 100644
--- a/src/store/selectors/windows.js
+++ b/src/store/selectors/windows.js
@@ -44,3 +44,6 @@ export const makeSelectWindowById = (windowId) => createSelector(
*/
// eslint-disable-next-line max-len
export const makeSelectWindowPosById = (windowId) => (state) => state.windows.positions[windowId];
+
+// eslint-disable-next-line max-len
+export const makeSelectWindowArgs = (windowId) => (state) => state.windows.args[windowId] || {};