diff --git a/web/chat/thread-menu.react.js b/web/chat/thread-menu.react.js
index 34ed9633e..f79c0040f 100644
--- a/web/chat/thread-menu.react.js
+++ b/web/chat/thread-menu.react.js
@@ -1,223 +1,255 @@
// @flow
import {
faArrowRight,
faBell,
faCog,
faCommentAlt,
faSignOutAlt,
faPlusCircle,
faUserFriends,
} from '@fortawesome/free-solid-svg-icons';
import * as React from 'react';
+import {
+ leaveThread,
+ leaveThreadActionTypes,
+} from 'lib/actions/thread-actions';
import { childThreadInfos } from 'lib/selectors/thread-selectors';
import {
threadHasPermission,
viewerIsMember,
threadIsChannel,
} from 'lib/shared/thread-utils';
import {
type ThreadInfo,
threadTypes,
threadPermissions,
} from 'lib/types/thread-types';
+import {
+ useServerCall,
+ useDispatchActionPromise,
+} from 'lib/utils/action-utils';
import SidebarListModal from '../modals/chat/sidebar-list-modal.react';
import { useModalContext } from '../modals/modal-provider.react';
+import ConfirmLeaveThreadModal from '../modals/threads/confirm-leave-thread-modal.react';
import ThreadSettingsModal from '../modals/threads/thread-settings-modal.react';
import { useSelector } from '../redux/redux-utils';
import SWMansionIcon from '../SWMansionIcon.react';
import ThreadMenuItem from './thread-menu-item.react';
import css from './thread-menu.css';
type ThreadMenuProps = {
+threadInfo: ThreadInfo,
};
function ThreadMenu(props: ThreadMenuProps): React.Node {
const [isOpen, setIsOpen] = React.useState(false);
- const { setModal } = useModalContext();
+ const { setModal, clearModal } = useModalContext();
const { threadInfo } = props;
const onClickSettings = React.useCallback(
() => setModal(),
[setModal, threadInfo.id],
);
const settingsItem = React.useMemo(() => {
return (
);
}, [onClickSettings]);
const membersItem = React.useMemo(() => {
if (threadInfo.type === threadTypes.PERSONAL) {
return null;
}
return ;
}, [threadInfo.type]);
const childThreads = useSelector(
state => childThreadInfos(state)[threadInfo.id],
);
const hasSidebars = React.useMemo(() => {
return childThreads?.some(
childThreadInfo => childThreadInfo.type === threadTypes.SIDEBAR,
);
}, [childThreads]);
const onClickSidebars = React.useCallback(
() => setModal(),
[setModal, threadInfo],
);
const sidebarItem = React.useMemo(() => {
if (!hasSidebars) {
return null;
}
return (
);
}, [hasSidebars, onClickSidebars]);
const canCreateSubchannels = React.useMemo(
() => threadHasPermission(threadInfo, threadPermissions.CREATE_SUBCHANNELS),
[threadInfo],
);
const hasSubchannels = React.useMemo(() => {
return !!childThreads?.some(threadIsChannel);
}, [childThreads]);
const viewSubchannelsItem = React.useMemo(() => {
if (!hasSubchannels && !canCreateSubchannels) {
return null;
}
return (
);
}, [canCreateSubchannels, hasSubchannels]);
const createSubchannelsItem = React.useMemo(() => {
if (!canCreateSubchannels) {
return null;
}
return (
);
}, [canCreateSubchannels]);
+ const dispatchActionPromise = useDispatchActionPromise();
+ const callLeaveThread = useServerCall(leaveThread);
+
+ const onConfirmLeaveThread = React.useCallback(() => {
+ dispatchActionPromise(
+ leaveThreadActionTypes,
+ callLeaveThread(threadInfo.id),
+ );
+ clearModal();
+ }, [callLeaveThread, clearModal, dispatchActionPromise, threadInfo.id]);
+
+ const onClickLeaveThread = React.useCallback(
+ () =>
+ setModal(
+ ,
+ ),
+ [clearModal, onConfirmLeaveThread, setModal, threadInfo],
+ );
+
const leaveThreadItem = React.useMemo(() => {
const canLeaveThread = threadHasPermission(
threadInfo,
threadPermissions.LEAVE_THREAD,
);
if (!viewerIsMember(threadInfo) || !canLeaveThread) {
return null;
}
return (
);
- }, [threadInfo]);
+ }, [onClickLeaveThread, threadInfo]);
const menuItems = React.useMemo(() => {
const notificationsItem = (
);
const separator =
;
// TODO: Enable menu items when the modals are implemented
const SHOW_NOTIFICATIONS = false;
const SHOW_MEMBERS = false;
const SHOW_VIEW_SUBCHANNELS = false;
const SHOW_CREATE_SUBCHANNELS = false;
- const SHOW_LEAVE_THREAD = false;
const items = [
settingsItem,
SHOW_NOTIFICATIONS && notificationsItem,
SHOW_MEMBERS && membersItem,
sidebarItem,
SHOW_VIEW_SUBCHANNELS && viewSubchannelsItem,
SHOW_CREATE_SUBCHANNELS && createSubchannelsItem,
- SHOW_LEAVE_THREAD && leaveThreadItem && separator,
- SHOW_LEAVE_THREAD && leaveThreadItem,
+ leaveThreadItem && separator,
+ leaveThreadItem,
];
return items.filter(Boolean);
}, [
settingsItem,
membersItem,
sidebarItem,
viewSubchannelsItem,
createSubchannelsItem,
leaveThreadItem,
]);
const closeMenuCallback = React.useCallback(() => {
document.removeEventListener('click', closeMenuCallback);
if (isOpen) {
setIsOpen(false);
}
}, [isOpen]);
React.useEffect(() => {
if (!document || !isOpen) {
return undefined;
}
document.addEventListener('click', closeMenuCallback);
return () => document.removeEventListener('click', closeMenuCallback);
}, [closeMenuCallback, isOpen]);
const switchMenuCallback = React.useCallback(() => {
setIsOpen(isMenuOpen => !isMenuOpen);
}, []);
if (menuItems.length === 0) {
return null;
}
let menuActionList = null;
if (isOpen) {
menuActionList = (
{menuItems}
);
}
return (
{menuActionList}
);
}
export default ThreadMenu;