--- /dev/null
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { twemojify } from '../../../util/twemojify';
+
+import initMatrix from '../../../client/initMatrix';
+import { openInviteUser } from '../../../client/action/navigation';
+import * as roomActions from '../../../client/action/room';
+
+import { MenuHeader, MenuItem } from '../../atoms/context-menu/ContextMenu';
+import RoomNotification from '../room-notification/RoomNotification';
+
+import TickMarkIC from '../../../../public/res/ic/outlined/tick-mark.svg';
+import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
+import LeaveArrowIC from '../../../../public/res/ic/outlined/leave-arrow.svg';
+
+function RoomOptions({ roomId, afterOptionSelect }) {
+ const mx = initMatrix.matrixClient;
+ const room = mx.getRoom(roomId);
+ const canInvite = room?.canInvite(mx.getUserId());
+
+ const handleMarkAsRead = () => {
+ afterOptionSelect();
+ if (!room) return;
+ const events = room.getLiveTimeline().getEvents();
+ mx.sendReadReceipt(events[events.length - 1]);
+ };
+
+ const handleInviteClick = () => {
+ openInviteUser(roomId);
+ afterOptionSelect();
+ };
+ const handleLeaveClick = () => {
+ if (confirm('Are you really want to leave this room?')) {
+ roomActions.leave(roomId);
+ afterOptionSelect();
+ }
+ };
+
+ return (
+ <>
+ <MenuHeader>{twemojify(`Options for ${initMatrix.matrixClient.getRoom(roomId)?.name}`)}</MenuHeader>
+ <MenuItem iconSrc={TickMarkIC} onClick={handleMarkAsRead}>Mark as read</MenuItem>
+ <MenuItem
+ iconSrc={AddUserIC}
+ onClick={handleInviteClick}
+ disabled={!canInvite}
+ >
+ Invite
+ </MenuItem>
+ <MenuItem iconSrc={LeaveArrowIC} variant="danger" onClick={handleLeaveClick}>Leave</MenuItem>
+ <MenuHeader>Notification</MenuHeader>
+ <RoomNotification roomId={roomId} />
+ </>
+ );
+}
+
+RoomOptions.defaultProps = {
+ afterOptionSelect: null,
+};
+
+RoomOptions.propTypes = {
+ roomId: PropTypes.string.isRequired,
+ afterOptionSelect: PropTypes.func,
+};
+
+export default RoomOptions;
import initMatrix from '../../../client/initMatrix';
import navigation from '../../../client/state/navigation';
-import { openRoomOptions } from '../../../client/action/navigation';
+import { openReusableContextMenu } from '../../../client/action/navigation';
import { createSpaceShortcut, deleteSpaceShortcut } from '../../../client/action/room';
import { getEventCords, abbreviateNumber } from '../../../util/common';
import IconButton from '../../atoms/button/IconButton';
import RoomSelector from '../../molecules/room-selector/RoomSelector';
+import RoomOptions from '../../molecules/room-optons/RoomOptions';
import HashIC from '../../../../public/res/ic/outlined/hash.svg';
import HashGlobeIC from '../../../../public/res/ic/outlined/hash-globe.svg';
};
}, []);
+ const openRoomOptions = (e) => {
+ e.preventDefault();
+ openReusableContextMenu(
+ 'right',
+ getEventCords(e, '.room-selector'),
+ (closeMenu) => <RoomOptions roomId={roomId} afterOptionSelect={closeMenu} />,
+ );
+ };
+
const joinRuleToIconSrc = (joinRule) => ({
restricted: () => (room.isSpaceRoom() ? SpaceIC : HashIC),
invite: () => (room.isSpaceRoom() ? SpaceLockIC : HashLockIC),
tooltip="Options"
tooltipPlacement="right"
src={VerticalMenuIC}
- onClick={(e) => openRoomOptions(getEventCords(e), roomId)}
+ onClick={openRoomOptions}
/>
)}
/>
+++ /dev/null
-import React, { useEffect, useRef } from 'react';
-
-import { twemojify } from '../../../util/twemojify';
-
-import initMatrix from '../../../client/initMatrix';
-import cons from '../../../client/state/cons';
-import navigation from '../../../client/state/navigation';
-import { openInviteUser } from '../../../client/action/navigation';
-import * as roomActions from '../../../client/action/room';
-
-import ContextMenu, { MenuHeader, MenuItem } from '../../atoms/context-menu/ContextMenu';
-import RoomNotification from '../../molecules/room-notification/RoomNotification';
-
-import TickMarkIC from '../../../../public/res/ic/outlined/tick-mark.svg';
-import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
-import LeaveArrowIC from '../../../../public/res/ic/outlined/leave-arrow.svg';
-
-import { useForceUpdate } from '../../hooks/useForceUpdate';
-
-let isRoomOptionVisible = false;
-let roomId = null;
-function RoomOptions() {
- const openerRef = useRef(null);
- const [, forceUpdate] = useForceUpdate();
-
- function openRoomOptions(cords, rId) {
- if (roomId !== null || isRoomOptionVisible) {
- roomId = null;
- if (cords.detail === 0) openerRef.current.click();
- return;
- }
- openerRef.current.style.transform = `translate(${cords.x}px, ${cords.y}px)`;
- roomId = rId;
- openerRef.current.click();
- forceUpdate();
- }
-
- const afterRoomOptionsToggle = (isVisible) => {
- isRoomOptionVisible = isVisible;
- if (!isVisible) {
- setTimeout(() => {
- if (!isRoomOptionVisible) roomId = null;
- }, 500);
- }
- };
-
- useEffect(() => {
- navigation.on(cons.events.navigation.ROOMOPTIONS_OPENED, openRoomOptions);
- return () => {
- navigation.on(cons.events.navigation.ROOMOPTIONS_OPENED, openRoomOptions);
- };
- }, []);
-
- const handleMarkAsRead = () => {
- const mx = initMatrix.matrixClient;
- const room = mx.getRoom(roomId);
- if (!room) return;
- const events = room.getLiveTimeline().getEvents();
- mx.sendReadReceipt(events[events.length - 1]);
- };
-
- const handleInviteClick = () => openInviteUser(roomId);
- const handleLeaveClick = (toggleMenu) => {
- if (confirm('Are you really want to leave this room?')) {
- roomActions.leave(roomId);
- toggleMenu();
- }
- };
-
- const mx = initMatrix.matrixClient;
- const room = mx.getRoom(roomId);
- const canInvite = room?.canInvite(mx.getUserId());
-
- return (
- <ContextMenu
- afterToggle={afterRoomOptionsToggle}
- maxWidth={298}
- content={(toggleMenu) => (
- <>
- <MenuHeader>{twemojify(`Options for ${initMatrix.matrixClient.getRoom(roomId)?.name}`)}</MenuHeader>
- <MenuItem
- iconSrc={TickMarkIC}
- onClick={() => {
- handleMarkAsRead(); toggleMenu();
- }}
- >
- Mark as read
- </MenuItem>
- <MenuItem
- disabled={!canInvite}
- iconSrc={AddUserIC}
- onClick={() => {
- handleInviteClick(); toggleMenu();
- }}
- >
- Invite
- </MenuItem>
- <MenuItem iconSrc={LeaveArrowIC} variant="danger" onClick={() => handleLeaveClick(toggleMenu)}>Leave</MenuItem>
- <MenuHeader>Notification</MenuHeader>
- {roomId && <RoomNotification roomId={roomId} />}
- </>
- )}
- render={(toggleMenu) => (
- <input
- ref={openerRef}
- onClick={toggleMenu}
- type="button"
- style={{
- width: '32px',
- height: '32px',
- backgroundColor: 'transparent',
- position: 'absolute',
- top: 0,
- left: 0,
- padding: 0,
- border: 'none',
- visibility: 'hidden',
- }}
- />
- )}
- />
- );
-}
-
-export default RoomOptions;
import initMatrix from '../../../client/initMatrix';
import cons from '../../../client/state/cons';
import navigation from '../../../client/state/navigation';
-import { toggleRoomSettings, openRoomOptions } from '../../../client/action/navigation';
+import { toggleRoomSettings, openReusableContextMenu } from '../../../client/action/navigation';
import { togglePeopleDrawer } from '../../../client/action/settings';
import colorMXID from '../../../util/colorMXID';
import { getEventCords } from '../../../util/common';
import IconButton from '../../atoms/button/IconButton';
import Header, { TitleWrapper } from '../../atoms/header/Header';
import Avatar from '../../atoms/avatar/Avatar';
+import RoomOptions from '../../molecules/room-optons/RoomOptions';
import UserIC from '../../../../public/res/ic/outlined/user.svg';
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
};
}, [roomId]);
+ const openRoomOptions = (e) => {
+ openReusableContextMenu(
+ 'bottom',
+ getEventCords(e, '.ic-btn'),
+ (closeMenu) => <RoomOptions roomId={roomId} afterOptionSelect={closeMenu} />,
+ );
+ };
+
return (
<Header>
<button
</button>
<IconButton onClick={togglePeopleDrawer} tooltip="People" src={UserIC} />
<IconButton
- onClick={(e) => openRoomOptions(getEventCords(e), roomId)}
+ onClick={openRoomOptions}
tooltip="Options"
src={VerticalMenuIC}
/>
import Windows from '../../organisms/pw/Windows';
import Dialogs from '../../organisms/pw/Dialogs';
import EmojiBoardOpener from '../../organisms/emoji-board/EmojiBoardOpener';
-import RoomOptions from '../../organisms/room-optons/RoomOptions';
import logout from '../../../client/action/logout';
import initMatrix from '../../../client/initMatrix';
<Windows />
<Dialogs />
<EmojiBoardOpener />
- <RoomOptions />
<ReusableContextMenu />
</div>
);
});
}
-export function openRoomOptions(cords, roomId) {
- appDispatcher.dispatch({
- type: cons.actions.navigation.OPEN_ROOMOPTIONS,
- cords,
- roomId,
- });
-}
-
export function replyTo(userId, eventId, body) {
appDispatcher.dispatch({
type: cons.actions.navigation.CLICK_REPLY_TO,
OPEN_SETTINGS: 'OPEN_SETTINGS',
OPEN_EMOJIBOARD: 'OPEN_EMOJIBOARD',
OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
- OPEN_ROOMOPTIONS: 'OPEN_ROOMOPTIONS',
CLICK_REPLY_TO: 'CLICK_REPLY_TO',
OPEN_SEARCH: 'OPEN_SEARCH',
OPEN_REUSABLE_CONTEXT_MENU: 'OPEN_REUSABLE_CONTEXT_MENU',
PROFILE_VIEWER_OPENED: 'PROFILE_VIEWER_OPENED',
EMOJIBOARD_OPENED: 'EMOJIBOARD_OPENED',
READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
- ROOMOPTIONS_OPENED: 'ROOMOPTIONS_OPENED',
REPLY_TO_CLICKED: 'REPLY_TO_CLICKED',
SEARCH_OPENED: 'SEARCH_OPENED',
REUSABLE_CONTEXT_MENU_OPENED: 'REUSABLE_CONTEXT_MENU_OPENED',
action.userIds,
);
},
- [cons.actions.navigation.OPEN_ROOMOPTIONS]: () => {
- this.emit(
- cons.events.navigation.ROOMOPTIONS_OPENED,
- action.cords,
- action.roomId,
- );
- },
[cons.actions.navigation.CLICK_REPLY_TO]: () => {
this.emit(
cons.events.navigation.REPLY_TO_CLICKED,