Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: collapse sidebar groups #33592

Merged
merged 7 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
aleksandernsilva marked this conversation as resolved.
Show resolved Hide resolved
aleksandernsilva marked this conversation as resolved.
Show resolved Hide resolved
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
Loading