Refactor room options

Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
Ajay Bura 2022-01-13 18:30:43 +05:30
parent ba6d9d0c23
commit 60c44da974
8 changed files with 90 additions and 148 deletions

View file

@ -0,0 +1,67 @@
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;

View file

@ -4,12 +4,13 @@ import PropTypes from 'prop-types';
import initMatrix from '../../../client/initMatrix'; import initMatrix from '../../../client/initMatrix';
import navigation from '../../../client/state/navigation'; 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 { createSpaceShortcut, deleteSpaceShortcut } from '../../../client/action/room';
import { getEventCords, abbreviateNumber } from '../../../util/common'; import { getEventCords, abbreviateNumber } from '../../../util/common';
import IconButton from '../../atoms/button/IconButton'; import IconButton from '../../atoms/button/IconButton';
import RoomSelector from '../../molecules/room-selector/RoomSelector'; import RoomSelector from '../../molecules/room-selector/RoomSelector';
import RoomOptions from '../../molecules/room-optons/RoomOptions';
import HashIC from '../../../../public/res/ic/outlined/hash.svg'; import HashIC from '../../../../public/res/ic/outlined/hash.svg';
import HashGlobeIC from '../../../../public/res/ic/outlined/hash-globe.svg'; import HashGlobeIC from '../../../../public/res/ic/outlined/hash-globe.svg';
@ -49,6 +50,15 @@ function Selector({
}; };
}, []); }, []);
const openRoomOptions = (e) => {
e.preventDefault();
openReusableContextMenu(
'right',
getEventCords(e, '.room-selector'),
(closeMenu) => <RoomOptions roomId={roomId} afterOptionSelect={closeMenu} />,
);
};
const joinRuleToIconSrc = (joinRule) => ({ const joinRuleToIconSrc = (joinRule) => ({
restricted: () => (room.isSpaceRoom() ? SpaceIC : HashIC), restricted: () => (room.isSpaceRoom() ? SpaceIC : HashIC),
invite: () => (room.isSpaceRoom() ? SpaceLockIC : HashLockIC), invite: () => (room.isSpaceRoom() ? SpaceLockIC : HashLockIC),
@ -102,7 +112,7 @@ function Selector({
tooltip="Options" tooltip="Options"
tooltipPlacement="right" tooltipPlacement="right"
src={VerticalMenuIC} src={VerticalMenuIC}
onClick={(e) => openRoomOptions(getEventCords(e), roomId)} onClick={openRoomOptions}
/> />
)} )}
/> />

View file

@ -1,125 +0,0 @@
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;

View file

@ -8,7 +8,7 @@ import { blurOnBubbling } from '../../atoms/button/script';
import initMatrix from '../../../client/initMatrix'; import initMatrix from '../../../client/initMatrix';
import cons from '../../../client/state/cons'; import cons from '../../../client/state/cons';
import navigation from '../../../client/state/navigation'; 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 { togglePeopleDrawer } from '../../../client/action/settings';
import colorMXID from '../../../util/colorMXID'; import colorMXID from '../../../util/colorMXID';
import { getEventCords } from '../../../util/common'; import { getEventCords } from '../../../util/common';
@ -18,6 +18,7 @@ import RawIcon from '../../atoms/system-icons/RawIcon';
import IconButton from '../../atoms/button/IconButton'; import IconButton from '../../atoms/button/IconButton';
import Header, { TitleWrapper } from '../../atoms/header/Header'; import Header, { TitleWrapper } from '../../atoms/header/Header';
import Avatar from '../../atoms/avatar/Avatar'; import Avatar from '../../atoms/avatar/Avatar';
import RoomOptions from '../../molecules/room-optons/RoomOptions';
import UserIC from '../../../../public/res/ic/outlined/user.svg'; import UserIC from '../../../../public/res/ic/outlined/user.svg';
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg'; import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
@ -60,6 +61,14 @@ function RoomViewHeader({ roomId }) {
}; };
}, [roomId]); }, [roomId]);
const openRoomOptions = (e) => {
openReusableContextMenu(
'bottom',
getEventCords(e, '.ic-btn'),
(closeMenu) => <RoomOptions roomId={roomId} afterOptionSelect={closeMenu} />,
);
};
return ( return (
<Header> <Header>
<button <button
@ -77,7 +86,7 @@ function RoomViewHeader({ roomId }) {
</button> </button>
<IconButton onClick={togglePeopleDrawer} tooltip="People" src={UserIC} /> <IconButton onClick={togglePeopleDrawer} tooltip="People" src={UserIC} />
<IconButton <IconButton
onClick={(e) => openRoomOptions(getEventCords(e), roomId)} onClick={openRoomOptions}
tooltip="Options" tooltip="Options"
src={VerticalMenuIC} src={VerticalMenuIC}
/> />

View file

@ -9,7 +9,6 @@ import Room from '../../organisms/room/Room';
import Windows from '../../organisms/pw/Windows'; import Windows from '../../organisms/pw/Windows';
import Dialogs from '../../organisms/pw/Dialogs'; import Dialogs from '../../organisms/pw/Dialogs';
import EmojiBoardOpener from '../../organisms/emoji-board/EmojiBoardOpener'; import EmojiBoardOpener from '../../organisms/emoji-board/EmojiBoardOpener';
import RoomOptions from '../../organisms/room-optons/RoomOptions';
import logout from '../../../client/action/logout'; import logout from '../../../client/action/logout';
import initMatrix from '../../../client/initMatrix'; import initMatrix from '../../../client/initMatrix';
@ -66,7 +65,6 @@ function Client() {
<Windows /> <Windows />
<Dialogs /> <Dialogs />
<EmojiBoardOpener /> <EmojiBoardOpener />
<RoomOptions />
<ReusableContextMenu /> <ReusableContextMenu />
</div> </div>
); );

View file

@ -87,14 +87,6 @@ export function openReadReceipts(roomId, userIds) {
}); });
} }
export function openRoomOptions(cords, roomId) {
appDispatcher.dispatch({
type: cons.actions.navigation.OPEN_ROOMOPTIONS,
cords,
roomId,
});
}
export function replyTo(userId, eventId, body) { export function replyTo(userId, eventId, body) {
appDispatcher.dispatch({ appDispatcher.dispatch({
type: cons.actions.navigation.CLICK_REPLY_TO, type: cons.actions.navigation.CLICK_REPLY_TO,

View file

@ -39,7 +39,6 @@ const cons = {
OPEN_SETTINGS: 'OPEN_SETTINGS', OPEN_SETTINGS: 'OPEN_SETTINGS',
OPEN_EMOJIBOARD: 'OPEN_EMOJIBOARD', OPEN_EMOJIBOARD: 'OPEN_EMOJIBOARD',
OPEN_READRECEIPTS: 'OPEN_READRECEIPTS', OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
OPEN_ROOMOPTIONS: 'OPEN_ROOMOPTIONS',
CLICK_REPLY_TO: 'CLICK_REPLY_TO', CLICK_REPLY_TO: 'CLICK_REPLY_TO',
OPEN_SEARCH: 'OPEN_SEARCH', OPEN_SEARCH: 'OPEN_SEARCH',
OPEN_REUSABLE_CONTEXT_MENU: 'OPEN_REUSABLE_CONTEXT_MENU', OPEN_REUSABLE_CONTEXT_MENU: 'OPEN_REUSABLE_CONTEXT_MENU',
@ -76,7 +75,6 @@ const cons = {
PROFILE_VIEWER_OPENED: 'PROFILE_VIEWER_OPENED', PROFILE_VIEWER_OPENED: 'PROFILE_VIEWER_OPENED',
EMOJIBOARD_OPENED: 'EMOJIBOARD_OPENED', EMOJIBOARD_OPENED: 'EMOJIBOARD_OPENED',
READRECEIPTS_OPENED: 'READRECEIPTS_OPENED', READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
ROOMOPTIONS_OPENED: 'ROOMOPTIONS_OPENED',
REPLY_TO_CLICKED: 'REPLY_TO_CLICKED', REPLY_TO_CLICKED: 'REPLY_TO_CLICKED',
SEARCH_OPENED: 'SEARCH_OPENED', SEARCH_OPENED: 'SEARCH_OPENED',
REUSABLE_CONTEXT_MENU_OPENED: 'REUSABLE_CONTEXT_MENU_OPENED', REUSABLE_CONTEXT_MENU_OPENED: 'REUSABLE_CONTEXT_MENU_OPENED',

View file

@ -126,13 +126,6 @@ class Navigation extends EventEmitter {
action.userIds, action.userIds,
); );
}, },
[cons.actions.navigation.OPEN_ROOMOPTIONS]: () => {
this.emit(
cons.events.navigation.ROOMOPTIONS_OPENED,
action.cords,
action.roomId,
);
},
[cons.actions.navigation.CLICK_REPLY_TO]: () => { [cons.actions.navigation.CLICK_REPLY_TO]: () => {
this.emit( this.emit(
cons.events.navigation.REPLY_TO_CLICKED, cons.events.navigation.REPLY_TO_CLICKED,