move context menu out of store
This commit is contained in:
parent
352649e3bd
commit
856b1288be
|
@ -19,8 +19,8 @@ import WindowManager from './WindowManager';
|
||||||
|
|
||||||
const iconContextValue = { style: { verticalAlign: 'middle' } };
|
const iconContextValue = { style: { verticalAlign: 'middle' } };
|
||||||
|
|
||||||
const App = ({ store }) => (
|
const App = () => (
|
||||||
<Provider store={store}>
|
<>
|
||||||
<Style />
|
<Style />
|
||||||
<IconContext.Provider value={iconContextValue}>
|
<IconContext.Provider value={iconContextValue}>
|
||||||
<CanvasSwitchButton />
|
<CanvasSwitchButton />
|
||||||
|
@ -32,12 +32,16 @@ const App = ({ store }) => (
|
||||||
<UI />
|
<UI />
|
||||||
<WindowManager />
|
<WindowManager />
|
||||||
</IconContext.Provider>
|
</IconContext.Provider>
|
||||||
</Provider>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
function renderApp(domParent, store) {
|
function renderApp(domParent, store) {
|
||||||
const root = createRoot(domParent);
|
const root = createRoot(domParent);
|
||||||
root.render(<App store={store} />);
|
root.render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<App />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default renderApp;
|
export default renderApp;
|
||||||
|
|
|
@ -12,18 +12,22 @@ import UIWin from './UIWin';
|
||||||
|
|
||||||
const iconContextValue = { style: { verticalAlign: 'middle' } };
|
const iconContextValue = { style: { verticalAlign: 'middle' } };
|
||||||
|
|
||||||
const AppWin = ({ store }) => (
|
const AppWin = () => (
|
||||||
<Provider store={store}>
|
<>
|
||||||
<Style />
|
<Style />
|
||||||
<IconContext.Provider value={iconContextValue}>
|
<IconContext.Provider value={iconContextValue}>
|
||||||
<UIWin />
|
<UIWin />
|
||||||
</IconContext.Provider>
|
</IconContext.Provider>
|
||||||
</Provider>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
function renderAppWin(domParent, store) {
|
function renderAppWin(domParent, store) {
|
||||||
const root = createRoot(domParent);
|
const root = createRoot(domParent);
|
||||||
root.render(<AppWin store={store} />);
|
root.render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<AppWin />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default renderAppWin;
|
export default renderAppWin;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React, { useRef } from 'react';
|
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 { MarkdownParagraph } from './Markdown';
|
||||||
import {
|
import {
|
||||||
colorFromText,
|
colorFromText,
|
||||||
|
@ -11,19 +10,20 @@ import {
|
||||||
import { parseParagraph } from '../core/MarkdownParser';
|
import { parseParagraph } from '../core/MarkdownParser';
|
||||||
|
|
||||||
|
|
||||||
|
const selectStyle = (state) => state.gui.style.indexOf('dark') !== -1;
|
||||||
|
|
||||||
function ChatMessage({
|
function ChatMessage({
|
||||||
name,
|
name,
|
||||||
uid,
|
uid,
|
||||||
country,
|
country,
|
||||||
windowId,
|
|
||||||
msg,
|
msg,
|
||||||
ts,
|
ts,
|
||||||
|
openCm,
|
||||||
}) {
|
}) {
|
||||||
const dispatch = useDispatch();
|
|
||||||
const isDarkMode = useSelector(
|
const isDarkMode = useSelector(
|
||||||
(state) => state.gui.style.indexOf('dark') !== -1,
|
selectStyle,
|
||||||
);
|
);
|
||||||
const refEmbed = useRef(null);
|
const refEmbed = useRef();
|
||||||
|
|
||||||
const isInfo = (name === 'info');
|
const isInfo = (name === 'info');
|
||||||
const isEvent = (name === 'event');
|
const isEvent = (name === 'event');
|
||||||
|
@ -66,15 +66,7 @@ function ChatMessage({
|
||||||
title={name}
|
title={name}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
const {
|
openCm(event.clientX, event.clientY, name, uid);
|
||||||
clientX,
|
|
||||||
clientY,
|
|
||||||
} = event;
|
|
||||||
dispatch(showContextMenu('USER', clientX, clientY, {
|
|
||||||
windowId,
|
|
||||||
uid,
|
|
||||||
name,
|
|
||||||
}));
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
|
|
|
@ -89,7 +89,7 @@ const MdLink = ({ href, title, refEmbed }) => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{showEmbed && embedAvailable && (
|
{showEmbed && embedAvailable && (
|
||||||
(refEmbed)
|
(refEmbed && refEmbed.current)
|
||||||
? ReactDOM.createPortal(
|
? ReactDOM.createPortal(
|
||||||
<Embed url={href} />,
|
<Embed url={href} />,
|
||||||
refEmbed.current,
|
refEmbed.current,
|
||||||
|
|
|
@ -13,25 +13,18 @@ import Palette from './Palette';
|
||||||
import Alert from './Alert';
|
import Alert from './Alert';
|
||||||
import HistorySelect from './HistorySelect';
|
import HistorySelect from './HistorySelect';
|
||||||
import Mobile3DControls from './Mobile3DControls';
|
import Mobile3DControls from './Mobile3DControls';
|
||||||
import ContextMenues from './contextmenus';
|
|
||||||
|
|
||||||
const UI = () => {
|
const UI = () => {
|
||||||
const [
|
const [
|
||||||
isHistoricalView,
|
isHistoricalView,
|
||||||
is3D,
|
is3D,
|
||||||
isOnMobile,
|
isOnMobile,
|
||||||
menuOpen,
|
|
||||||
menuType,
|
|
||||||
] = useSelector((state) => [
|
] = useSelector((state) => [
|
||||||
state.canvas.isHistoricalView,
|
state.canvas.isHistoricalView,
|
||||||
state.canvas.is3D,
|
state.canvas.is3D,
|
||||||
state.user.isOnMobile,
|
state.user.isOnMobile,
|
||||||
state.contextMenu.menuOpen,
|
|
||||||
state.contextMenu.menuType,
|
|
||||||
], shallowEqual);
|
], shallowEqual);
|
||||||
|
|
||||||
const ContextMenu = menuOpen && menuType && ContextMenues[menuType];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Alert />
|
<Alert />
|
||||||
|
@ -47,7 +40,6 @@ const UI = () => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<NotifyBox />
|
<NotifyBox />
|
||||||
{ContextMenu && <ContextMenu />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,10 +16,13 @@ import {
|
||||||
toggleMaximizeWindow,
|
toggleMaximizeWindow,
|
||||||
cloneWindow,
|
cloneWindow,
|
||||||
focusWindow,
|
focusWindow,
|
||||||
|
setWindowTitle,
|
||||||
|
setWindowArgs,
|
||||||
} from '../store/actions/windows';
|
} from '../store/actions/windows';
|
||||||
import {
|
import {
|
||||||
makeSelectWindowById,
|
makeSelectWindowById,
|
||||||
makeSelectWindowPosById,
|
makeSelectWindowPosById,
|
||||||
|
makeSelectWindowArgs,
|
||||||
selectShowWindows,
|
selectShowWindows,
|
||||||
} from '../store/selectors/windows';
|
} from '../store/selectors/windows';
|
||||||
import useDrag from './hooks/drag';
|
import useDrag from './hooks/drag';
|
||||||
|
@ -28,17 +31,26 @@ import COMPONENTS from './windows';
|
||||||
const Window = ({ id }) => {
|
const Window = ({ id }) => {
|
||||||
const [render, setRender] = useState(false);
|
const [render, setRender] = useState(false);
|
||||||
|
|
||||||
const titleBarRef = useRef(null);
|
const titleBarRef = useRef();
|
||||||
const resizeRef = useRef(null);
|
const resizeRef = useRef();
|
||||||
|
|
||||||
const selectWindowById = useMemo(() => makeSelectWindowById(id), []);
|
const selectWindowById = useMemo(() => makeSelectWindowById(id), []);
|
||||||
const selectWIndowPosById = useMemo(() => makeSelectWindowPosById(id), []);
|
const selectWIndowPosById = useMemo(() => makeSelectWindowPosById(id), []);
|
||||||
|
const selectWindowArgs = useMemo(() => makeSelectWindowArgs(id), []);
|
||||||
const win = useSelector(selectWindowById);
|
const win = useSelector(selectWindowById);
|
||||||
const position = useSelector(selectWIndowPosById);
|
const position = useSelector(selectWIndowPosById);
|
||||||
const showWindows = useSelector(selectShowWindows);
|
const showWindows = useSelector(selectShowWindows);
|
||||||
|
const args = useSelector(selectWindowArgs);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const setArgs = useCallback(
|
||||||
|
(newArgs) => dispatch(setWindowArgs(id, newArgs),
|
||||||
|
), [dispatch]);
|
||||||
|
const setTitle = useCallback(
|
||||||
|
(title) => dispatch(setWindowTitle(id, title),
|
||||||
|
), [dispatch]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
open,
|
open,
|
||||||
hidden,
|
hidden,
|
||||||
|
@ -156,7 +168,7 @@ const Window = ({ id }) => {
|
||||||
className="modal-content"
|
className="modal-content"
|
||||||
key="content"
|
key="content"
|
||||||
>
|
>
|
||||||
<Content windowId={id} />
|
<Content args={args} setArgs={setArgs} setTitle={setTitle} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -224,7 +236,7 @@ const Window = ({ id }) => {
|
||||||
className="win-content"
|
className="win-content"
|
||||||
key="content"
|
key="content"
|
||||||
>
|
>
|
||||||
<Content windowId={id} />
|
<Content args={args} setArgs={setArgs} setTitle={setTitle} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,7 +36,7 @@ const ChatButton = () => {
|
||||||
shallowEqual,
|
shallowEqual,
|
||||||
);
|
);
|
||||||
|
|
||||||
const chatNotify = useSelector((state) => state.audio.chatNotify);
|
const chatNotify = useSelector((state) => state.gui.chatNotify);
|
||||||
const channels = useSelector((state) => state.chat.channels);
|
const channels = useSelector((state) => state.chat.channels);
|
||||||
const [unread, mute] = useSelector((state) => [
|
const [unread, mute] = useSelector((state) => [
|
||||||
state.chatRead.unread,
|
state.chatRead.unread,
|
||||||
|
|
|
@ -2,15 +2,11 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useRef, useCallback } from 'react';
|
import React from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useClickOutside,
|
|
||||||
} from '../hooks/clickOutside';
|
|
||||||
import {
|
|
||||||
hideContextMenu,
|
|
||||||
muteChatChannel,
|
muteChatChannel,
|
||||||
unmuteChatChannel,
|
unmuteChatChannel,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions';
|
||||||
|
@ -18,31 +14,25 @@ import {
|
||||||
setLeaveChannel,
|
setLeaveChannel,
|
||||||
} from '../../store/actions/thunks';
|
} from '../../store/actions/thunks';
|
||||||
|
|
||||||
const ChannelContextMenu = () => {
|
/*
|
||||||
const wrapperRef = useRef(null);
|
* args: {
|
||||||
|
* cid,
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
const ChannelContextMenu = ({ args, close }) => {
|
||||||
const channels = useSelector((state) => state.chat.channels);
|
const channels = useSelector((state) => state.chat.channels);
|
||||||
const muteArr = useSelector((state) => state.chatRead.mute);
|
const muteArr = useSelector((state) => state.chatRead.mute);
|
||||||
const { xPos, yPos, args } = useSelector((state) => state.contextMenu);
|
|
||||||
const { cid } = args;
|
const { cid } = args;
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const close = useCallback(() => dispatch(hideContextMenu()), [dispatch]);
|
|
||||||
|
|
||||||
useClickOutside([wrapperRef], close);
|
|
||||||
|
|
||||||
const isMuted = muteArr.includes(cid);
|
const isMuted = muteArr.includes(cid);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
ref={wrapperRef}
|
|
||||||
className="contextmenu"
|
|
||||||
style={{
|
|
||||||
right: window.innerWidth - xPos,
|
|
||||||
top: yPos,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
|
key="mute"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isMuted) {
|
if (isMuted) {
|
||||||
dispatch(unmuteChatChannel(cid));
|
dispatch(unmuteChatChannel(cid));
|
||||||
|
@ -58,6 +48,7 @@ const ChannelContextMenu = () => {
|
||||||
{(channels[cid][1] !== 0)
|
{(channels[cid][1] !== 0)
|
||||||
&& (
|
&& (
|
||||||
<div
|
<div
|
||||||
|
key="leave"
|
||||||
role="button"
|
role="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dispatch(setLeaveChannel(cid));
|
dispatch(setLeaveChannel(cid));
|
||||||
|
@ -68,7 +59,7 @@ const ChannelContextMenu = () => {
|
||||||
{t`Close`}
|
{t`Close`}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ const ChannelDropDown = ({
|
||||||
const unread = useSelector((state) => state.chatRead.unread);
|
const unread = useSelector((state) => state.chatRead.unread);
|
||||||
const mute = useSelector((state) => state.chatRead.mute);
|
const mute = useSelector((state) => state.chatRead.mute);
|
||||||
const channels = useSelector((state) => state.chat.channels);
|
const channels = useSelector((state) => state.chat.channels);
|
||||||
const chatNotify = useSelector((state) => state.audio.chatNotify);
|
const chatNotify = useSelector((state) => state.gui.chatNotify);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setOffset(buttonRef.current.clientHeight);
|
setOffset(buttonRef.current.clientHeight);
|
||||||
|
|
|
@ -2,57 +2,46 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useRef } from 'react';
|
import React from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import {
|
|
||||||
useClickOutside,
|
|
||||||
} from '../hooks/clickOutside';
|
|
||||||
import {
|
|
||||||
hideContextMenu,
|
|
||||||
} from '../../store/actions';
|
|
||||||
import {
|
import {
|
||||||
startDm,
|
startDm,
|
||||||
setUserBlock,
|
setUserBlock,
|
||||||
} from '../../store/actions/thunks';
|
} from '../../store/actions/thunks';
|
||||||
import {
|
|
||||||
addToChatInputMessage,
|
|
||||||
setWindowArgs,
|
|
||||||
} from '../../store/actions/windows';
|
|
||||||
import { escapeMd } from '../../core/utils';
|
import { escapeMd } from '../../core/utils';
|
||||||
|
|
||||||
const UserContextMenu = () => {
|
/*
|
||||||
const wrapperRef = useRef(null);
|
* args: {
|
||||||
|
* name,
|
||||||
const { xPos, yPos, args } = useSelector((state) => state.contextMenu);
|
* uid,
|
||||||
const { windowId, name, uid } = args;
|
* setChannel,
|
||||||
|
* addToInput,
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
const UserContextMenu = ({ args, close }) => {
|
||||||
const channels = useSelector((state) => state.chat.channels);
|
const channels = useSelector((state) => state.chat.channels);
|
||||||
const fetching = useSelector((state) => state.fetching.fetchingApi);
|
const fetching = useSelector((state) => state.fetching.fetchingApi);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const close = () => dispatch(hideContextMenu());
|
|
||||||
|
|
||||||
useClickOutside([wrapperRef], close);
|
const {
|
||||||
|
name,
|
||||||
|
uid,
|
||||||
|
setChannel,
|
||||||
|
addToInput,
|
||||||
|
} = args;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
ref={wrapperRef}
|
|
||||||
className="contextmenu"
|
|
||||||
style={{
|
|
||||||
left: xPos,
|
|
||||||
top: yPos,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
|
key="ping"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const ping = `@[${escapeMd(name)}](${uid})`;
|
const ping = `@[${escapeMd(name)}](${uid})`;
|
||||||
dispatch(
|
addToInput(ping);
|
||||||
addToChatInputMessage(windowId, ping),
|
|
||||||
);
|
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
style={{ borderTop: 'none' }}
|
style={{ borderTop: 'none' }}
|
||||||
|
@ -61,6 +50,7 @@ const UserContextMenu = () => {
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
|
key="dm"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
/*
|
/*
|
||||||
|
@ -71,15 +61,13 @@ const UserContextMenu = () => {
|
||||||
for (let i = 0; i < cids.length; i += 1) {
|
for (let i = 0; i < cids.length; i += 1) {
|
||||||
const cid = cids[i];
|
const cid = cids[i];
|
||||||
if (channels[cid].length === 4 && channels[cid][3] === uid) {
|
if (channels[cid].length === 4 && channels[cid][3] === uid) {
|
||||||
dispatch(setWindowArgs(windowId, {
|
setChannel(cid);
|
||||||
chatChannel: cid,
|
|
||||||
}));
|
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!fetching) {
|
if (!fetching) {
|
||||||
dispatch(startDm(windowId, { userId: uid }));
|
dispatch(startDm({ userId: uid }, setChannel));
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
|
@ -87,17 +75,18 @@ const UserContextMenu = () => {
|
||||||
{t`DM`}
|
{t`DM`}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
role="button"
|
||||||
|
key="block"
|
||||||
|
tabIndex={-1}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dispatch(setUserBlock(uid, name, true));
|
dispatch(setUserBlock(uid, name, true));
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
role="button"
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
>
|
||||||
{t`Block`}
|
{t`Block`}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserContextMenu;
|
export default React.memo(UserContextMenu);
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import UserContextMenu from './UserContextMenu';
|
|
||||||
import ChannelContextMenu from './ChannelContextMenu';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
USER: UserContextMenu,
|
|
||||||
CHANNEL: ChannelContextMenu,
|
|
||||||
};
|
|
42
src/components/contextmenus/index.jsx
Normal file
42
src/components/contextmenus/index.jsx
Normal file
|
@ -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((
|
||||||
|
<div
|
||||||
|
ref={wrapperRef}
|
||||||
|
className={`contextmenu ${type}`}
|
||||||
|
style={{
|
||||||
|
left: x,
|
||||||
|
top: y,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Content close={close} args={args} />
|
||||||
|
</div>
|
||||||
|
), document.getElementById('app'));
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(ContextMenu);
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* @flex
|
|
||||||
*
|
|
||||||
* detect click outside
|
* detect click outside
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable consistent-return */
|
||||||
|
|
||||||
import { useEffect, useLayoutEffect, useCallback } from 'react';
|
import { useEffect, useLayoutEffect, useCallback } from 'react';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -47,9 +47,16 @@ export function useConditionalClickOutside(insideRefs, active, callback) {
|
||||||
*/
|
*/
|
||||||
export function useClickOutside(insideRefs, callback) {
|
export function useClickOutside(insideRefs, callback) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const insideElems = insideRefs.some((ref) => ref.current)
|
||||||
|
? insideRefs.map((ref) => ref.current)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (insideElems === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const handleClickOutside = (event) => {
|
const handleClickOutside = (event) => {
|
||||||
if (insideRefs.every((ref) => !ref.current
|
if (insideElems.every((elem) => !elem || !elem.contains(event.target))) {
|
||||||
|| !ref.current.contains(event.target))) {
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -62,11 +69,12 @@ export function useClickOutside(insideRefs, callback) {
|
||||||
capture: true,
|
capture: true,
|
||||||
});
|
});
|
||||||
window.addEventListener('resize', handleWindowResize);
|
window.addEventListener('resize', handleWindowResize);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('mousedown', handleClickOutside, {
|
document.removeEventListener('mousedown', handleClickOutside, {
|
||||||
capture: true,
|
capture: true,
|
||||||
});
|
});
|
||||||
window.removeEventListener('resize', handleWindowResize);
|
window.removeEventListener('resize', handleWindowResize);
|
||||||
};
|
};
|
||||||
}, [callback]);
|
}, [insideRefs, callback]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* @flex
|
|
||||||
*
|
|
||||||
* mouse draging
|
* mouse draging
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable consistent-return */
|
||||||
|
|
||||||
import { useEffect, useCallback } from 'react';
|
import { useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -49,23 +49,22 @@ function useDrag(elRef, startHandler, diffHandler) {
|
||||||
}, [startHandler, diffHandler]);
|
}, [startHandler, diffHandler]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let prevCurrent = null;
|
const refElem = elRef.current;
|
||||||
|
|
||||||
if (elRef.current) {
|
if (!refElem) {
|
||||||
elRef.current.addEventListener('mousedown', startDrag, {
|
return;
|
||||||
passive: false,
|
|
||||||
});
|
|
||||||
elRef.current.addEventListener('touchstart', startDrag, {
|
|
||||||
passive: false,
|
|
||||||
});
|
|
||||||
prevCurrent = elRef.current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refElem.addEventListener('mousedown', startDrag, {
|
||||||
|
passive: false,
|
||||||
|
});
|
||||||
|
refElem.addEventListener('touchstart', startDrag, {
|
||||||
|
passive: false,
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (prevCurrent) {
|
refElem.removeEventListener('mousedown', startDrag);
|
||||||
prevCurrent.removeEventListener('mousedown', startDrag);
|
refElem.removeEventListener('touchstart', startDrag);
|
||||||
prevCurrent.removeEventListener('touchstart', startDrag);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}, [elRef, startDrag]);
|
}, [elRef, startDrag]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,15 @@ import useStayScrolled from 'react-stay-scrolled';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
|
import ContextMenu from '../contextmenus';
|
||||||
import ChatMessage from '../ChatMessage';
|
import ChatMessage from '../ChatMessage';
|
||||||
import ChannelDropDown from '../contextmenus/ChannelDropDown';
|
import ChannelDropDown from '../contextmenus/ChannelDropDown';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
showContextMenu,
|
|
||||||
markChannelAsRead,
|
markChannelAsRead,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions';
|
||||||
import {
|
import {
|
||||||
showUserAreaModal,
|
showUserAreaModal,
|
||||||
setWindowTitle,
|
|
||||||
setWindowArgs,
|
|
||||||
} from '../../store/actions/windows';
|
} from '../../store/actions/windows';
|
||||||
import {
|
import {
|
||||||
fetchChatMessages,
|
fetchChatMessages,
|
||||||
|
@ -28,38 +26,66 @@ import SocketClient from '../../socket/SocketClient';
|
||||||
|
|
||||||
|
|
||||||
const Chat = ({
|
const Chat = ({
|
||||||
windowId,
|
args,
|
||||||
|
setArgs,
|
||||||
|
setTitle,
|
||||||
}) => {
|
}) => {
|
||||||
const listRef = useRef();
|
const listRef = useRef();
|
||||||
const targetRef = useRef();
|
const targetRef = useRef();
|
||||||
|
const inputRef = useRef();
|
||||||
|
|
||||||
const [blockedIds, setBlockedIds] = useState([]);
|
const [blockedIds, setBlockedIds] = useState([]);
|
||||||
const [btnSize, setBtnSize] = useState(20);
|
const [btnSize, setBtnSize] = useState(20);
|
||||||
|
const [cmArgs, setCmArgs] = useState({});
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
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);
|
const ownName = useSelector((state) => state.user.name);
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
const fetching = useSelector((state) => state.fetching.fetchingChat);
|
const fetching = useSelector((state) => state.fetching.fetchingChat);
|
||||||
const { channels, messages, blocked } = useSelector((state) => state.chat);
|
const { channels, messages, blocked } = useSelector((state) => state.chat);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
chatChannel = 1,
|
chatChannel = 1,
|
||||||
inputMessage = '',
|
} = args;
|
||||||
} = useSelector((state) => state.windows.args[windowId] || {});
|
|
||||||
|
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, {
|
const { stayScrolled } = useStayScrolled(listRef, {
|
||||||
initialScroll: Infinity,
|
initialScroll: Infinity,
|
||||||
|
@ -76,7 +102,7 @@ const Chat = ({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (channels[chatChannel]) {
|
if (channels[chatChannel]) {
|
||||||
const channelName = channels[chatChannel][0];
|
const channelName = channels[chatChannel][0];
|
||||||
dispatch(setWindowTitle(windowId, `Chan: ${channelName}`));
|
setTitle(`Chan: ${channelName}`);
|
||||||
}
|
}
|
||||||
}, [chatChannel]);
|
}, [chatChannel]);
|
||||||
|
|
||||||
|
@ -101,11 +127,11 @@ const Chat = ({
|
||||||
|
|
||||||
function handleSubmit(evt) {
|
function handleSubmit(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const inptMsg = inputMessage.trim();
|
const inptMsg = inputRef.current.value.trim();
|
||||||
if (!inptMsg) return;
|
if (!inptMsg) return;
|
||||||
// send message via websocket
|
// send message via websocket
|
||||||
SocketClient.sendChatMessage(inptMsg, chatChannel);
|
SocketClient.sendChatMessage(inptMsg, chatChannel);
|
||||||
setChatInputMessage('');
|
inputRef.current.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -127,6 +153,13 @@ const Chat = ({
|
||||||
ref={targetRef}
|
ref={targetRef}
|
||||||
className="chat-container"
|
className="chat-container"
|
||||||
>
|
>
|
||||||
|
<ContextMenu
|
||||||
|
type={cmArgs.type}
|
||||||
|
x={cmArgs.x}
|
||||||
|
y={cmArgs.y}
|
||||||
|
args={cmArgs.args}
|
||||||
|
close={closeCm}
|
||||||
|
/>
|
||||||
<ul
|
<ul
|
||||||
className="chatarea"
|
className="chatarea"
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
|
@ -141,10 +174,9 @@ const Chat = ({
|
||||||
name="info"
|
name="info"
|
||||||
country="xx"
|
country="xx"
|
||||||
msg={t`Start chatting here`}
|
msg={t`Start chatting here`}
|
||||||
windowId={windowId}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
channelMessages.map((message) => ((blockedIds.includes(message[3]))
|
channelMessages.map((message) => ((blockedIds.includes(message[3]))
|
||||||
? null : (
|
? null : (
|
||||||
|
@ -155,7 +187,7 @@ const Chat = ({
|
||||||
uid={message[3]}
|
uid={message[3]}
|
||||||
ts={message[4]}
|
ts={message[4]}
|
||||||
key={message[5]}
|
key={message[5]}
|
||||||
windowId={windowId}
|
openCm={openUserCm}
|
||||||
/>
|
/>
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -168,15 +200,13 @@ const Chat = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(ownName) ? (
|
{(ownName) ? (
|
||||||
<React.Fragment key={`chtipt-${windowId}`}>
|
<React.Fragment key="chtipt">
|
||||||
<input
|
<input
|
||||||
style={{
|
style={{
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
minWidth: 40,
|
minWidth: 40,
|
||||||
}}
|
}}
|
||||||
id={`chtipt-${windowId}`}
|
ref={inputRef}
|
||||||
value={inputMessage}
|
|
||||||
onChange={(e) => setChatInputMessage(e.target.value)}
|
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
maxLength="200"
|
maxLength="200"
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -193,6 +223,7 @@ const Chat = ({
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="modallink"
|
className="modallink"
|
||||||
|
key="nlipt"
|
||||||
onClick={() => dispatch(showUserAreaModal())}
|
onClick={() => dispatch(showUserAreaModal())}
|
||||||
style={{
|
style={{
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
|
@ -206,6 +237,7 @@ const Chat = ({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ChannelDropDown
|
<ChannelDropDown
|
||||||
|
key="cdd"
|
||||||
setChatChannel={setChannel}
|
setChatChannel={setChannel}
|
||||||
chatChannel={chatChannel}
|
chatChannel={chatChannel}
|
||||||
/>
|
/>
|
||||||
|
@ -219,15 +251,15 @@ const Chat = ({
|
||||||
<span
|
<span
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
const {
|
const {
|
||||||
clientX,
|
clientX: x,
|
||||||
clientY,
|
clientY: y,
|
||||||
} = event;
|
} = event;
|
||||||
dispatch(showContextMenu(
|
setCmArgs({
|
||||||
'CHANNEL',
|
type: 'CHANNEL',
|
||||||
clientX,
|
x,
|
||||||
clientY,
|
y,
|
||||||
{ cid: chatChannel },
|
args: { cid: chatChannel },
|
||||||
));
|
});
|
||||||
}}
|
}}
|
||||||
role="button"
|
role="button"
|
||||||
title={t`Channel settings`}
|
title={t`Channel settings`}
|
||||||
|
|
|
@ -72,8 +72,8 @@ function Settings() {
|
||||||
state.gui.isPotato,
|
state.gui.isPotato,
|
||||||
state.gui.isLightGrid,
|
state.gui.isLightGrid,
|
||||||
state.gui.style,
|
state.gui.style,
|
||||||
state.audio.mute,
|
state.gui.mute,
|
||||||
state.audio.chatNotify,
|
state.gui.chatNotify,
|
||||||
state.canvas.isHistoricalView,
|
state.canvas.isHistoricalView,
|
||||||
], shallowEqual);
|
], shallowEqual);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
|
@ -328,7 +328,7 @@ export async function executeWatchAction(
|
||||||
&& Date.now() - ts > 5 * 60 * 1000
|
&& Date.now() - ts > 5 * 60 * 1000
|
||||||
&& !iid
|
&& !iid
|
||||||
) {
|
) {
|
||||||
return { info: 'Cann not watch so many pixels' };
|
return { info: 'Can not watch so many pixels' };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'summary') {
|
if (action === 'summary') {
|
||||||
|
|
|
@ -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) {
|
export function openChatChannel(cid) {
|
||||||
return {
|
return {
|
||||||
type: 'OPEN_CHAT_CHANNEL',
|
type: 'OPEN_CHAT_CHANNEL',
|
||||||
|
@ -499,12 +484,6 @@ export function unmuteChatChannel(cid) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hideContextMenu() {
|
|
||||||
return {
|
|
||||||
type: 'HIDE_CONTEXT_MENU',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reloadUrl() {
|
export function reloadUrl() {
|
||||||
return {
|
return {
|
||||||
type: 'RELOAD_URL',
|
type: 'RELOAD_URL',
|
||||||
|
|
|
@ -10,9 +10,6 @@ import {
|
||||||
requestMe,
|
requestMe,
|
||||||
} from './fetch';
|
} from './fetch';
|
||||||
|
|
||||||
import {
|
|
||||||
setWindowArgs,
|
|
||||||
} from './windows';
|
|
||||||
import {
|
import {
|
||||||
addChatChannel,
|
addChatChannel,
|
||||||
pAlert,
|
pAlert,
|
||||||
|
@ -52,7 +49,7 @@ function receiveChatHistory(
|
||||||
/*
|
/*
|
||||||
* query with either userId or userName
|
* query with either userId or userName
|
||||||
*/
|
*/
|
||||||
export function startDm(windowId, query) {
|
export function startDm(query, cb = null) {
|
||||||
return async (dispatch) => {
|
return async (dispatch) => {
|
||||||
dispatch(setApiFetching(true));
|
dispatch(setApiFetching(true));
|
||||||
const res = await requestStartDm(query);
|
const res = await requestStartDm(query);
|
||||||
|
@ -66,9 +63,9 @@ export function startDm(windowId, query) {
|
||||||
} else {
|
} else {
|
||||||
const cid = Number(Object.keys(res)[0]);
|
const cid = Number(Object.keys(res)[0]);
|
||||||
dispatch(addChatChannel(res));
|
dispatch(addChatChannel(res));
|
||||||
dispatch(setWindowArgs(windowId, {
|
if (cb) {
|
||||||
chatChannel: cid,
|
cb(cid);
|
||||||
}));
|
}
|
||||||
}
|
}
|
||||||
dispatch(setApiFetching(false));
|
dispatch(setApiFetching(false));
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) {
|
export function closeWindow(windowId) {
|
||||||
return {
|
return {
|
||||||
type: 'CLOSE_WIN',
|
type: 'CLOSE_WIN',
|
||||||
|
|
|
@ -14,7 +14,6 @@ import storage from 'redux-persist/lib/storage';
|
||||||
/*
|
/*
|
||||||
* reducers
|
* reducers
|
||||||
*/
|
*/
|
||||||
import audio from './reducers/audio';
|
|
||||||
import canvas from './reducers/canvas';
|
import canvas from './reducers/canvas';
|
||||||
import gui from './reducers/gui';
|
import gui from './reducers/gui';
|
||||||
import windows from './reducers/windows';
|
import windows from './reducers/windows';
|
||||||
|
@ -22,14 +21,13 @@ import user from './reducers/user';
|
||||||
import ranks from './reducers/ranks';
|
import ranks from './reducers/ranks';
|
||||||
import alert from './reducers/alert';
|
import alert from './reducers/alert';
|
||||||
import chat from './reducers/chat';
|
import chat from './reducers/chat';
|
||||||
import contextMenu from './reducers/contextMenu';
|
|
||||||
import chatRead from './reducers/chatRead';
|
import chatRead from './reducers/chatRead';
|
||||||
import fetching from './reducers/fetching';
|
import fetching from './reducers/fetching';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* middleware
|
* middleware
|
||||||
*/
|
*/
|
||||||
import audiom from './middleware/audio';
|
import audio from './middleware/audio';
|
||||||
import socketClientHook from './middleware/socketClientHook';
|
import socketClientHook from './middleware/socketClientHook';
|
||||||
import rendererHook from './middleware/rendererHook';
|
import rendererHook from './middleware/rendererHook';
|
||||||
import array from './middleware/array';
|
import array from './middleware/array';
|
||||||
|
@ -38,7 +36,7 @@ import notifications from './middleware/notifications';
|
||||||
import title from './middleware/title';
|
import title from './middleware/title';
|
||||||
import extensions from './middleware/extensions';
|
import extensions from './middleware/extensions';
|
||||||
|
|
||||||
const CURRENT_VERSION = 3;
|
const CURRENT_VERSION = 5;
|
||||||
|
|
||||||
const reducers = persistReducer({
|
const reducers = persistReducer({
|
||||||
key: 'primary',
|
key: 'primary',
|
||||||
|
@ -58,11 +56,9 @@ const reducers = persistReducer({
|
||||||
'canvas',
|
'canvas',
|
||||||
'alert',
|
'alert',
|
||||||
'chat',
|
'chat',
|
||||||
'contextMenu',
|
|
||||||
'fetching',
|
'fetching',
|
||||||
],
|
],
|
||||||
}, combineReducers({
|
}, combineReducers({
|
||||||
audio,
|
|
||||||
canvas,
|
canvas,
|
||||||
gui,
|
gui,
|
||||||
windows,
|
windows,
|
||||||
|
@ -70,7 +66,6 @@ const reducers = persistReducer({
|
||||||
ranks,
|
ranks,
|
||||||
alert,
|
alert,
|
||||||
chat,
|
chat,
|
||||||
contextMenu,
|
|
||||||
chatRead,
|
chatRead,
|
||||||
fetching,
|
fetching,
|
||||||
}));
|
}));
|
||||||
|
@ -83,7 +78,7 @@ const store = createStore(
|
||||||
thunk,
|
thunk,
|
||||||
promise,
|
promise,
|
||||||
array,
|
array,
|
||||||
audiom,
|
audio,
|
||||||
notifications,
|
notifications,
|
||||||
title,
|
title,
|
||||||
socketClientHook,
|
socketClientHook,
|
||||||
|
|
|
@ -14,7 +14,6 @@ import storage from 'redux-persist/lib/storage';
|
||||||
/*
|
/*
|
||||||
* reducers
|
* reducers
|
||||||
*/
|
*/
|
||||||
import audio from './reducers/audio';
|
|
||||||
import canvas from './reducers/canvas';
|
import canvas from './reducers/canvas';
|
||||||
import gui from './reducers/gui';
|
import gui from './reducers/gui';
|
||||||
import win from './reducers/win';
|
import win from './reducers/win';
|
||||||
|
@ -44,7 +43,6 @@ const reducers = persistReducer({
|
||||||
'win',
|
'win',
|
||||||
],
|
],
|
||||||
}, combineReducers({
|
}, combineReducers({
|
||||||
audio,
|
|
||||||
canvas,
|
canvas,
|
||||||
gui,
|
gui,
|
||||||
win,
|
win,
|
||||||
|
@ -62,6 +60,9 @@ const store = createStore(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
persistStore(store);
|
export const persistor = persistStore(store);
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
|
||||||
|
|
||||||
|
// persistent stores: gui, windows, ranks, chatRead;
|
||||||
|
|
|
@ -9,7 +9,7 @@ const context = AudioContext && new AudioContext();
|
||||||
|
|
||||||
export default (store) => (next) => (action) => {
|
export default (store) => (next) => (action) => {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const { mute, chatNotify } = state.audio;
|
const { mute, chatNotify } = state.gui;
|
||||||
|
|
||||||
if (!mute && context) {
|
if (!mute && context) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default (store) => (next) => (action) => {
|
||||||
|
|
||||||
case 'REC_CHAT_MESSAGE': {
|
case 'REC_CHAT_MESSAGE': {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const { chatNotify } = state.audio;
|
const { chatNotify } = state.gui;
|
||||||
if (!chatNotify) break;
|
if (!chatNotify) break;
|
||||||
|
|
||||||
const { isPing } = action;
|
const { isPing } = action;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,8 @@ const initialState = {
|
||||||
isLightGrid: false,
|
isLightGrid: false,
|
||||||
compactPalette: false,
|
compactPalette: false,
|
||||||
paletteOpen: true,
|
paletteOpen: true,
|
||||||
|
mute: false,
|
||||||
|
chatNotify: true,
|
||||||
// top-left button menu
|
// top-left button menu
|
||||||
menuOpen: false,
|
menuOpen: false,
|
||||||
// show online users per canvas instead of total
|
// 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:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -446,7 +446,7 @@ export default function windows(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'REC_ME':
|
case 'persist/REHYDRATE':
|
||||||
case 'WIN_RESIZE': {
|
case 'WIN_RESIZE': {
|
||||||
const {
|
const {
|
||||||
innerWidth: width,
|
innerWidth: width,
|
||||||
|
@ -456,7 +456,8 @@ export default function windows(
|
||||||
let { windows: newWindows, args, positions } = state;
|
let { windows: newWindows, args, positions } = state;
|
||||||
const showWindows = width > SCREEN_WIDTH_THRESHOLD;
|
const showWindows = width > SCREEN_WIDTH_THRESHOLD;
|
||||||
|
|
||||||
if (action.type === 'REC_ME') {
|
if (action.type === 'persist/REHYDRATE') {
|
||||||
|
console.log('persist', state, action.payload);
|
||||||
if (!showWindows) {
|
if (!showWindows) {
|
||||||
// reset on phones on every refresh
|
// reset on phones on every refresh
|
||||||
return initialState;
|
return initialState;
|
||||||
|
|
|
@ -44,3 +44,6 @@ export const makeSelectWindowById = (windowId) => createSelector(
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
export const makeSelectWindowPosById = (windowId) => (state) => state.windows.positions[windowId];
|
export const makeSelectWindowPosById = (windowId) => (state) => state.windows.positions[windowId];
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
export const makeSelectWindowArgs = (windowId) => (state) => state.windows.args[windowId] || {};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user