Skip to content

Commit

Permalink
feat: collapse sidebar groups (#33592)
Browse files Browse the repository at this point in the history
  • Loading branch information
juliajforesti authored Oct 18, 2024
1 parent bd64aed commit 9274cf4
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 106 deletions.
14 changes: 14 additions & 0 deletions .changeset/khaki-boxes-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@rocket.chat/fuselage-ui-kit': minor
'@rocket.chat/ui-theming': minor
'@rocket.chat/ui-video-conf': minor
'@rocket.chat/uikit-playground': minor
'@rocket.chat/ui-composer': minor
'@rocket.chat/gazzodown': minor
'@rocket.chat/ui-avatar': minor
'@rocket.chat/ui-client': minor
'@rocket.chat/ui-voip': minor
'@rocket.chat/meteor': minor
---

Adds ability to collapse/expand sidebar groups
46 changes: 17 additions & 29 deletions apps/meteor/client/sidebarv2/RoomList/RoomList.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/* eslint-disable react/no-multi-comp */
import type { ISubscription, IRoom } from '@rocket.chat/core-typings';
import { Box, SidebarV2GroupTitle } from '@rocket.chat/fuselage';
import { Box, SidebarV2CollapseGroup } from '@rocket.chat/fuselage';
import { useResizeObserver } from '@rocket.chat/fuselage-hooks';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useUserPreference, useUserId } from '@rocket.chat/ui-contexts';
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
Expand All @@ -11,6 +9,7 @@ import { GroupedVirtuoso } from 'react-virtuoso';
import { VirtuosoScrollbars } from '../../components/CustomScrollbars';
import { useOpenedRoom } from '../../lib/RoomManager';
import { useAvatarTemplate } from '../hooks/useAvatarTemplate';
import { useCollapsedGroups } from '../hooks/useCollapsedGroups';
import { usePreventDefault } from '../hooks/usePreventDefault';
import { useRoomList } from '../hooks/useRoomList';
import { useShortcutOpenMenu } from '../hooks/useShortcutOpenMenu';
Expand All @@ -19,30 +18,12 @@ import RoomListRow from './RoomListRow';
import RoomListRowWrapper from './RoomListRowWrapper';
import RoomListWrapper from './RoomListWrapper';

const getRoomsByGroup = (rooms: (ISubscription & IRoom)[]) => {
const groupCounts = rooms
.reduce((acc, item, index) => {
if (typeof item === 'string') {
acc.push(index);
}
return acc;
}, [] as number[])
.map((item, index, arr) => (arr[index + 1] ? arr[index + 1] : rooms.length) - item - 1);

const groupList = rooms.filter((item) => typeof item === 'string') as unknown as TranslationKey[];
const roomList = rooms.filter((item) => typeof item !== 'string');

return {
groupCounts,
groupList,
roomList,
};
};

