Skip to content

Commit

Permalink
feat: add sections to room header and user infos menus with menuV2 (#…
Browse files Browse the repository at this point in the history
…29780)

Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com>
  • Loading branch information
guijun13 and gabriellsh committed Aug 18, 2023
1 parent 59e6fe3 commit a08006c
Show file tree
Hide file tree
Showing 34 changed files with 249 additions and 180 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilled-flies-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

feat: add sections to room header and user infos menus with menuV2
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const useAutotranslateRoomAction = () => {
tabComponent: AutoTranslate,
order: 20,
full: true,
type: 'customization',
};
}, [enabled, permitted]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const useCleanHistoryRoomAction = () => {
}),
tabComponent: PruneMessages,
order: 250,
type: 'customization',
};
}, [federated, permitted, t]);
};
1 change: 1 addition & 0 deletions apps/meteor/client/hooks/roomActions/useE2EERoomAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const useE2EERoomAction = () => {
icon: 'key',
order: 13,
action,
type: 'organization',
...(federated && {
tooltip: t('core.E2E_unavailable_for_federation'),
disabled: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const useExportMessagesRoomAction = () => {
tabComponent: ExportMessages,
full: true,
order: 12,
type: 'communication',
};
}, [permitted]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const useKeyboardShortcutListRoomAction = () => {
icon: 'keyboard',
tabComponent: KeyboardShortcuts,
order: 99,
type: 'customization',
}),
[],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const useMembersListRoomAction = () => {
title: team ? 'Teams_members' : 'Members',
icon: 'members',
tabComponent: MemberListRouter,
order: 5,
order: 7,
};
}, [broadcast, permittedToViewBroadcastMemberList, team]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const useMentionsRoomAction = () => {
title: 'Mentions',
icon: 'at',
tabComponent: MentionsTab,
order: 9,
order: 6,
type: 'organization',
}),
[],
);
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/client/hooks/roomActions/useOTRRoomAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const useOTRRoomAction = () => {
tabComponent: OTR,
order: 13,
full: true,
type: 'communication',
...(federated && {
tooltip: t('core.OTR_unavailable_for_federation'),
disabled: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export const usePinnedMessagesRoomAction = () => {
tooltip: t('core.Pinned_messages_unavailable_for_federation'),
disabled: true,
}),
order: 11,
order: 9,
type: 'organization',
};
}, [enabled, federated, t]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export const usePushNotificationsRoomAction = () => {
title: 'Notifications_Preferences',
icon: 'bell',
tabComponent: NotificationPreferences,
order: 8,
order: 11,
type: 'customization',
};
}, [capable]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const useRocketSearchRoomAction = () => {
title: 'Search_Messages',
icon: 'magnifier',
tabComponent: MessageSearchTab,
order: 6,
order: 5,
}),
[],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const useStarredMessagesRoomAction = () => {
icon: 'star',
tabComponent: StarredMessagesTab,
order: 10,
type: 'organization',
}),
[],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const useUploadedFilesListRoomAction = () => {
title: 'Files',
icon: 'clip',
tabComponent: RoomFiles,
order: 7,
order: 8,
type: 'organization',
};
}, []);
};
67 changes: 36 additions & 31 deletions apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import type { Box } from '@rocket.chat/fuselage';
import { Menu, Option } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { HeaderToolboxAction, HeaderToolboxDivider } from '@rocket.chat/ui-client';
import { useLayout, useTranslation } from '@rocket.chat/ui-contexts';
import type { ComponentProps } from 'react';
import React, { memo } from 'react';

import GenericMenu from '../../../../components/GenericMenu/GenericMenu';
import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem';
import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
import type { RoomToolboxActionConfig } from '../../contexts/RoomToolboxContext';

type RoomToolboxProps = {
className?: ComponentProps<typeof Box>['className'];
};

type MenuActionsProps = {
id: string;
items: GenericMenuItemProps[];
}[];

