From 78fa840d312bb34582571c9d35e02c2a503fc808 Mon Sep 17 00:00:00 2001 From: dougfabris Date: Mon, 1 Mar 2021 18:11:50 -0300 Subject: [PATCH 001/238] add folder structure --- client/views/teams/index.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/views/teams/index.js diff --git a/client/views/teams/index.js b/client/views/teams/index.js new file mode 100644 index 000000000000..e69de29bb2d1 From 124e88407399bbff8e7ba110ddabba015bd8ddbe Mon Sep 17 00:00:00 2001 From: Gabriel Henriques Date: Tue, 2 Mar 2021 12:29:14 -0300 Subject: [PATCH 002/238] Rewrite Infopanels, create teaminfo --- client/views/InfoPanel/InfoPanel.stories.js | 67 +++++++ client/views/InfoPanel/InfoPanel.tsx | 53 ++++++ .../InfoPanel/RetentionPolicyCallout.tsx | 22 +++ client/views/InfoPanel/index.ts | 6 + .../contextualBar/Info/RoomInfo/RoomInfo.js | 108 +++++------- .../Info/RoomInfo/RoomInfo.stories.js | 8 +- .../UserInfo/UserInfo.stories.js | 11 +- .../room/contextualBar/UserInfo/index.js | 164 +++++++++--------- client/views/teams/info/TeamsInfo.stories.js | 54 ++++++ client/views/teams/info/index.js | 101 +++++++++++ packages/rocketchat-i18n/i18n/en.i18n.json | 2 + 11 files changed, 444 insertions(+), 152 deletions(-) create mode 100644 client/views/InfoPanel/InfoPanel.stories.js create mode 100644 client/views/InfoPanel/InfoPanel.tsx create mode 100644 client/views/InfoPanel/RetentionPolicyCallout.tsx create mode 100644 client/views/InfoPanel/index.ts create mode 100644 client/views/teams/info/TeamsInfo.stories.js create mode 100644 client/views/teams/info/index.js diff --git a/client/views/InfoPanel/InfoPanel.stories.js b/client/views/InfoPanel/InfoPanel.stories.js new file mode 100644 index 000000000000..da3477a6d772 --- /dev/null +++ b/client/views/InfoPanel/InfoPanel.stories.js @@ -0,0 +1,67 @@ +import React from 'react'; + +import InfoPanel, { RetentionPolicyCallout } from '.'; + +export default { + title: 'components/InfoPanel', + component: InfoPanel, +}; + +const room = { + fname: 'rocketchat-frontend-team', + description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', + announcement: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', + topic: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', +}; + +export const Default = () => + + + + + + + + Description + {room.description} + + + Announcement + {room.announcement} + + + Topic + {room.topic} + + + + + + +; + + +// export const Archived = () => +// +// ; + + +// export const Broadcast = () => +// +// ; diff --git a/client/views/InfoPanel/InfoPanel.tsx b/client/views/InfoPanel/InfoPanel.tsx new file mode 100644 index 000000000000..a093cb65bf8a --- /dev/null +++ b/client/views/InfoPanel/InfoPanel.tsx @@ -0,0 +1,53 @@ +import React, { FC, ReactNode } from 'react'; +import { Box, Icon, BoxProps } from '@rocket.chat/fuselage'; +import { css } from '@rocket.chat/css-in-js'; + +type TitleProps = { + title: string; + icon: string | ReactNode; +} + +const wordBreak = css` + word-break: break-word; +`; + +const InfoPanel: FC = ({ children }) => {children}; + +const Section: FC = (props) => ; + +const Title: FC = ({ title, icon }) => + { + typeof icon === 'string' + ? + : icon + } + {title} +; + +const Label: FC = (props) => ; + +const Text: FC = (props) => ; + +const Field: FC = ({ children }) => {children}; + +const Avatar: FC = ({ children }) =>
+ {children} +
; + +Object.assign(InfoPanel, { + Title, + Label, + Text, + Avatar, + Field, + Section, +}); + +export default InfoPanel; diff --git a/client/views/InfoPanel/RetentionPolicyCallout.tsx b/client/views/InfoPanel/RetentionPolicyCallout.tsx new file mode 100644 index 000000000000..b96ac2994cb2 --- /dev/null +++ b/client/views/InfoPanel/RetentionPolicyCallout.tsx @@ -0,0 +1,22 @@ +import React, { FC } from 'react'; +import { Callout } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../contexts/TranslationContext'; + +type RetentionPolicyCalloutProps = { + filesOnlyDefault: boolean; + excludePinnedDefault: boolean; + maxAgeDefault: number; +} + +const RetentionPolicyCallout: FC = ({ filesOnlyDefault, excludePinnedDefault, maxAgeDefault }) => { + const t = useTranslation(); + return + {filesOnlyDefault && excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_FilesOnly', { time: maxAgeDefault })}

} + {filesOnlyDefault && !excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_UnpinnedFilesOnly', { time: maxAgeDefault })}

} + {!filesOnlyDefault && excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning', { time: maxAgeDefault })}

} + {!filesOnlyDefault && !excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_Unpinned', { time: maxAgeDefault })}

} +
; +}; + +export default RetentionPolicyCallout; diff --git a/client/views/InfoPanel/index.ts b/client/views/InfoPanel/index.ts new file mode 100644 index 000000000000..9a0b6946e83a --- /dev/null +++ b/client/views/InfoPanel/index.ts @@ -0,0 +1,6 @@ +import InfoPanel from './InfoPanel'; +import RetentionPolicyCallout from './RetentionPolicyCallout'; + +export { RetentionPolicyCallout }; + +export default InfoPanel; diff --git a/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js b/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js index bf1581fb5b4c..b8b21a84d260 100644 --- a/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js +++ b/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js @@ -1,11 +1,8 @@ import React from 'react'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { Box, Icon, Button, ButtonGroup, Divider, Callout } from '@rocket.chat/fuselage'; -import { css } from '@rocket.chat/css-in-js'; -import RoomAvatar from '../../../../../components/avatar/RoomAvatar'; import { useTranslation } from '../../../../../contexts/TranslationContext'; -import UserCard from '../../../../../components/UserCard'; import VerticalBar from '../../../../../components/VerticalBar'; import { useUserRoom } from '../../../../../contexts/UserContext'; import { useMethod } from '../../../../../contexts/ServerContext'; @@ -20,6 +17,9 @@ import { usePermission } from '../../../../../contexts/AuthorizationContext'; import WarningModal from '../../../../admin/apps/WarningModal'; import MarkdownText from '../../../../../components/MarkdownText'; import { useTabBarClose } from '../../../providers/ToolboxProvider'; +import InfoPanel, { RetentionPolicyCallout } from '../../../../InfoPanel'; +import RoomAvatar from '../../../../../components/avatar/RoomAvatar'; + const retentionPolicyMaxAge = { c: 'RetentionPolicy_MaxAge_Channels', @@ -33,19 +33,9 @@ const retentionPolicyAppliesTo = { d: 'RetentionPolicy_AppliesToDMs', }; -const wordBreak = css` - word-break: break-word !important; -`; - -const Label = (props) => ; -const Info = ({ className, ...props }) => ; - -export const RoomInfoIcon = ({ name }) => ; - -export const Title = (props) => ; - export const RoomInfo = function RoomInfo({ - fname: name, + name, + fname, description, archived, broadcast, @@ -79,49 +69,50 @@ export const RoomInfo = function RoomInfo({ - - + + + - - - { archived && - - {t('Room_archived')} - - } - - - }>{name} - - - {broadcast && broadcast !== '' && - - } - - {description && description !== '' && - - {description} - } - - {announcement && announcement !== '' && - - {announcement} - } - - {topic && topic !== '' && - - {topic} - } - - {retentionPolicyEnabled && ( - - {filesOnlyDefault && excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_FilesOnly', { time: maxAgeDefault })}

} - {filesOnlyDefault && !excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_UnpinnedFilesOnly', { time: maxAgeDefault })}

} - {!filesOnlyDefault && excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning', { time: maxAgeDefault })}

} - {!filesOnlyDefault && !excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_Unpinned', { time: maxAgeDefault })}

} -
- )} -
+ + + + { archived && + + {t('Room_archived')} + + } + + + + + + + + {broadcast && broadcast !== '' && + {t('Broadcast_channel')} {t('Broadcast_channel_Description')} + } + + {description && description !== '' && + {t('Description')} + {description} + } + + {announcement && announcement !== '' && + {t('Announcement')} + {announcement} + } + + {topic && topic !== '' && + {t('Topic')} + {topic} + } + + {retentionPolicyEnabled && ( + + )} + + +
@@ -140,9 +131,6 @@ export const RoomInfo = function RoomInfo({ ); }; -RoomInfo.Title = Title; -RoomInfo.Icon = RoomInfoIcon; - export default ({ rid, openEditing, diff --git a/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.stories.js b/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.stories.js index 57e1c5c87fea..665c1446bab3 100644 --- a/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.stories.js +++ b/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.stories.js @@ -9,13 +9,13 @@ export default { }; const room = { - name: 'rocketchat-frontend-team', + fname: 'rocketchat-frontend-team', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', announcement: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', topic: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', }; -export const Default = () => +export const Default = () => ; -export const Archived = () => +export const Archived = () => ; -export const Broadcast = () => +export const Broadcast = () => , ], localTime: 'Local Time: 7:44 AM', utcOffset: -3, - email: { - address: 'rocketchat@rocket.chat', - verified: true, - }, + email: 'rocketchat@rocket.chat', + status: , }; const nickname = { @@ -29,5 +28,5 @@ const nickname = { nickname: 'Nickname', }; -export const Default = () => ; -export const Nickname = () => ; +export const Default = () => ; +export const Nickname = () => ; diff --git a/client/views/room/contextualBar/UserInfo/index.js b/client/views/room/contextualBar/UserInfo/index.js index 0f9645112e23..34400e5ff920 100644 --- a/client/views/room/contextualBar/UserInfo/index.js +++ b/client/views/room/contextualBar/UserInfo/index.js @@ -1,6 +1,5 @@ import React, { useMemo } from 'react'; import { Box, Margins, Tag, Button, Icon } from '@rocket.chat/fuselage'; -import { css } from '@rocket.chat/css-in-js'; import { useTranslation } from '../../../../contexts/TranslationContext'; import { useSetting } from '../../../../contexts/SettingsContext'; @@ -18,14 +17,8 @@ import { AsyncStatePhase } from '../../../../hooks/useAsyncState'; import { getUserEmailAddress } from '../../../../lib/getUserEmailAddress'; import { FormSkeleton } from '../../../../components/Skeleton'; import { getUserEmailVerified } from '../../../../lib/getUserEmailVerified'; +import InfoPanel from '../../../InfoPanel'; -const Label = (props) => ; - -const wordBreak = css` - word-break: break-word; -`; - -const Info = ({ className, ...props }) => ; const Avatar = ({ username, ...props }) => ; const Username = ({ username, status, ...props }) => ; @@ -46,7 +39,6 @@ export const UserInfo = React.memo(function UserInfo({ name, data, nickname, - // onChange, actions, ...props }) { @@ -55,76 +47,85 @@ export const UserInfo = React.memo(function UserInfo({ const timeAgo = useTimeAgo(); return - - - - - - {actions} - - - - {customStatus} - - {!!roles && <> - - {roles} - } - - {Number.isInteger(utcOffset) && <> - - - } - - {username && username !== name && <> - - {username} - } - - - {lastLogin ? timeAgo(lastLogin) : t('Never')} - - {name && <> - - {name} - } - - {nickname && <> - - {nickname} - } - - {bio && <> - - - } - - {phone && <> - - {phone} - - } - - {email && <> - - {email} - - {verified && {t('Verified')}} - {verified || {t('Not_verified')}} - - - } - - { customFields && Object.entries(customFields).map(([label, value]) => - - {value} - ) } - - - {timeAgo(createdAt)} - - - + + + + + + + {actions && !!actions.length && + {actions} + } + + + + + {customStatus} + + + + {!!roles && + {t('Roles')} + {roles} + } + + {Number.isInteger(utcOffset) && + {t('Local_Time')} + + } + + {username && username !== name && + {t('Username')} + {username} + } + + + {t('Last_login')} + {lastLogin ? timeAgo(lastLogin) : t('Never')} + + + {name && + {t('Full_Name')} + {name} + } + + {nickname && + {t('Nickname')} + {nickname} + } + + {bio && + {t('Bio')} + + } + + {phone && {t('Phone')} + + {phone} + + } + + {email && {t('Email')} + + {email} + + {verified && {t('Verified')}} + {verified || {t('Not_verified')}} + + + } + + { customFields && Object.entries(customFields).map(([label, value]) => + {t(label)} + {value} + ) } + + + {t('Created_at')} + {timeAgo(createdAt)} + + + ; }); @@ -137,8 +138,8 @@ export const Action = ({ icon, label, ...props }) => ( UserInfo.Action = Action; UserInfo.Avatar = Avatar; -UserInfo.Info = Info; -UserInfo.Label = Label; +UserInfo.Info = InfoPanel.Text; +UserInfo.Label = InfoPanel.Label; UserInfo.Username = Username; export const UserInfoWithData = React.memo(function UserInfoWithData({ uid, username, tabBar, rid, onClickClose, onClose = onClickClose, video, onClickBack, ...props }) { @@ -210,7 +211,6 @@ export const UserInfoWithData = React.memo(function UserInfoWithData({ uid, user || } {...props} p='x24' diff --git a/client/views/teams/info/TeamsInfo.stories.js b/client/views/teams/info/TeamsInfo.stories.js new file mode 100644 index 000000000000..5f8f0ab105e4 --- /dev/null +++ b/client/views/teams/info/TeamsInfo.stories.js @@ -0,0 +1,54 @@ +import React from 'react'; + +import VerticalBar from '../../../components/VerticalBar'; + +import TeamsInfo from '.'; + +export default { + title: 'components/TeamsInfo', + component: TeamsInfo, +}; + +const room = { + fname: 'rocketchat-frontend-team', + description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', + announcement: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', + topic: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis nisi vel arcu bibendum vehicula. Integer vitae suscipit libero', +}; + +export const Default = () => + +; + + +export const Archived = () => + +; + + +export const Broadcast = () => + +; diff --git a/client/views/teams/info/index.js b/client/views/teams/info/index.js new file mode 100644 index 000000000000..22268c82052b --- /dev/null +++ b/client/views/teams/info/index.js @@ -0,0 +1,101 @@ +import React from 'react'; +import { Box, Button, Callout } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../../contexts/TranslationContext'; +import VerticalBar from '../../../components/VerticalBar'; +import InfoPanel, { RetentionPolicyCallout } from '../../InfoPanel'; +import RoomAvatar from '../../../components/avatar/RoomAvatar'; + +const TeamsInfo = ({ + name, + fname, + description, + archived, + broadcast, + announcement, + topic, + type, + rid, + icon, + retentionPolicy = {}, + // onClickHide, + onClickClose, + // onClickLeave, + // onClickEdit, + // onClickDelete, +}) => { + const t = useTranslation(); + + const { + retentionPolicyEnabled, + filesOnlyDefault, + excludePinnedDefault, + maxAgeDefault, + } = retentionPolicy; + + return ( + <> + + + {t('Room_Info')} + { onClickClose && } + + + + + + + + + + + { archived && + + {t('Room_archived')} + + } + + + + + + + + {broadcast && broadcast !== '' && + {t('Broadcast_channel')} {t('Broadcast_channel_Description')} + } + + {description && description !== '' && + {t('Description')} + {description} + } + + {announcement && announcement !== '' && + {t('Announcement')} + {announcement} + } + + {topic && topic !== '' && + {t('Topic')} + {topic} + } + + + {t('Teams_channels')} + + + + + + {retentionPolicyEnabled && ( + + )} + + + + + + ); +}; + +export default TeamsInfo; diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index a588448c1d0d..2f955d13d6fc 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3705,6 +3705,8 @@ "TargetRoom": "Target Room", "TargetRoom_Description": "The room where messages will be sent which are a result of this event being fired. Only one target room is allowed and it must exist.", "Team": "Team", + "Teams_channels": "Team's Channels", + "View_channels": "View Channels", "Technology_Provider": "Technology Provider", "Technology_Services": "Technology Services", "Telecom": "Telecom", From e7bcd481a54e174d5fda6239d61d7c20da4dd9ef Mon Sep 17 00:00:00 2001 From: Gabriel Henriques Date: Tue, 2 Mar 2021 17:17:01 -0300 Subject: [PATCH 003/238] Convert buttons to actions --- client/views/InfoPanel/InfoPanel.tsx | 11 ++- client/views/admin/users/UserInfoActions.js | 4 +- client/views/hooks/useActionSpread.ts | 30 ++++++++ client/views/room/UserCard/index.js | 5 +- .../contextualBar/Info/RoomInfo/RoomInfo.js | 70 +++++++++++++++---- .../RoomMembers/List/components/MemberItem.js | 5 +- .../UserInfo/actions/UserActions.js | 5 +- client/views/room/hooks/useUserInfoActions.js | 20 ------ client/views/teams/info/index.js | 65 +++++++++++++++-- 9 files changed, 165 insertions(+), 50 deletions(-) create mode 100644 client/views/hooks/useActionSpread.ts diff --git a/client/views/InfoPanel/InfoPanel.tsx b/client/views/InfoPanel/InfoPanel.tsx index a093cb65bf8a..3e7ad529eb1b 100644 --- a/client/views/InfoPanel/InfoPanel.tsx +++ b/client/views/InfoPanel/InfoPanel.tsx @@ -1,5 +1,5 @@ import React, { FC, ReactNode } from 'react'; -import { Box, Icon, BoxProps } from '@rocket.chat/fuselage'; +import { Box, Icon, BoxProps, Button, ButtonProps, ButtonGroup, ButtonGroupProps } from '@rocket.chat/fuselage'; import { css } from '@rocket.chat/css-in-js'; type TitleProps = { @@ -35,6 +35,13 @@ const Text: FC = (props) => ; +const Action: FC = ({ label, icon, ...props }) => ; + +const ActionGroup: FC = (props) =>
; + const Field: FC = ({ children }) => {children}; const Avatar: FC = ({ children }) =>
@@ -47,7 +54,9 @@ Object.assign(InfoPanel, { Text, Avatar, Field, + Action, Section, + ActionGroup, }); export default InfoPanel; diff --git a/client/views/admin/users/UserInfoActions.js b/client/views/admin/users/UserInfoActions.js index dad869cda049..319b4ed14e29 100644 --- a/client/views/admin/users/UserInfoActions.js +++ b/client/views/admin/users/UserInfoActions.js @@ -1,7 +1,7 @@ import { ButtonGroup, Menu, Option } from '@rocket.chat/fuselage'; import React, { useCallback, useMemo } from 'react'; -import { useUserInfoActionsSpread } from '../../room/hooks/useUserInfoActions'; +import { useActionSpread } from '../../hooks/useActionSpread'; import ConfirmOwnerChangeWarningModal from '../../../components/ConfirmOwnerChangeWarningModal'; import { UserInfo } from '../../room/contextualBar/UserInfo'; import { usePermission } from '../../../contexts/AuthorizationContext'; @@ -234,7 +234,7 @@ export const UserInfoActions = ({ username, _id, isActive, isAdmin, onChange }) username, ]); - const { actions: actionsDefinition, menu: menuOptions } = useUserInfoActionsSpread(options); + const { actions: actionsDefinition, menu: menuOptions } = useActionSpread(options); const menu = useMemo(() => { if (!menuOptions) { diff --git a/client/views/hooks/useActionSpread.ts b/client/views/hooks/useActionSpread.ts new file mode 100644 index 000000000000..5e2244af198c --- /dev/null +++ b/client/views/hooks/useActionSpread.ts @@ -0,0 +1,30 @@ +import { useMemo } from 'react'; + +type Action = { + label: string; + icon: string; + action: () => any; +} + +type MenuOption = { + label: { label: string; icon: string}; + action: Function; +} + +const mapOptions = ([key, { action, label, icon }]: [string, Action]): [string, MenuOption] => [ + key, + { + label: { label, icon }, // TODO fuselage + action, + }, +]; + +export const useActionSpread = (actions: Action[], size = 2): { actions: [string, Action][]; menu: { [id: string]: MenuOption } | undefined } => useMemo(() => { + const entries = Object.entries(actions); + + const options = entries.slice(0, size); + const menuOptions = entries.slice(size, entries.length).map(mapOptions); + const menu = menuOptions.length ? Object.fromEntries(menuOptions) : undefined; + + return { actions: options, menu }; +}, [actions, size]); diff --git a/client/views/room/UserCard/index.js b/client/views/room/UserCard/index.js index ddd2d092084b..015a07f30bdd 100644 --- a/client/views/room/UserCard/index.js +++ b/client/views/room/UserCard/index.js @@ -8,7 +8,8 @@ import UserCard from '../../../components/UserCard'; import { Backdrop } from '../../../components/Backdrop'; import { ReactiveUserStatus } from '../../../components/UserStatus'; import { LocalTime } from '../../../components/UTCClock'; -import { useUserInfoActions, useUserInfoActionsSpread } from '../hooks/useUserInfoActions'; +import { useUserInfoActions } from '../hooks/useUserInfoActions'; +import { useActionSpread } from '../../hooks/useActionSpread'; import { useRolesDescription } from '../../../contexts/AuthorizationContext'; import { AsyncStatePhase } from '../../../hooks/useAsyncState'; import { useEndpointData } from '../../../hooks/useEndpointData'; @@ -69,7 +70,7 @@ const UserCardWithData = ({ username, onClose, target, open, rid }) => { onClose && onClose(); }); - const { actions: actionsDefinition, menu: menuOptions } = useUserInfoActionsSpread(useUserInfoActions(user, rid)); + const { actions: actionsDefinition, menu: menuOptions } = useActionSpread(useUserInfoActions(user, rid)); const menu = useMemo(() => { if (!menuOptions) { diff --git a/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js b/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js index b8b21a84d260..51bca0cf41ed 100644 --- a/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js +++ b/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { Box, Icon, Button, ButtonGroup, Divider, Callout } from '@rocket.chat/fuselage'; +import { Box, Callout, Menu, Option } from '@rocket.chat/fuselage'; import { useTranslation } from '../../../../../contexts/TranslationContext'; import VerticalBar from '../../../../../components/VerticalBar'; @@ -19,6 +19,7 @@ import MarkdownText from '../../../../../components/MarkdownText'; import { useTabBarClose } from '../../../providers/ToolboxProvider'; import InfoPanel, { RetentionPolicyCallout } from '../../../../InfoPanel'; import RoomAvatar from '../../../../../components/avatar/RoomAvatar'; +import { useActionSpread } from '../../../../hooks/useActionSpread'; const retentionPolicyMaxAge = { @@ -60,6 +61,54 @@ export const RoomInfo = function RoomInfo({ maxAgeDefault, } = retentionPolicy; + const memoizedActions = useMemo(() => ({ + ...onClickEdit && { edit: { + label: t('Edit'), + icon: 'edit', + action: onClickEdit, + } }, + ...onClickDelete && { delete: { + label: t('Delete'), + icon: 'trash', + action: onClickDelete, + } }, + ...onClickHide && { hide: { + label: t('Hide'), + action: onClickHide, + icon: 'eye-off', + } }, + ...onClickLeave && { leave: { + label: t('Leave'), + action: onClickLeave, + icon: 'sign-out', + } }, + }), [t, onClickHide, onClickLeave, onClickEdit, onClickDelete]); + + const { actions: actionsDefinition, menu: menuOptions } = useActionSpread(memoizedActions); + + const menu = useMemo(() => { + if (!menuOptions) { + return null; + } + + return