Add dnd space shortcut (#153)
Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
parent
a7a5b08ad8
commit
b8fe4c937e
3 changed files with 353 additions and 105 deletions
129
package-lock.json
generated
129
package-lock.json
generated
|
@ -31,6 +31,8 @@
|
|||
"prop-types": "^15.8.1",
|
||||
"react": "^17.0.2",
|
||||
"react-autosize-textarea": "^7.1.0",
|
||||
"react-dnd": "^15.1.1",
|
||||
"react-dnd-html5-backend": "^15.1.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-google-recaptcha": "^2.1.0",
|
||||
"react-modal": "^3.14.4",
|
||||
|
@ -2422,6 +2424,21 @@
|
|||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-dnd/asap": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.0.tgz",
|
||||
"integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ=="
|
||||
},
|
||||
"node_modules/@react-dnd/invariant": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-3.0.0.tgz",
|
||||
"integrity": "sha512-keberJRIqPX15IK3SWS/iO1t/kGETiL1oczKrDitAaMnQ+kpHf81l3MrRmFjvfqcnApE+izEvwM6GsyoIcpsVA=="
|
||||
},
|
||||
"node_modules/@react-dnd/shallowequal": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-3.0.0.tgz",
|
||||
"integrity": "sha512-1ELWQdJB2UrCXTKK5cCD9uGLLIwECLIEdttKA255owdpchtXohIjZBTlFJszwYi2ZKe2Do+QvUzsGyGCMNwbdw=="
|
||||
},
|
||||
"node_modules/@tippyjs/react": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
||||
|
@ -2605,7 +2622,7 @@
|
|||
"version": "16.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
|
||||
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
|
@ -5267,6 +5284,16 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dnd-core": {
|
||||
"version": "15.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-15.1.1.tgz",
|
||||
"integrity": "sha512-Mtj/Sltcx7stVXzeDg4g7roTe/AmzRuIf/FYOxX6F8gULbY54w066BlErBOzQfn9RIJ3gAYLGX7wvVvoBSq7ig==",
|
||||
"dependencies": {
|
||||
"@react-dnd/asap": "4.0.0",
|
||||
"@react-dnd/invariant": "3.0.0",
|
||||
"redux": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/dns-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||
|
@ -11324,6 +11351,43 @@
|
|||
"react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dnd": {
|
||||
"version": "15.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-15.1.1.tgz",
|
||||
"integrity": "sha512-QLrHtPU08U4c5zop0ANeqrHXaQw2EWLMn8DQoN6/e4eSN/UbB84P49/80Qg0MEF29VLB5vikSoiFh9N8ASNmpQ==",
|
||||
"dependencies": {
|
||||
"@react-dnd/invariant": "3.0.0",
|
||||
"@react-dnd/shallowequal": "3.0.0",
|
||||
"dnd-core": "15.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"hoist-non-react-statics": "^3.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/hoist-non-react-statics": ">= 3.3.1",
|
||||
"@types/node": ">= 12",
|
||||
"@types/react": ">= 16",
|
||||
"react": ">= 16.14"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/hoist-non-react-statics": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-dnd-html5-backend": {
|
||||
"version": "15.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-15.1.2.tgz",
|
||||
"integrity": "sha512-mem9QbutUF+aA2YC1y47G3ECjnYV/sCYKSnu5Jd7cbg3fLMPAwbnTf/JayYdnCH5l3eg9akD9dQt+cD0UdF8QQ==",
|
||||
"dependencies": {
|
||||
"dnd-core": "15.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
|
@ -11434,6 +11498,14 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
|
||||
"integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerate": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||
|
@ -15715,6 +15787,21 @@
|
|||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.2.tgz",
|
||||
"integrity": "sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ=="
|
||||
},
|
||||
"@react-dnd/asap": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.0.tgz",
|
||||
"integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ=="
|
||||
},
|
||||
"@react-dnd/invariant": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-3.0.0.tgz",
|
||||
"integrity": "sha512-keberJRIqPX15IK3SWS/iO1t/kGETiL1oczKrDitAaMnQ+kpHf81l3MrRmFjvfqcnApE+izEvwM6GsyoIcpsVA=="
|
||||
},
|
||||
"@react-dnd/shallowequal": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-3.0.0.tgz",
|
||||
"integrity": "sha512-1ELWQdJB2UrCXTKK5cCD9uGLLIwECLIEdttKA255owdpchtXohIjZBTlFJszwYi2ZKe2Do+QvUzsGyGCMNwbdw=="
|
||||
},
|
||||
"@tippyjs/react": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
||||
|
@ -15891,7 +15978,7 @@
|
|||
"version": "16.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
|
||||
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"@types/qs": {
|
||||
"version": "6.9.7",
|
||||
|
@ -18041,6 +18128,16 @@
|
|||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"dnd-core": {
|
||||
"version": "15.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-15.1.1.tgz",
|
||||
"integrity": "sha512-Mtj/Sltcx7stVXzeDg4g7roTe/AmzRuIf/FYOxX6F8gULbY54w066BlErBOzQfn9RIJ3gAYLGX7wvVvoBSq7ig==",
|
||||
"requires": {
|
||||
"@react-dnd/asap": "4.0.0",
|
||||
"@react-dnd/invariant": "3.0.0",
|
||||
"redux": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"dns-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||
|
@ -22591,6 +22688,26 @@
|
|||
"prop-types": "^15.5.6"
|
||||
}
|
||||
},
|
||||
"react-dnd": {
|
||||
"version": "15.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-15.1.1.tgz",
|
||||
"integrity": "sha512-QLrHtPU08U4c5zop0ANeqrHXaQw2EWLMn8DQoN6/e4eSN/UbB84P49/80Qg0MEF29VLB5vikSoiFh9N8ASNmpQ==",
|
||||
"requires": {
|
||||
"@react-dnd/invariant": "3.0.0",
|
||||
"@react-dnd/shallowequal": "3.0.0",
|
||||
"dnd-core": "15.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"hoist-non-react-statics": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"react-dnd-html5-backend": {
|
||||
"version": "15.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-15.1.2.tgz",
|
||||
"integrity": "sha512-mem9QbutUF+aA2YC1y47G3ECjnYV/sCYKSnu5Jd7cbg3fLMPAwbnTf/JayYdnCH5l3eg9akD9dQt+cD0UdF8QQ==",
|
||||
"requires": {
|
||||
"dnd-core": "15.1.1"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
|
@ -22676,6 +22793,14 @@
|
|||
"resolve": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"redux": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
|
||||
"integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
},
|
||||
"regenerate": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
"prop-types": "^15.8.1",
|
||||
"react": "^17.0.2",
|
||||
"react-autosize-textarea": "^7.1.0",
|
||||
"react-dnd": "^15.1.1",
|
||||
"react-dnd-html5-backend": "^15.1.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-google-recaptcha": "^2.1.0",
|
||||
"react-modal": "^3.14.4",
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './SideBar.scss';
|
||||
|
||||
import { DndProvider, useDrag, useDrop } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
|
||||
import initMatrix from '../../../client/initMatrix';
|
||||
import cons from '../../../client/state/cons';
|
||||
import colorMXID from '../../../util/colorMXID';
|
||||
|
@ -8,6 +12,7 @@ import {
|
|||
selectTab, openShortcutSpaces, openInviteList,
|
||||
openSearch, openSettings, openReusableContextMenu,
|
||||
} from '../../../client/action/navigation';
|
||||
import { moveSpaceShortcut } from '../../../client/action/accountData';
|
||||
import { abbreviateNumber, getEventCords } from '../../../util/common';
|
||||
|
||||
import Avatar from '../../atoms/avatar/Avatar';
|
||||
|
@ -23,7 +28,21 @@ import SearchIC from '../../../../public/res/ic/outlined/search.svg';
|
|||
import InviteIC from '../../../../public/res/ic/outlined/invite.svg';
|
||||
|
||||
import { useSelectedTab } from '../../hooks/useSelectedTab';
|
||||
import { useSpaceShortcut } from '../../hooks/useSpaceShortcut';
|
||||
|
||||
function useNotificationUpdate() {
|
||||
const { notifications } = initMatrix;
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
function ProfileAvatarMenu() {
|
||||
const mx = initMatrix.matrixClient;
|
||||
|
@ -66,54 +85,10 @@ function ProfileAvatarMenu() {
|
|||
);
|
||||
}
|
||||
|
||||
function useTotalInvites() {
|
||||
const { roomList } = initMatrix;
|
||||
const totalInviteCount = () => roomList.inviteRooms.size
|
||||
+ roomList.inviteSpaces.size
|
||||
+ roomList.inviteDirects.size;
|
||||
const [totalInvites, updateTotalInvites] = useState(totalInviteCount());
|
||||
|
||||
useEffect(() => {
|
||||
const onInviteListChange = () => {
|
||||
updateTotalInvites(totalInviteCount());
|
||||
};
|
||||
roomList.on(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
||||
return () => {
|
||||
roomList.removeListener(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return [totalInvites];
|
||||
}
|
||||
|
||||
function SideBar() {
|
||||
function FeaturedTab() {
|
||||
const { roomList, accountData, 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);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const openSpaceOptions = (e, spaceId) => {
|
||||
e.preventDefault();
|
||||
openReusableContextMenu(
|
||||
'right',
|
||||
getEventCords(e, '.sidebar-avatar'),
|
||||
(closeMenu) => <SpaceOptions roomId={spaceId} afterOptionSelect={closeMenu} />,
|
||||
);
|
||||
};
|
||||
useNotificationUpdate();
|
||||
|
||||
function getHomeNoti() {
|
||||
const orphans = roomList.getOrphans();
|
||||
|
@ -145,17 +120,11 @@ function SideBar() {
|
|||
return noti;
|
||||
}
|
||||
|
||||
// TODO: bellow operations are heavy.
|
||||
// refactor this component into more smaller components.
|
||||
const dmsNoti = getDMsNoti();
|
||||
const homeNoti = getHomeNoti();
|
||||
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<div className="sidebar__scrollable">
|
||||
<ScrollView invisible>
|
||||
<div className="scrollable-content">
|
||||
<div className="featured-container">
|
||||
<>
|
||||
<SidebarAvatar
|
||||
tooltip="Home"
|
||||
active={selectedTab === cons.tabs.HOME}
|
||||
|
@ -180,38 +149,190 @@ function SideBar() {
|
|||
/>
|
||||
) : null}
|
||||
/>
|
||||
</div>
|
||||
<div className="sidebar-divider" />
|
||||
<div className="space-container">
|
||||
{
|
||||
spaceShortcut.map((shortcut) => {
|
||||
const sRoomId = shortcut;
|
||||
const room = mx.getRoom(sRoomId);
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function DraggableSpaceShortcut({
|
||||
isActive, spaceId, index, moveShortcut, onDrop,
|
||||
}) {
|
||||
const mx = initMatrix.matrixClient;
|
||||
const { notifications } = initMatrix;
|
||||
const room = mx.getRoom(spaceId);
|
||||
const shortcutRef = useRef(null);
|
||||
const avatarRef = useRef(null);
|
||||
|
||||
const openSpaceOptions = (e, sId) => {
|
||||
e.preventDefault();
|
||||
openReusableContextMenu(
|
||||
'right',
|
||||
getEventCords(e, '.sidebar-avatar'),
|
||||
(closeMenu) => <SpaceOptions roomId={sId} afterOptionSelect={closeMenu} />,
|
||||
);
|
||||
};
|
||||
|
||||
const [, drop] = useDrop({
|
||||
accept: 'SPACE_SHORTCUT',
|
||||
collect(monitor) {
|
||||
return {
|
||||
handlerId: monitor.getHandlerId(),
|
||||
};
|
||||
},
|
||||
drop(item) {
|
||||
onDrop(item.index, item.spaceId);
|
||||
},
|
||||
hover(item, monitor) {
|
||||
if (!shortcutRef.current) return;
|
||||
|
||||
const dragIndex = item.index;
|
||||
const hoverIndex = index;
|
||||
if (dragIndex === hoverIndex) return;
|
||||
|
||||
const hoverBoundingRect = shortcutRef.current?.getBoundingClientRect();
|
||||
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
|
||||
const clientOffset = monitor.getClientOffset();
|
||||
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
|
||||
|
||||
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
||||
return;
|
||||
}
|
||||
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
||||
return;
|
||||
}
|
||||
moveShortcut(dragIndex, hoverIndex);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.index = hoverIndex;
|
||||
},
|
||||
});
|
||||
const [{ isDragging }, drag] = useDrag({
|
||||
type: 'SPACE_SHORTCUT',
|
||||
item: () => ({ spaceId, index }),
|
||||
collect: (monitor) => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
});
|
||||
|
||||
drag(avatarRef);
|
||||
drop(shortcutRef);
|
||||
|
||||
if (shortcutRef.current) {
|
||||
if (isDragging) shortcutRef.current.style.opacity = 0;
|
||||
else shortcutRef.current.style.opacity = 1;
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarAvatar
|
||||
active={selectedTab === sRoomId}
|
||||
key={sRoomId}
|
||||
ref={shortcutRef}
|
||||
active={isActive}
|
||||
tooltip={room.name}
|
||||
onClick={() => selectTab(shortcut)}
|
||||
onContextMenu={(e) => openSpaceOptions(e, sRoomId)}
|
||||
onClick={() => selectTab(spaceId)}
|
||||
onContextMenu={(e) => openSpaceOptions(e, spaceId)}
|
||||
avatar={(
|
||||
<Avatar
|
||||
ref={avatarRef}
|
||||
text={room.name}
|
||||
bgColor={colorMXID(room.roomId)}
|
||||
size="normal"
|
||||
imageSrc={room.getAvatarUrl(initMatrix.matrixClient.baseUrl, 42, 42, 'crop') || null}
|
||||
/>
|
||||
)}
|
||||
notificationBadge={notifications.hasNoti(sRoomId) ? (
|
||||
notificationBadge={notifications.hasNoti(spaceId) ? (
|
||||
<NotificationBadge
|
||||
alert={notifications.getHighlightNoti(sRoomId) > 0}
|
||||
content={abbreviateNumber(notifications.getTotalNoti(sRoomId)) || null}
|
||||
alert={notifications.getHighlightNoti(spaceId) > 0}
|
||||
content={abbreviateNumber(notifications.getTotalNoti(spaceId)) || null}
|
||||
/>
|
||||
) : null}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
DraggableSpaceShortcut.propTypes = {
|
||||
spaceId: PropTypes.string.isRequired,
|
||||
isActive: PropTypes.bool.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
moveShortcut: PropTypes.func.isRequired,
|
||||
onDrop: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
function SpaceShortcut() {
|
||||
const { accountData } = initMatrix;
|
||||
const [selectedTab] = useSelectedTab();
|
||||
useNotificationUpdate();
|
||||
const [spaceShortcut, setSpaceShortcut] = useState([...accountData.spaceShortcut]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleShortcut = () => setSpaceShortcut([...accountData.spaceShortcut]);
|
||||
accountData.on(cons.events.accountData.SPACE_SHORTCUT_UPDATED, handleShortcut);
|
||||
return () => {
|
||||
accountData.removeListener(cons.events.accountData.SPACE_SHORTCUT_UPDATED, handleShortcut);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const moveShortcut = (dragIndex, hoverIndex) => {
|
||||
const dragSpaceId = spaceShortcut[dragIndex];
|
||||
const newShortcuts = [...spaceShortcut];
|
||||
newShortcuts.splice(dragIndex, 1);
|
||||
newShortcuts.splice(hoverIndex, 0, dragSpaceId);
|
||||
setSpaceShortcut(newShortcuts);
|
||||
};
|
||||
|
||||
const handleDrop = (dragIndex, dragSpaceId) => {
|
||||
if ([...accountData.spaceShortcut][dragIndex] === dragSpaceId) return;
|
||||
moveSpaceShortcut(dragSpaceId, dragIndex);
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
{
|
||||
spaceShortcut.map((shortcut, index) => (
|
||||
<DraggableSpaceShortcut
|
||||
key={shortcut}
|
||||
index={index}
|
||||
spaceId={shortcut}
|
||||
isActive={selectedTab === shortcut}
|
||||
moveShortcut={moveShortcut}
|
||||
onDrop={handleDrop}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</DndProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function useTotalInvites() {
|
||||
const { roomList } = initMatrix;
|
||||
const totalInviteCount = () => roomList.inviteRooms.size
|
||||
+ roomList.inviteSpaces.size
|
||||
+ roomList.inviteDirects.size;
|
||||
const [totalInvites, updateTotalInvites] = useState(totalInviteCount());
|
||||
|
||||
useEffect(() => {
|
||||
const onInviteListChange = () => {
|
||||
updateTotalInvites(totalInviteCount());
|
||||
};
|
||||
roomList.on(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
||||
return () => {
|
||||
roomList.removeListener(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return [totalInvites];
|
||||
}
|
||||
|
||||
function SideBar() {
|
||||
const [totalInvites] = useTotalInvites();
|
||||
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<div className="sidebar__scrollable">
|
||||
<ScrollView invisible>
|
||||
<div className="scrollable-content">
|
||||
<div className="featured-container">
|
||||
<FeaturedTab />
|
||||
</div>
|
||||
<div className="sidebar-divider" />
|
||||
<div className="space-container">
|
||||
<SpaceShortcut />
|
||||
<SidebarAvatar
|
||||
tooltip="Pin spaces"
|
||||
onClick={() => openShortcutSpaces()}
|
||||
|
|
Loading…
Reference in a new issue