const RoomToolbox = ({ className }: RoomToolboxProps) => {
const t = useTranslation();
const { roomToolboxExpanded } = useLayout();
Expand All @@ -23,22 +29,33 @@ const RoomToolbox = ({ className }: RoomToolboxProps) => {
const featuredActions = actions.filter((action) => action.featured);
const normalActions = actions.filter((action) => !action.featured);
const visibleActions = !roomToolboxExpanded ? [] : normalActions.slice(0, 6);
const hiddenActions: Record<string, RoomToolboxActionConfig> = Object.fromEntries(
(!roomToolboxExpanded ? actions : normalActions.slice(6))
.filter((item) => !item.disabled)
.map((item) => {
return [
item.id,
{
label: { title: t(item.title), icon: item.icon },
action: (): void => {
openTab(item.id);
},
...item,
},
];
}),
);

const hiddenActions = (!roomToolboxExpanded ? actions : normalActions.slice(6))
.filter((item) => !item.disabled && !item.featured)
.map((item) => ({
'key': item.id,
'content': t(item.title),
'onClick':
item.action ??
((): void => {
openTab(item.id);
}),
'data-qa-id': `ToolBoxAction-${item.icon}`,
...item,
}))
.reduce((acc, item) => {
const group = item.type ? item.type : '';
const section = acc.find((section: { id: string }) => section.id === group);
if (section) {
section.items.push(item);
return acc;
}

const newSection = { id: group, key: item.key, title: group === 'apps' ? t('Apps') : '', items: [item] };
acc.push(newSection);

return acc;
}, [] as MenuActionsProps);

const renderDefaultToolboxItem: RoomToolboxActionConfig['renderToolboxItem'] = useMutableCallback(
({ id, className, index, icon, title, toolbox: { tab }, action, disabled, tooltip }) => {
Expand Down Expand Up @@ -74,20 +91,8 @@ const RoomToolbox = ({ className }: RoomToolboxProps) => {
{featuredActions.map(mapToToolboxItem)}
{featuredActions.length > 0 && <HeaderToolboxDivider />}
{visibleActions.map(mapToToolboxItem)}
{(normalActions.length > 6 || !roomToolboxExpanded) && (
<Menu
data-qa-id='ToolBox-Menu'
tiny={roomToolboxExpanded}
title={t('Options')}
maxHeight='initial'
className={className}
aria-keyshortcuts='alt'
tabIndex={-1}
options={hiddenActions}
renderItem={({ label: { title, icon }, ...props }) => (
<Option label={title} icon={icon} data-qa-id={`ToolBoxAction-${icon}`} gap={!icon} {...props} />
)}
/>
{(normalActions.length > 6 || roomToolboxExpanded) && (
<GenericMenu title={t('Options')} data-qa-id='ToolBox-Menu' sections={hiddenActions} placement='bottom-end' />
)}
</>
);
Expand Down
30 changes: 12 additions & 18 deletions apps/meteor/client/views/room/UserCard/UserCardWithData.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { PositionAnimated, AnimatedVisibility, Menu, Option } from '@rocket.chat/fuselage';
import { PositionAnimated, AnimatedVisibility } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useSetting, useRolesDescription } from '@rocket.chat/ui-contexts';
import { useSetting, useRolesDescription, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement, UIEvent } from 'react';
import React, { useMemo, useRef } from 'react';

import { getUserDisplayName } from '../../../../lib/getUserDisplayName';
import { Backdrop } from '../../../components/Backdrop';
import GenericMenu from '../../../components/GenericMenu/GenericMenu';
import LocalTime from '../../../components/LocalTime';
import UserCard from '../../../components/UserCard';
import { ReactiveUserStatus } from '../../../components/UserStatus';
import { useUserInfoQuery } from '../../../hooks/useUserInfoQuery';
import { useActionSpread } from '../../hooks/useActionSpread';
import { useUserInfoActions } from '../hooks/useUserInfoActions';

type UserCardWithDataProps = {
Expand All @@ -23,6 +23,7 @@ type UserCardWithDataProps = {
};

const UserCardWithData = ({ username, target, rid, open, onClose }: UserCardWithDataProps): ReactElement => {
const t = useTranslation();
const ref = useRef(target);
const getRoles = useRolesDescription();
const showRealNames = Boolean(useSetting('UI_Use_Real_Name'));
Expand Down Expand Up @@ -64,29 +65,22 @@ const UserCardWithData = ({ username, target, rid, open, onClose }: UserCardWith
onClose?.();
});

const userActions = useUserInfoActions({ _id: user._id ?? '', username: user.username }, rid);
const { actions: actionsDefinition, menu: menuOptions } = useActionSpread(userActions);
const { actions: actionsDefinition, menuActions: menuOptions } = useUserInfoActions(
{ _id: user._id ?? '', username: user.username },
rid,
);

const menu = useMemo(() => {
if (!menuOptions) {
return null;
}

return (
<Menu
flexShrink={0}
maxHeight='initial'
mi={2}
key='menu'
renderItem={({ label: { label, icon }, ...props }): ReactElement => <Option {...props} label={label} icon={icon} />}
options={menuOptions}
/>
);
}, [menuOptions]);
return <GenericMenu title={t('More')} key='menu' data-qa-id='menu' sections={menuOptions} placement='bottom-start' />;
}, [menuOptions, t]);

const actions = useMemo(() => {
const mapAction = ([key, { label, icon, action }]: any): ReactElement => (
<UserCard.Action key={key} label={label} aria-label={label} onClick={action} icon={icon} />
const mapAction = ([key, { content, icon, onClick }]: any): ReactElement => (
<UserCard.Action key={key} label={content} aria-label={content} onClick={onClick} icon={icon} />
);

return [...actionsDefinition.map(mapAction), menu].filter(Boolean);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type RoomToolboxActionConfig = {
tabComponent?: ComponentType<{
onClickBack?: () => void;
}>;
type?: 'organization' | 'communication' | 'customization' | 'apps';
};

export type RoomToolboxContextValue = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { IUser, IRoom } from '@rocket.chat/core-typings';
import { Option, Menu } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React from 'react';

import { useActionSpread } from '../../../hooks/useActionSpread';
import GenericMenu from '../../../../components/GenericMenu/GenericMenu';
import { useUserInfoActions } from '../../hooks/useUserInfoActions';

type RoomMembersActionsProps = {
Expand All @@ -14,21 +14,12 @@ type RoomMembersActionsProps = {
};

const RoomMembersActions = ({ username, _id, rid, reload }: RoomMembersActionsProps): ReactElement | null => {
const { menu: menuOptions } = useActionSpread(useUserInfoActions({ _id, username }, rid, reload), 0);
const t = useTranslation();
const { menuActions: menuOptions } = useUserInfoActions({ _id, username }, rid, reload, 0);
if (!menuOptions) {
return null;
}

return (
<Menu
flexShrink={0}
maxHeight='initial'
key='menu'
tiny
renderItem={({ label: { label, icon }, ...props }): ReactElement => <Option {...props} label={label} icon={icon} />}
options={menuOptions}
/>
);
return <GenericMenu title={t('More')} key='menu' data-qa-id='UserUserInfo-menu' sections={menuOptions} placement='bottom-end' />;
};

export default RoomMembersActions;
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* eslint-disable react/display-name, react/no-multi-comp */
import type { IRoom, IUser } from '@rocket.chat/core-typings';
import { ButtonGroup, Menu, Option } from '@rocket.chat/fuselage';
import { ButtonGroup, IconButton } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useMemo } from 'react';

import GenericMenu from '../../../../components/GenericMenu/GenericMenu';
import UserInfo from '../../../../components/UserInfo';
import { useActionSpread } from '../../../hooks/useActionSpread';
import { useUserInfoActions } from '../../hooks/useUserInfoActions';

type UserInfoActionsProps = {
Expand All @@ -14,8 +16,11 @@ type UserInfoActionsProps = {
};

const UserInfoActions = ({ user, rid, backToList }: UserInfoActionsProps): ReactElement => {
const { actions: actionsDefinition, menu: menuOptions } = useActionSpread(
useUserInfoActions({ _id: user._id, username: user.username }, rid, backToList),
const t = useTranslation();
const { actions: actionsDefinition, menuActions: menuOptions } = useUserInfoActions(
{ _id: user._id, username: user.username },
rid,
backToList,
);

const menu = useMemo(() => {
Expand All @@ -24,24 +29,23 @@ const UserInfoActions = ({ user, rid, backToList }: UserInfoActionsProps): React
}

return (
<Menu
<GenericMenu
button={<IconButton icon='kebab' secondary />}
title={t('More')}
key='menu'
mi={4}
secondary
data-qa-id='UserUserInfo-menu'
sections={menuOptions}
placement='bottom-end'
small={false}
maxHeight='initial'
renderItem={({ label: { label, icon }, ...props }): ReactElement => <Option {...props} label={label} icon={icon} />}
flexShrink={0}
options={menuOptions}
data-qa='UserUserInfo-menu'
/>
);
}, [menuOptions]);
}, [menuOptions, t]);

// TODO: sanitize Action type to avoid any
const actions = useMemo(() => {
const mapAction = ([key, { label, icon, action }]: any): ReactElement => (
<UserInfo.Action key={key} title={label} label={label} onClick={action} icon={icon} />
const mapAction = ([key, { content, icon, onClick }]: any): ReactElement => (
<UserInfo.Action key={key} title={content} label={content} onClick={onClick} icon={icon} />
);

return [...actionsDefinition.map(mapAction), menu].filter(Boolean);
Expand Down

0 comments on commit a08006c

Please sign in to comment.