2021-07-28 15:15:52 +02:00
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
import './SideBar.scss';
|
|
|
|
|
|
|
|
import initMatrix from '../../../client/initMatrix';
|
|
|
|
import cons from '../../../client/state/cons';
|
|
|
|
import colorMXID from '../../../util/colorMXID';
|
|
|
|
import logout from '../../../client/action/logout';
|
2021-08-30 05:01:13 +02:00
|
|
|
import {
|
2021-09-05 15:26:34 +02:00
|
|
|
selectTab, openInviteList, openPublicRooms, openSettings,
|
2021-08-30 05:01:13 +02:00
|
|
|
} from '../../../client/action/navigation';
|
|
|
|
import navigation from '../../../client/state/navigation';
|
2021-09-12 17:14:13 +02:00
|
|
|
import { abbreviateNumber } from '../../../util/common';
|
2021-07-28 15:15:52 +02:00
|
|
|
|
|
|
|
import ScrollView from '../../atoms/scroll/ScrollView';
|
|
|
|
import SidebarAvatar from '../../molecules/sidebar-avatar/SidebarAvatar';
|
|
|
|
import ContextMenu, { MenuItem, MenuHeader, MenuBorder } from '../../atoms/context-menu/ContextMenu';
|
|
|
|
|
|
|
|
import HomeIC from '../../../../public/res/ic/outlined/home.svg';
|
|
|
|
import UserIC from '../../../../public/res/ic/outlined/user.svg';
|
|
|
|
import HashSearchIC from '../../../../public/res/ic/outlined/hash-search.svg';
|
|
|
|
import InviteIC from '../../../../public/res/ic/outlined/invite.svg';
|
|
|
|
import SettingsIC from '../../../../public/res/ic/outlined/settings.svg';
|
|
|
|
import PowerIC from '../../../../public/res/ic/outlined/power.svg';
|
|
|
|
|
|
|
|
function ProfileAvatarMenu() {
|
|
|
|
const mx = initMatrix.matrixClient;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<ContextMenu
|
|
|
|
content={(hideMenu) => (
|
|
|
|
<>
|
|
|
|
<MenuHeader>{mx.getUserId()}</MenuHeader>
|
|
|
|
{/* <MenuItem iconSrc={UserIC} onClick={() => ''}>Profile</MenuItem> */}
|
|
|
|
{/* <MenuItem iconSrc={BellIC} onClick={() => ''}>Notification settings</MenuItem> */}
|
|
|
|
<MenuItem
|
|
|
|
iconSrc={SettingsIC}
|
|
|
|
onClick={() => { hideMenu(); openSettings(); }}
|
|
|
|
>
|
|
|
|
Settings
|
|
|
|
</MenuItem>
|
|
|
|
<MenuBorder />
|
|
|
|
<MenuItem iconSrc={PowerIC} variant="danger" onClick={logout}>Logout</MenuItem>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
render={(toggleMenu) => (
|
|
|
|
<SidebarAvatar
|
|
|
|
onClick={toggleMenu}
|
|
|
|
tooltip={mx.getUser(mx.getUserId()).displayName}
|
|
|
|
imageSrc={mx.getUser(mx.getUserId()).avatarUrl !== null ? mx.mxcUrlToHttp(mx.getUser(mx.getUserId()).avatarUrl, 42, 42, 'crop') : null}
|
|
|
|
bgColor={colorMXID(mx.getUserId())}
|
|
|
|
text={mx.getUser(mx.getUserId()).displayName.slice(0, 1)}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-08-30 05:01:13 +02:00
|
|
|
function SideBar() {
|
2021-09-12 17:14:13 +02:00
|
|
|
const { roomList, notifications } = initMatrix;
|
2021-09-05 15:26:34 +02:00
|
|
|
const mx = initMatrix.matrixClient;
|
|
|
|
const totalInviteCount = () => roomList.inviteRooms.size
|
|
|
|
+ roomList.inviteSpaces.size
|
|
|
|
+ roomList.inviteDirects.size;
|
2021-07-28 15:15:52 +02:00
|
|
|
|
|
|
|
const [totalInvites, updateTotalInvites] = useState(totalInviteCount());
|
2021-09-05 15:26:34 +02:00
|
|
|
const [selectedTab, setSelectedTab] = useState(navigation.selectedTab);
|
|
|
|
const [, forceUpdate] = useState({});
|
2021-07-28 15:15:52 +02:00
|
|
|
|
2021-09-05 15:26:34 +02:00
|
|
|
function onTabSelected(tabId) {
|
2021-09-03 14:28:01 +02:00
|
|
|
setSelectedTab(tabId);
|
2021-08-30 05:01:13 +02:00
|
|
|
}
|
2021-07-28 15:15:52 +02:00
|
|
|
function onInviteListChange() {
|
|
|
|
updateTotalInvites(totalInviteCount());
|
|
|
|
}
|
2021-09-05 15:26:34 +02:00
|
|
|
function onSpaceShortcutUpdated() {
|
|
|
|
forceUpdate({});
|
|
|
|
}
|
2021-09-12 17:14:13 +02:00
|
|
|
function onNotificationChanged(roomId, total, prevTotal) {
|
|
|
|
if (total === prevTotal) return;
|
|
|
|
forceUpdate({});
|
|
|
|
}
|
2021-07-28 15:15:52 +02:00
|
|
|
|
|
|
|
useEffect(() => {
|
2021-09-05 15:26:34 +02:00
|
|
|
navigation.on(cons.events.navigation.TAB_SELECTED, onTabSelected);
|
|
|
|
roomList.on(cons.events.roomList.SPACE_SHORTCUT_UPDATED, onSpaceShortcutUpdated);
|
2021-09-12 17:14:13 +02:00
|
|
|
roomList.on(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
|
|
|
notifications.on(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
|
2021-07-28 15:15:52 +02:00
|
|
|
|
|
|
|
return () => {
|
2021-09-05 15:26:34 +02:00
|
|
|
navigation.removeListener(cons.events.navigation.TAB_SELECTED, onTabSelected);
|
|
|
|
roomList.removeListener(cons.events.roomList.SPACE_SHORTCUT_UPDATED, onSpaceShortcutUpdated);
|
2021-09-12 17:14:13 +02:00
|
|
|
roomList.removeListener(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
|
|
|
notifications.removeListener(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
|
2021-07-28 15:15:52 +02:00
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
2021-09-12 17:14:13 +02:00
|
|
|
function getHomeNoti() {
|
|
|
|
const orphans = roomList.getOrphans();
|
|
|
|
let noti = null;
|
|
|
|
|
|
|
|
orphans.forEach((roomId) => {
|
|
|
|
if (!notifications.hasNoti(roomId)) return;
|
|
|
|
if (noti === null) noti = { total: 0, highlight: 0 };
|
|
|
|
const childNoti = notifications.getNoti(roomId);
|
|
|
|
noti.total += childNoti.total;
|
|
|
|
noti.highlight += childNoti.highlight;
|
|
|
|
});
|
|
|
|
|
|
|
|
return noti;
|
|
|
|
}
|
|
|
|
function getDMsNoti() {
|
|
|
|
if (roomList.directs.size === 0) return null;
|
|
|
|
let noti = null;
|
|
|
|
|
|
|
|
[...roomList.directs].forEach((roomId) => {
|
|
|
|
if (!notifications.hasNoti(roomId)) return;
|
|
|
|
if (noti === null) noti = { total: 0, highlight: 0 };
|
|
|
|
const childNoti = notifications.getNoti(roomId);
|
|
|
|
noti.total += childNoti.total;
|
|
|
|
noti.highlight += childNoti.highlight;
|
|
|
|
});
|
|
|
|
|
|
|
|
return noti;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: bellow operations are heavy.
|
|
|
|
// refactor this component into more smaller components.
|
|
|
|
const dmsNoti = getDMsNoti();
|
|
|
|
const homeNoti = getHomeNoti();
|
|
|
|
|
2021-07-28 15:15:52 +02:00
|
|
|
return (
|
|
|
|
<div className="sidebar">
|
|
|
|
<div className="sidebar__scrollable">
|
|
|
|
<ScrollView invisible>
|
|
|
|
<div className="scrollable-content">
|
|
|
|
<div className="featured-container">
|
2021-09-12 17:14:13 +02:00
|
|
|
<SidebarAvatar
|
|
|
|
active={selectedTab === cons.tabs.HOME}
|
|
|
|
onClick={() => selectTab(cons.tabs.HOME)}
|
|
|
|
tooltip="Home"
|
|
|
|
iconSrc={HomeIC}
|
|
|
|
isUnread={homeNoti !== null}
|
|
|
|
notificationCount={homeNoti !== null ? abbreviateNumber(homeNoti.total) : 0}
|
|
|
|
isAlert={homeNoti?.highlight > 0}
|
|
|
|
/>
|
|
|
|
<SidebarAvatar
|
|
|
|
active={selectedTab === cons.tabs.DIRECTS}
|
|
|
|
onClick={() => selectTab(cons.tabs.DIRECTS)}
|
|
|
|
tooltip="People"
|
|
|
|
iconSrc={UserIC}
|
|
|
|
isUnread={dmsNoti !== null}
|
|
|
|
notificationCount={dmsNoti !== null ? abbreviateNumber(dmsNoti.total) : 0}
|
|
|
|
isAlert={dmsNoti?.highlight > 0}
|
|
|
|
/>
|
2021-08-31 15:13:31 +02:00
|
|
|
<SidebarAvatar onClick={() => openPublicRooms()} tooltip="Public rooms" iconSrc={HashSearchIC} />
|
2021-07-28 15:15:52 +02:00
|
|
|
</div>
|
|
|
|
<div className="sidebar-divider" />
|
2021-09-05 15:26:34 +02:00
|
|
|
<div className="space-container">
|
|
|
|
{
|
|
|
|
[...roomList.spaceShortcut].map((shortcut) => {
|
|
|
|
const sRoomId = shortcut;
|
|
|
|
const room = mx.getRoom(sRoomId);
|
|
|
|
return (
|
|
|
|
<SidebarAvatar
|
|
|
|
active={selectedTab === sRoomId}
|
|
|
|
key={sRoomId}
|
|
|
|
tooltip={room.name}
|
|
|
|
bgColor={colorMXID(room.roomId)}
|
|
|
|
imageSrc={room.getAvatarUrl(initMatrix.matrixClient.baseUrl, 42, 42, 'crop') || null}
|
|
|
|
text={room.name.slice(0, 1)}
|
2021-09-12 17:14:13 +02:00
|
|
|
isUnread={notifications.hasNoti(sRoomId)}
|
|
|
|
notificationCount={abbreviateNumber(notifications.getTotalNoti(sRoomId))}
|
|
|
|
isAlert={notifications.getHighlightNoti(sRoomId) !== 0}
|
2021-09-05 15:26:34 +02:00
|
|
|
onClick={() => selectTab(shortcut)}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</div>
|
2021-07-28 15:15:52 +02:00
|
|
|
</div>
|
|
|
|
</ScrollView>
|
|
|
|
</div>
|
|
|
|
<div className="sidebar__sticky">
|
|
|
|
<div className="sidebar-divider" />
|
|
|
|
<div className="sticky-container">
|
|
|
|
{ totalInvites !== 0 && (
|
|
|
|
<SidebarAvatar
|
2021-09-12 17:14:13 +02:00
|
|
|
isUnread
|
|
|
|
notificationCount={totalInvites}
|
|
|
|
isAlert
|
2021-07-28 15:15:52 +02:00
|
|
|
onClick={() => openInviteList()}
|
|
|
|
tooltip="Invites"
|
|
|
|
iconSrc={InviteIC}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<ProfileAvatarMenu />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default SideBar;
|