cinny/src/app/organisms/navigation/SideBar.jsx

223 lines
7.4 KiB
React
Raw Normal View History

2021-07-28 13:15:52 +00: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';
2021-08-30 03:01:13 +00:00
import {
selectTab, openInviteList, openSearch,
openSettings, openReusableContextMenu,
2021-08-30 03:01:13 +00:00
} from '../../../client/action/navigation';
import { abbreviateNumber, getEventCords } from '../../../util/common';
2021-07-28 13:15:52 +00:00
import ScrollView from '../../atoms/scroll/ScrollView';
import SidebarAvatar from '../../molecules/sidebar-avatar/SidebarAvatar';
import SpaceOptions from '../../molecules/space-options/SpaceOptions';
2021-07-28 13:15:52 +00:00
import HomeIC from '../../../../public/res/ic/outlined/home.svg';
import UserIC from '../../../../public/res/ic/outlined/user.svg';
import SearchIC from '../../../../public/res/ic/outlined/search.svg';
2021-07-28 13:15:52 +00:00
import InviteIC from '../../../../public/res/ic/outlined/invite.svg';
import { useSelectedTab } from '../../hooks/useSelectedTab';
import { useSpaceShortcut } from '../../hooks/useSpaceShortcut';
2021-07-28 13:15:52 +00:00
function ProfileAvatarMenu() {
const mx = initMatrix.matrixClient;
const [profile, setProfile] = useState({
avatarUrl: null,
displayName: mx.getUser(mx.getUserId()).displayName,
});
useEffect(() => {
const user = mx.getUser(mx.getUserId());
const setNewProfile = (avatarUrl, displayName) => setProfile({
avatarUrl: avatarUrl || null,
displayName: displayName || profile.displayName,
});
const onAvatarChange = (event, myUser) => {
setNewProfile(myUser.avatarUrl, myUser.displayName);
};
mx.getProfileInfo(mx.getUserId()).then((info) => {
setNewProfile(info.avatar_url, info.displayname);
});
user.on('User.avatarUrl', onAvatarChange);
return () => {
user.removeListener('User.avatarUrl', onAvatarChange);
};
}, []);
2021-07-28 13:15:52 +00:00
return (
<SidebarAvatar
onClick={openSettings}
tooltip={profile.displayName}
imageSrc={profile.avatarUrl !== null ? mx.mxcUrlToHttp(profile.avatarUrl, 42, 42, 'crop') : null}
bgColor={colorMXID(mx.getUserId())}
text={profile.displayName}
2021-07-28 13:15:52 +00:00
/>
);
}
function useTotalInvites() {
const { roomList } = initMatrix;
2021-09-05 13:26:34 +00:00
const totalInviteCount = () => roomList.inviteRooms.size
+ roomList.inviteSpaces.size
+ roomList.inviteDirects.size;
2021-07-28 13:15:52 +00:00
const [totalInvites, updateTotalInvites] = useState(totalInviteCount());
useEffect(() => {
const onInviteListChange = () => {
updateTotalInvites(totalInviteCount());
};
roomList.on(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
2021-07-28 13:15:52 +00:00
return () => {
roomList.removeListener(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
};
}, []);
return [totalInvites];
}
function SideBar() {
const { roomList, notifications } = initMatrix;
const mx = initMatrix.matrixClient;
const [selectedTab] = useSelectedTab();
const [spaceShortcut] = useSpaceShortcut();
const [totalInvites] = useTotalInvites();
const [, forceUpdate] = useState({});
useEffect(() => {
function onNotificationChanged(roomId, total, prevTotal) {
if (total === prevTotal) return;
forceUpdate({});
}
notifications.on(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
return () => {
notifications.removeListener(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
2021-07-28 13:15:52 +00:00
};
}, []);
const openSpaceOptions = (e, spaceId) => {
e.preventDefault();
openReusableContextMenu(
'right',
getEventCords(e, '.sidebar-avatar'),
(closeMenu) => <SpaceOptions roomId={spaceId} afterOptionSelect={closeMenu} />,
);
};
function getHomeNoti() {
const orphans = roomList.getOrphans();
let noti = null;
orphans.forEach((roomId) => {
if (roomList.spaceShortcut.has(roomId)) return;
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 13:15:52 +00:00
return (
<div className="sidebar">
<div className="sidebar__scrollable">
<ScrollView invisible>
<div className="scrollable-content">
<div className="featured-container">
<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-07-28 13:15:52 +00:00
</div>
<div className="sidebar-divider" />
2021-09-05 13:26:34 +00:00
<div className="space-container">
{
spaceShortcut.map((shortcut) => {
2021-09-05 13:26:34 +00:00
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}
isUnread={notifications.hasNoti(sRoomId)}
notificationCount={abbreviateNumber(notifications.getTotalNoti(sRoomId))}
isAlert={notifications.getHighlightNoti(sRoomId) !== 0}
2021-09-05 13:26:34 +00:00
onClick={() => selectTab(shortcut)}
onContextMenu={(e) => openSpaceOptions(e, sRoomId)}
2021-09-05 13:26:34 +00:00
/>
);
})
}
</div>
2021-07-28 13:15:52 +00:00
</div>
</ScrollView>
</div>
<div className="sidebar__sticky">
<div className="sidebar-divider" />
<div className="sticky-container">
<SidebarAvatar
onClick={() => openSearch()}
tooltip="Search"
iconSrc={SearchIC}
/>
2021-07-28 13:15:52 +00:00
{ totalInvites !== 0 && (
<SidebarAvatar
isUnread
notificationCount={totalInvites}
isAlert
2021-07-28 13:15:52 +00:00
onClick={() => openInviteList()}
tooltip="Invites"
iconSrc={InviteIC}
/>
)}
<ProfileAvatarMenu />
</div>
</div>
</div>
);
}
export default SideBar;