apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx
import type { IRoom } from '@rocket.chat/core-typings';
import { Box, Button, Callout, Option, Menu } from '@rocket.chat/fuselage';
import { RoomAvatar } from '@rocket.chat/ui-avatar';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useMemo } from 'react';
import {
ContextualbarHeader,
ContextualbarIcon,
ContextualbarTitle,
ContextualbarClose,
ContextualbarScrollableContent,
} from '../../../../components/Contextualbar';
import InfoPanel from '../../../../components/InfoPanel';
import RetentionPolicyCallout from '../../../../components/InfoPanel/RetentionPolicyCallout';
import MarkdownText from '../../../../components/MarkdownText';
import type { Action } from '../../../hooks/useActionSpread';
import { useActionSpread } from '../../../hooks/useActionSpread';
type RetentionPolicy = {
retentionPolicyEnabled: boolean;
maxAgeDefault: number;
retentionEnabledDefault: boolean;
excludePinnedDefault: boolean;
filesOnlyDefault: boolean;
};
type TeamsInfoProps = {
room: IRoom;
retentionPolicy: RetentionPolicy;
onClickHide: () => void;
onClickClose: () => void;
onClickLeave: () => void;
onClickEdit: () => void;
onClickDelete: () => void;
onClickViewChannels: () => void;
onClickConvertToChannel?: () => void;
};
const TeamsInfo = ({
room,
retentionPolicy,
onClickHide,
onClickClose,
onClickLeave,
onClickEdit,
onClickDelete,
onClickViewChannels,
onClickConvertToChannel,
}: TeamsInfoProps): ReactElement => {
const t = useTranslation();
const { retentionPolicyEnabled, filesOnlyDefault, excludePinnedDefault, maxAgeDefault } = retentionPolicy;
const memoizedActions = useMemo(
() => ({
...(onClickEdit && {
edit: {
label: t('Edit'),
action: onClickEdit,
icon: 'edit' as const,
},
}),
...(onClickDelete && {
delete: {
label: t('Delete'),
action: onClickDelete,
icon: 'trash' as const,
},
}),
...(onClickConvertToChannel && {
convertToChannel: {
label: t('Convert_to_channel'),
action: onClickConvertToChannel,
icon: 'hash' as const,
},
}),
...(onClickHide && {
hide: {
label: t('Hide'),
action: onClickHide,
icon: 'eye-off' as const,
},
}),
...(onClickLeave && {
leave: {
label: t('Leave'),
action: onClickLeave,
icon: 'sign-out' as const,
},
}),
}),
[t, onClickHide, onClickLeave, onClickEdit, onClickDelete, onClickConvertToChannel],
);
const { actions: actionsDefinition, menu: menuOptions } = useActionSpread(memoizedActions);
const menu = useMemo(() => {
if (!menuOptions) {
return null;
}
return (
<Menu
small={false}
flexShrink={0}
mi={2}
key='menu'
maxHeight='initial'
secondary
renderItem={({ label: { label, icon }, ...props }): ReactElement => <Option {...props} label={label} icon={icon} />}
options={menuOptions}
/>
);
}, [menuOptions]);
const actions = useMemo(() => {
const mapAction = ([key, { label, icon, action }]: [string, Action]): ReactElement => (
<InfoPanel.Action key={key} label={label as string} onClick={action} icon={icon} />
);
return [...actionsDefinition.map(mapAction), menu].filter(Boolean);
}, [actionsDefinition, menu]);
return (
<>
<ContextualbarHeader>
<ContextualbarIcon name='info-circled' />
<ContextualbarTitle>{t('Teams_Info')}</ContextualbarTitle>
{onClickClose && <ContextualbarClose onClick={onClickClose} />}
</ContextualbarHeader>
<ContextualbarScrollableContent p={24}>
<InfoPanel>
<InfoPanel.Avatar>
<RoomAvatar size='x332' room={room} />
</InfoPanel.Avatar>
<InfoPanel.ActionGroup>{actions}</InfoPanel.ActionGroup>
<InfoPanel.Section>
{room.archived && (
<Box mb={16}>
<Callout type='warning'>{t('Room_archived')}</Callout>
</Box>
)}
</InfoPanel.Section>
<InfoPanel.Section>
<InfoPanel.Title title={room.fname || room.name || ''} icon='team' />
</InfoPanel.Section>
<InfoPanel.Section>
{room.broadcast && (
<InfoPanel.Field>
<InfoPanel.Label>
<b>{t('Broadcast_channel')}</b> {t('Broadcast_channel_Description')}
</InfoPanel.Label>
</InfoPanel.Field>
)}
{room.description && (
<InfoPanel.Field>
<InfoPanel.Label>{t('Description')}</InfoPanel.Label>
<InfoPanel.Text withTruncatedText={false}>
<MarkdownText variant='inline' content={room.description} />
</InfoPanel.Text>
</InfoPanel.Field>
)}
{room.announcement && (
<InfoPanel.Field>
<InfoPanel.Label>{t('Announcement')}</InfoPanel.Label>
<InfoPanel.Text withTruncatedText={false}>
<MarkdownText variant='inline' content={room.announcement} />
</InfoPanel.Text>
</InfoPanel.Field>
)}
{room.topic && (
<InfoPanel.Field>
<InfoPanel.Label>{t('Topic')}</InfoPanel.Label>
<InfoPanel.Text withTruncatedText={false}>
<MarkdownText variant='inline' content={room.topic} />
</InfoPanel.Text>
</InfoPanel.Field>
)}
{onClickViewChannels && (
<InfoPanel.Field>
<InfoPanel.Label>{t('Teams_channels')}</InfoPanel.Label>
<InfoPanel.Text>
<Button onClick={onClickViewChannels} small>
{t('View_channels')}
</Button>
</InfoPanel.Text>
</InfoPanel.Field>
)}
{retentionPolicyEnabled && (
<RetentionPolicyCallout
filesOnlyDefault={filesOnlyDefault}
excludePinnedDefault={excludePinnedDefault}
maxAgeDefault={maxAgeDefault}
/>
)}
</InfoPanel.Section>
</InfoPanel>
</ContextualbarScrollableContent>
</>
);
};
export default TeamsInfo;