const RoomList = () => {
const { t } = useTranslation();
const isAnonymous = !useUserId();
const roomsList = useRoomList();

const { collapsedGroups, handleCollapsedGroups } = useCollapsedGroups();
const { groupsCount, groupsList, roomList } = useRoomList({ collapsedGroups });
const avatarTemplate = useAvatarTemplate();
const sideBarItemTemplate = useTemplateByViewMode();
const { ref } = useResizeObserver<HTMLElement>({ debounceDelay: 100 });
Expand All @@ -66,14 +47,21 @@ const RoomList = () => {
usePreventDefault(ref);
useShortcutOpenMenu(ref);

const { groupCounts, groupList, roomList } = getRoomsByGroup(roomsList);

return (
<Box position='relative' display='flex' overflow='hidden' height='full' flexGrow={1} flexShrink={1} flexBasis='auto' ref={ref}>
<GroupedVirtuoso
groupCounts={groupCounts}
groupContent={(index) => <SidebarV2GroupTitle title={t(groupList[index])} />}
itemContent={(index) => <RoomListRow data={itemData} item={roomList[index]} />}
groupCounts={groupsCount}
groupContent={(index) => (
<SidebarV2CollapseGroup
title={t(groupsList[index])}
onClick={() => handleCollapsedGroups(groupsList[index])}
onKeyDown={() => handleCollapsedGroups(groupsList[index])}
expanded={!collapsedGroups.includes(groupsList[index])}
/>
)}
{...(roomList.length > 0 && {
itemContent: (index) => roomList[index] && <RoomListRow data={itemData} item={roomList[index]} />,
})}
components={{ Item: RoomListRowWrapper, List: RoomListWrapper, Scroller: VirtuosoScrollbars }}
/>
</Box>
Expand Down
19 changes: 19 additions & 0 deletions apps/meteor/client/sidebarv2/hooks/useCollapsedGroups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useLocalStorage } from '@rocket.chat/fuselage-hooks';
import { useCallback } from 'react';

export const useCollapsedGroups = () => {
const [collapsedGroups, setCollapsedGroups] = useLocalStorage<string[]>('sidebarGroups', []);

const handleCollapsedGroups = useCallback(
(group: string) => {
if (collapsedGroups.includes(group)) {
setCollapsedGroups(collapsedGroups.filter((item) => item !== group));
} else {
setCollapsedGroups([...collapsedGroups, group]);
}
},
[collapsedGroups, setCollapsedGroups],
);

return { collapsedGroups, handleCollapsedGroups };
};
134 changes: 81 additions & 53 deletions apps/meteor/client/sidebarv2/hooks/useRoomList.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { ILivechatInquiryRecord, IRoom, ISubscription } from '@rocket.chat/core-typings';
import { useDebouncedState } from '@rocket.chat/fuselage-hooks';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useUserPreference, useUserSubscriptions, useSetting } from '@rocket.chat/ui-contexts';
import { useEffect } from 'react';
import { useMemo } from 'react';

import { useVideoConfIncomingCalls } from '../../contexts/VideoConfContext';
import { useOmnichannelEnabled } from '../../hooks/omnichannel/useOmnichannelEnabled';
Expand All @@ -12,19 +13,7 @@ const query = { open: { $ne: false } };

const emptyQueue: ILivechatInquiryRecord[] = [];

const order: (
| 'Incoming_Calls'
| 'Incoming_Livechats'
| 'Open_Livechats'
| 'On_Hold_Chats'
| 'Unread'
| 'Favorites'
| 'Teams'
| 'Discussions'
| 'Channels'
| 'Direct_Messages'
| 'Conversations'
)[] = [
const order = [
'Incoming_Calls',
'Incoming_Livechats',
'Open_Livechats',
Expand All @@ -36,11 +25,17 @@ const order: (
'Channels',
'Direct_Messages',
'Conversations',
];

export const useRoomList = (): Array<ISubscription & IRoom> => {
const [roomList, setRoomList] = useDebouncedState<(ISubscription & IRoom)[]>([], 150);

] as const;

export const useRoomList = ({
collapsedGroups,
}: {
collapsedGroups?: string[];
}): {
roomList: Array<ISubscription & IRoom>;
groupsCount: number[];
groupsList: TranslationKey[];
} => {
const showOmnichannel = useOmnichannelEnabled();
const sidebarGroupByType = useUserPreference('sidebarGroupByType');
const favoritesEnabled = useUserPreference('sidebarShowFavorites');
Expand All @@ -56,13 +51,12 @@ export const useRoomList = (): Array<ISubscription & IRoom> => {

const incomingCalls = useVideoConfIncomingCalls();

let queue = emptyQueue;
if (inquiries.enabled) {
queue = inquiries.queue;
}
const queue = inquiries.enabled ? inquiries.queue : emptyQueue;

const { groupsCount, groupsList, roomList } = useDebouncedValue(
useMemo(() => {
const isCollapsed = (groupTitle: string) => collapsedGroups?.includes(groupTitle);

useEffect(() => {
setRoomList(() => {
const incomingCall = new Set();
const favorite = new Set();
const team = new Set();
Expand All @@ -83,7 +77,7 @@ export const useRoomList = (): Array<ISubscription & IRoom> => {
return incomingCall.add(room);
}

if (sidebarShowUnread && (room.alert || room.unread) && !room.hideUnreadStatus) {
if (sidebarShowUnread && (room.alert || room.unread)) {
return unread.add(room);
}

Expand Down Expand Up @@ -118,42 +112,76 @@ export const useRoomList = (): Array<ISubscription & IRoom> => {
conversation.add(room);
});

const groups = new Map();
const groups = new Map<string, Set<any>>();
incomingCall.size && groups.set('Incoming_Calls', incomingCall);
showOmnichannel && inquiries.enabled && queue.length && groups.set('Incoming_Livechats', queue);

showOmnichannel && inquiries.enabled && queue.length && groups.set('Incoming_Livechats', new Set(queue));
showOmnichannel && omnichannel.size && groups.set('Open_Livechats', omnichannel);
showOmnichannel && onHold.size && groups.set('On_Hold_Chats', onHold);

sidebarShowUnread && unread.size && groups.set('Unread', unread);

favoritesEnabled && favorite.size && groups.set('Favorites', favorite);

sidebarGroupByType && team.size && groups.set('Teams', team);

sidebarGroupByType && isDiscussionEnabled && discussion.size && groups.set('Discussions', discussion);

sidebarGroupByType && channels.size && groups.set('Channels', channels);

sidebarGroupByType && direct.size && groups.set('Direct_Messages', direct);

!sidebarGroupByType && groups.set('Conversations', conversation);
return sidebarOrder
.map((key) => {
const group = groups.get(key);
if (!group) {
return [];

const { groupsCount, groupsList, roomList } = sidebarOrder.reduce(
(acc, key) => {
const value = groups.get(key);

if (!value) {
return acc;
}

acc.groupsList.push(key as TranslationKey);
if (isCollapsed(key)) {
acc.groupsCount.push(0);
return acc;
}

return [key, ...group];
})
.flat();
});
}, [
rooms,
showOmnichannel,
incomingCalls,
inquiries.enabled,
queue,
sidebarShowUnread,
favoritesEnabled,
sidebarGroupByType,
setRoomList,
isDiscussionEnabled,
sidebarOrder,
]);

return roomList;
acc.groupsCount.push(value.size);
acc.roomList.push(...value);
return acc;
},
{
groupsCount: [],
groupsList: [],
roomList: [],
} as {
groupsCount: number[];
groupsList: TranslationKey[];
roomList: Array<ISubscription & IRoom>;
},
);

return { groupsCount, groupsList, roomList };
}, [
rooms,
showOmnichannel,
inquiries.enabled,
queue,
sidebarShowUnread,
favoritesEnabled,
sidebarGroupByType,
isDiscussionEnabled,
sidebarOrder,
collapsedGroups,
incomingCalls,
]),
50,
);

return {
roomList,
groupsCount,
groupsList,
};
};
2 changes: 1 addition & 1 deletion apps/meteor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@
"@rocket.chat/forked-matrix-appservice-bridge": "^4.0.2",
"@rocket.chat/forked-matrix-bot-sdk": "^0.6.0-beta.3",
"@rocket.chat/freeswitch": "workspace:^",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-hooks": "^0.33.1",
"@rocket.chat/fuselage-polyfills": "~0.31.25",
"@rocket.chat/fuselage-toastbar": "^0.33.0",
Expand Down
2 changes: 1 addition & 1 deletion apps/uikit-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@lezer/highlight": "^1.1.6",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-hooks": "^0.33.1",
"@rocket.chat/fuselage-polyfills": "~0.31.25",
"@rocket.chat/fuselage-toastbar": "^0.33.0",
Expand Down
2 changes: 1 addition & 1 deletion ee/packages/ui-theming/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"devDependencies": {
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-hooks": "^0.33.1",
"@rocket.chat/icons": "~0.38.0",
"@rocket.chat/ui-contexts": "workspace:~",
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage-ui-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"@rocket.chat/apps-engine": "workspace:^",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/eslint-config": "workspace:^",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-hooks": "^0.33.1",
"@rocket.chat/fuselage-polyfills": "~0.31.25",
"@rocket.chat/icons": "~0.38.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/gazzodown/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@babel/core": "~7.25.8",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-tokens": "^0.33.1",
"@rocket.chat/jest-presets": "workspace:~",
"@rocket.chat/message-parser": "workspace:^",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-avatar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"devDependencies": {
"@babel/core": "~7.25.8",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/ui-contexts": "workspace:^",
"@types/react": "~17.0.80",
"@types/react-dom": "~17.0.25",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@babel/core": "~7.25.8",
"@react-aria/toolbar": "^3.0.0-beta.1",
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-hooks": "^0.33.1",
"@rocket.chat/icons": "~0.38.0",
"@rocket.chat/jest-presets": "workspace:~",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-composer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@babel/core": "~7.25.8",
"@react-aria/toolbar": "^3.0.0-beta.1",
"@rocket.chat/eslint-config": "workspace:^",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/icons": "~0.38.0",
"@storybook/addon-actions": "^8.3.5",
"@storybook/addon-docs": "^8.3.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-video-conf/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@babel/core": "~7.25.8",
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/eslint-config": "workspace:^",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-hooks": "^0.33.1",
"@rocket.chat/icons": "~0.38.0",
"@rocket.chat/jest-presets": "workspace:~",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-voip/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@faker-js/faker": "~8.0.2",
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/eslint-config": "workspace:^",
"@rocket.chat/fuselage": "^0.59.1",
"@rocket.chat/fuselage": "^0.59.3",
"@rocket.chat/fuselage-hooks": "^0.33.1",
"@rocket.chat/icons": "~0.38.0",
"@rocket.chat/jest-presets": "workspace:~",
Expand Down
Loading

0 comments on commit 9274cf4

Please sign in to comment.