Skip to content

Commit

Permalink
refactor: Replace Menu in favor of GenericMenu in TeamsInfo (#34278)
Browse files Browse the repository at this point in the history
Co-authored-by: Tasso Evangelista <[email protected]>
  • Loading branch information
2 people authored and gabriellsh committed Dec 31, 2024
1 parent 4b41e36 commit 4233266
Show file tree
Hide file tree
Showing 14 changed files with 223 additions and 212 deletions.
4 changes: 2 additions & 2 deletions apps/meteor/client/hooks/roomActions/useTeamInfoRoomAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { lazy, useMemo } from 'react';

import type { RoomToolboxActionConfig } from '../../views/room/contexts/RoomToolboxContext';

const TeamsInfoWithRooms = lazy(() => import('../../views/teams/contextualBar/info/TeamsInfoWithRooms'));
const TeamsInfoWithData = lazy(() => import('../../views/teams/contextualBar/info/TeamsInfoWithData'));

export const useTeamInfoRoomAction = () => {
return useMemo(
Expand All @@ -13,7 +13,7 @@ export const useTeamInfoRoomAction = () => {
full: true,
title: 'Teams_Info',
icon: 'info-circled',
tabComponent: TeamsInfoWithRooms,
tabComponent: TeamsInfoWithData,
order: 1,
}),
[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import type { IRoom, Serialized } from '@rocket.chat/core-typings';
import React, { useMemo } from 'react';

import BaseConvertToChannelModal from './BaseConvertToChannelModal';
import GenericModalSkeleton from '../../../components/GenericModal/GenericModalSkeleton';
import { useEndpointData } from '../../../hooks/useEndpointData';
import { AsyncStatePhase } from '../../../lib/asyncState';
import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton';
import { useEndpointData } from '../../../../../hooks/useEndpointData';
import { AsyncStatePhase } from '../../../../../lib/asyncState';

type ConvertToChannelModalProps = {
onClose: () => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Box } from '@rocket.chat/fuselage';
import React from 'react';
import { useTranslation } from 'react-i18next';

import GenericModal from '../../../../components/GenericModal';
import ChannelDesertionTable from '../../ChannelDesertionTable';
import GenericModal from '../../../../../../components/GenericModal';
import ChannelDesertionTable from '../../../../ChannelDesertionTable';

type FirstStepProps = {
onClose: () => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Icon } from '@rocket.chat/fuselage';
import React from 'react';
import { useTranslation } from 'react-i18next';

import GenericModal from '../../../../components/GenericModal';
import GenericModal from '../../../../../../components/GenericModal';

type SecondStepsProps = {
onClose: () => void;
Expand Down
113 changes: 23 additions & 90 deletions apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { Box, Button, Callout, Option, Menu } from '@rocket.chat/fuselage';
import { Box, Button, Callout, IconButton } from '@rocket.chat/fuselage';
import { RoomAvatar } from '@rocket.chat/ui-avatar';
import { GenericMenu } from '@rocket.chat/ui-client';
import type { ReactElement } from 'react';
import React, { useMemo } from 'react';
import React from 'react';
import { useTranslation } from 'react-i18next';

import { useTeamActions } from './useTeamActions';
import {
ContextualbarHeader,
ContextualbarIcon,
Expand All @@ -25,105 +27,23 @@ import {
} 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';
import { useSplitRoomActions } from '../../../room/contextualBar/Info/hooks/useSplitRoomActions';
import { useRetentionPolicy } from '../../../room/hooks/useRetentionPolicy';

type TeamsInfoProps = {
room: IRoom;
onClickHide?: () => void;
onClickClose?: () => void;
onClickLeave?: () => void;
onClickEdit?: () => void;
onClickDelete?: () => void;
onClickClose?: () => void;
onClickViewChannels: () => void;
onClickConvertToChannel?: () => void;
};

const TeamsInfo = ({
room,
onClickHide,
onClickClose,
onClickLeave,
onClickEdit,
onClickDelete,
onClickViewChannels,
onClickConvertToChannel,
}: TeamsInfoProps): ReactElement => {
const TeamsInfo = ({ room, onClickClose, onClickEdit, onClickViewChannels }: TeamsInfoProps): ReactElement => {
const { t } = useTranslation();

const retentionPolicy = useRetentionPolicy(room);
const memoizedActions = useTeamActions(room, { onClickEdit });

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}
flexGrow={0}
key='menu'
maxHeight='initial'
title={t('More')}
secondary
renderItem={({ label: { label, icon }, ...props }): ReactElement => <Option {...props} label={label} icon={icon} />}
options={menuOptions}
/>
);
}, [t, menuOptions]);

const actions = useMemo(() => {
const mapAction = ([key, { label, icon, action }]: [string, Action]): ReactElement => (
<InfoPanelAction key={key} label={label as string} onClick={action} icon={icon} />
);

return [...actionsDefinition.map(mapAction), menu].filter(Boolean);
}, [actionsDefinition, menu]);
const { buttons: actions, menu } = useSplitRoomActions(memoizedActions);

return (
<>
Expand All @@ -139,7 +59,20 @@ const TeamsInfo = ({
<RoomAvatar size='x332' room={room} />
</InfoPanelAvatar>

<InfoPanelActionGroup>{actions}</InfoPanelActionGroup>
<InfoPanelActionGroup>
{actions.items.map(({ id, content, icon, onClick }) => (
<InfoPanelAction key={id} label={content} onClick={onClick} icon={icon} />
))}
{menu && (
<GenericMenu
title={t('More')}
placement='bottom-end'
detached
button={<IconButton icon='kebab' secondary flexShrink={0} flexGrow={0} maxHeight='initial' />}
sections={menu}
/>
)}
</InfoPanelActionGroup>
</InfoPanelSection>

<InfoPanelSection>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,102 +1,33 @@
import type { IRoom, Serialized } from '@rocket.chat/core-typings';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useSetModal, useToastMessageDispatch, useUserId, usePermission, useRouter } from '@rocket.chat/ui-contexts';
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
import { usePermission } from '@rocket.chat/ui-contexts';
import React, { useCallback, useState } from 'react';

import LeaveTeam from './LeaveTeam';
import TeamsInfo from './TeamsInfo';
import { useEndpointAction } from '../../../../hooks/useEndpointAction';
import { useHideRoomAction } from '../../../../hooks/useHideRoomAction';
import { useDeleteRoom } from '../../../hooks/roomActions/useDeleteRoom';
import { useRoom } from '../../../room/contexts/RoomContext';
import { useRoomToolbox } from '../../../room/contexts/RoomToolboxContext';
import ConvertToChannelModal from '../../ConvertToChannelModal';
import EditChannelWithData from '../../../room/contextualBar/Info/EditRoomInfo';

type TeamsInfoWithLogicProps = {
openEditing: () => void;
};

const TeamsInfoWithLogic = ({ openEditing }: TeamsInfoWithLogicProps) => {
const TeamsInfoWithData = () => {
const room = useRoom();
const [editing, setEditing] = useState(false);
const { openTab, closeTab } = useRoomToolbox();
const { t } = useTranslation();
const userId = useUserId();

const dispatchToastMessage = useToastMessageDispatch();
const setModal = useSetModal();
const closeModal = useMutableCallback(() => setModal());

const leaveTeam = useEndpointAction('POST', '/v1/teams.leave');
const convertTeamToChannel = useEndpointAction('POST', '/v1/teams.convertToChannel');

const hideTeam = useHideRoomAction({ rid: room._id, type: room.t, name: room.name ?? '' });

const router = useRouter();

const canEdit = usePermission('edit-team-channel', room._id);

// const canLeave = usePermission('leave-team'); /* && room.cl !== false && joined */

const { handleDelete, canDeleteRoom } = useDeleteRoom(room);

const onClickLeave = useMutableCallback(() => {
const onConfirm = async (selectedRooms: { [key: string]: Serialized<IRoom> & { isLastOwner?: boolean } } = {}) => {
const roomsLeft = Object.keys(selectedRooms);
const roomsToLeave = Array.isArray(roomsLeft) && roomsLeft.length > 0 ? roomsLeft : [];

try {
await leaveTeam({
teamId: room.teamId!,
...(roomsToLeave.length && { rooms: roomsToLeave }),
});
dispatchToastMessage({ type: 'success', message: t('Teams_left_team_successfully') });
router.navigate('/home');
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
} finally {
closeModal();
}
};

setModal(<LeaveTeam onConfirm={onConfirm} onCancel={closeModal} teamId={room.teamId!} />);
});

const onClickBack = useEffectEvent(() => setEditing(false));
const onClickViewChannels = useCallback(() => openTab('team-channels'), [openTab]);

const onClickConvertToChannel = useMutableCallback(() => {
const onConfirm = async (roomsToRemove: { [key: string]: Serialized<IRoom> }) => {
try {
await convertTeamToChannel({
teamId: room.teamId!,
roomsToRemove: Object.keys(roomsToRemove),
});

dispatchToastMessage({ type: 'success', message: t('Success') });
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
} finally {
closeModal();
}
};

setModal(
<ConvertToChannelModal onClose={closeModal} onCancel={closeModal} onConfirm={onConfirm} teamId={room.teamId!} userId={userId!} />,
);
});
if (editing) {
return <EditChannelWithData onClickBack={onClickBack} />;
}

return (
<TeamsInfo
room={room}
onClickEdit={canEdit ? openEditing : undefined}
onClickEdit={canEdit ? () => setEditing(true) : undefined}
onClickClose={closeTab}
onClickDelete={canDeleteRoom ? handleDelete : undefined}
onClickLeave={onClickLeave}
onClickHide={hideTeam}
onClickViewChannels={onClickViewChannels}
onClickConvertToChannel={canEdit ? onClickConvertToChannel : undefined}
/>
);
};

export default TeamsInfoWithLogic;
export default TeamsInfoWithData;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { IRoom, Serialized } from '@rocket.chat/core-typings';
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
import { usePermission, useSetModal, useToastMessageDispatch, useUserId } from '@rocket.chat/ui-contexts';
import React from 'react';
import { useTranslation } from 'react-i18next';

import ConvertToChannelModal from './ConvertToChannelModal';
import { useEndpointAction } from '../../../../hooks/useEndpointAction';

export const useConvertToChannel = ({ _id, teamId }: IRoom) => {
const { t } = useTranslation();
const setModal = useSetModal();
const userId = useUserId();
const canEdit = usePermission('edit-team-channel', _id);
const dispatchToastMessage = useToastMessageDispatch();

const convertTeamToChannel = useEndpointAction('POST', '/v1/teams.convertToChannel');

const onClickConvertToChannel = useEffectEvent(() => {
if (!userId || !teamId) {
throw new Error('Invalid teamId or userId');
}

const onConfirm = async (roomsToRemove: { [key: string]: Serialized<IRoom> }) => {
try {
await convertTeamToChannel({
teamId,
roomsToRemove: Object.keys(roomsToRemove),
});

dispatchToastMessage({ type: 'success', message: t('Success') });
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
} finally {
setModal(null);
}
};

setModal(
<ConvertToChannelModal
onClose={() => setModal(null)}
onCancel={() => setModal(null)}
onConfirm={onConfirm}
teamId={teamId}
userId={userId}
/>,
);
});

return canEdit ? onClickConvertToChannel : undefined;
};
Loading

0 comments on commit 4233266

Please sign in to comment.