diff --git a/client/components/GenericModal.tsx b/client/components/GenericModal.tsx index 9393ce4fbfdca..fc8a25a2c93ea 100644 --- a/client/components/GenericModal.tsx +++ b/client/components/GenericModal.tsx @@ -1,5 +1,5 @@ import { Box, Button, ButtonGroup, Icon, Modal } from '@rocket.chat/fuselage'; -import React, { FC, ComponentProps } from 'react'; +import React, { FC, ComponentProps, ReactElement, ReactNode } from 'react'; import { useTranslation } from '../contexts/TranslationContext'; import { withDoNotAskAgain, RequiredModalProps } from './withDoNotAskAgain'; @@ -10,8 +10,8 @@ type GenericModalProps = RequiredModalProps & { variant?: VariantType; cancelText?: string; confirmText?: string; - title?: string; - icon?: string; + title?: string | ReactElement; + icon?: string | ReactElement | null; onCancel?: () => void; onClose: () => void; onConfirm: () => void; @@ -35,6 +35,22 @@ const getButtonProps = (variant: VariantType): ComponentProps => } }; +const renderIcon = (icon: GenericModalProps['icon'], variant: VariantType): ReactNode => { + if (icon === null) { + return null; + } + + if (icon === undefined) { + return ; + } + + if (typeof icon === 'string') { + return ; + } + + return icon; +}; + const GenericModal: FC = ({ variant = 'info', children, @@ -53,7 +69,7 @@ const GenericModal: FC = ({ return ( - {icon !== null && } + {renderIcon(icon, variant)} {title ?? t('Are_you_sure')} diff --git a/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.js b/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.js index 162ced6ec152c..45b823a8048ed 100644 --- a/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.js +++ b/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.js @@ -3,28 +3,33 @@ import React, { useState, useCallback } from 'react'; import { StepOne, StepTwo } from '.'; -export const LeaveRoomModal = ({ onCancel, onConfirm, rooms }) => { +const STEPS = { + LIST_ROOMS: 'LIST_ROOMS', + CONFIRM_LEAVE: 'CONFIRM_LEAVE', +}; + +export const LeaveTeamModal = ({ onCancel, onConfirm, rooms }) => { const [step, setStep] = useState(() => { if (rooms.length === 0) { - return 2; + return STEPS.CONFIRM_LEAVE; } - return 1; + return STEPS.LIST_ROOMS; }); const [selectedRooms, setSelectedRooms] = useState({}); - const [keptRooms, setKeptRooms] = useState({}); const lastOwnerRooms = rooms.filter(({ isLastOwner }) => isLastOwner); - const onContinue = useCallback(() => setStep((step) => step + 1), []); + const onContinue = useCallback(() => setStep(STEPS.CONFIRM_LEAVE), []); - const onReturn = useCallback(() => setStep((step) => step - 1), []); + const onReturn = useCallback(() => setStep(STEPS.LIST_ROOMS), []); const onChangeRoomSelection = useCallback((room) => { setSelectedRooms((selectedRooms) => { - if (selectedRooms[room.rid]) { - return { ...selectedRooms, [room.rid]: undefined }; + if (selectedRooms[room._id]) { + delete selectedRooms[room._id]; + return { ...selectedRooms }; } - return { ...selectedRooms, [room.rid]: room }; + return { ...selectedRooms, [room._id]: room }; }); }, []); @@ -32,7 +37,7 @@ export const LeaveRoomModal = ({ onCancel, onConfirm, rooms }) => { setSelectedRooms((selectedRooms) => { if (Object.values(selectedRooms).filter(Boolean).length === 0) { return Object.fromEntries( - rooms.filter(({ isLastOwner }) => !isLastOwner).map((room) => [room.rid, room]), + rooms.filter(({ isLastOwner }) => !isLastOwner).map((room) => [room._id, room]), ); } @@ -40,22 +45,12 @@ export const LeaveRoomModal = ({ onCancel, onConfirm, rooms }) => { }); }); - const onSelectRooms = useMutableCallback(() => { - const keptRooms = Object.fromEntries( - rooms.filter((room) => !selectedRooms[room.rid]).map((room) => [room.rid, room]), - ); - setKeptRooms(keptRooms); - onContinue(); - }); - - if (step === 2) { + if (step === STEPS.CONFIRM_LEAVE) { return ( 1 && onReturn} + onCancel={rooms.length > 0 && onReturn} onClose={onCancel} - lastOwnerRooms={Object.fromEntries(lastOwnerRooms.map((room) => [room._id, room]))} - keptRooms={keptRooms} rooms={rooms} /> ); @@ -70,10 +65,10 @@ export const LeaveRoomModal = ({ onCancel, onConfirm, rooms }) => { selectedRooms={selectedRooms} onToggleAllRooms={onToggleAllRooms} onChangeParams={(...args) => console.log(args)} - onConfirm={onSelectRooms} + onConfirm={onContinue} onChangeRoomSelection={onChangeRoomSelection} /> ); }; -export default LeaveRoomModal; +export default LeaveTeamModal; diff --git a/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.stories.js b/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.stories.js index c452a90a2ace4..cd3d427eb5ae1 100644 --- a/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.stories.js +++ b/client/views/teams/contextualBar/info/Leave/LeaveTeamModal.stories.js @@ -25,6 +25,4 @@ export const Default = () => ; export const ModalStepOne = () => ; -export const ModalStepTwo = () => ( - -); +export const ModalStepTwo = () => ; diff --git a/client/views/teams/contextualBar/info/Leave/StepOne.js b/client/views/teams/contextualBar/info/Leave/StepOne.js index 004a26dfbc260..6849ba0744666 100644 --- a/client/views/teams/contextualBar/info/Leave/StepOne.js +++ b/client/views/teams/contextualBar/info/Leave/StepOne.js @@ -13,6 +13,7 @@ export const StepOne = ({ onChangeRoomSelection, onConfirm, onCancel, + eligibleRoomsLength, selectedRooms, }) => { const t = useTranslation(); @@ -31,6 +32,7 @@ export const StepOne = ({ lastOwnerWarning={t('Teams_channels_last_owner_leave_channel_warning')} onToggleAllRooms={onToggleAllRooms} lastOwnerRooms={lastOwnerRooms} + eligibleRoomsLength={eligibleRoomsLength} rooms={rooms} params={{}} onChangeParams={() => {}} diff --git a/client/views/teams/contextualBar/info/Leave/StepTwo.js b/client/views/teams/contextualBar/info/Leave/StepTwo.js index 52327da030b1f..fe556b5268ab5 100644 --- a/client/views/teams/contextualBar/info/Leave/StepTwo.js +++ b/client/views/teams/contextualBar/info/Leave/StepTwo.js @@ -1,20 +1,16 @@ +import { Icon } from '@rocket.chat/fuselage'; import React from 'react'; import GenericModal from '../../../../../components/GenericModal'; import { useTranslation } from '../../../../../contexts/TranslationContext'; -import RoomLinkList from '../../RoomLinkList'; -export const StepTwo = ({ lastOwnerRooms, keptRooms, onConfirm, onCancel, onClose }) => { +export const StepTwo = ({ onConfirm, onCancel, onClose }) => { const t = useTranslation(); - const showLastOwnerWarning = !!Object.values(lastOwnerRooms).length; - const showKeptChannels = !!Object.values(keptRooms).length; - const showLeavingAllChannels = !(showLastOwnerWarning || showKeptChannels); - return ( } variant='danger' - icon='info-circled' title={t('Confirmation')} onConfirm={onConfirm} onCancel={onCancel} @@ -22,24 +18,7 @@ export const StepTwo = ({ lastOwnerRooms, keptRooms, onConfirm, onCancel, onClos confirmText={t('Leave')} cancelText={t('Back')} > - {showLastOwnerWarning && ( - <> -

{t('Teams_channels_last_owner_leave_team_warning')}

-
-

- {t('Teams_channels_last_owner_cant_leave_list')} -

-
- - )} - {showKeptChannels && ( - <> -

- {t('Teams_channels_didnt_leave')} -

- - )} - {showLeavingAllChannels &&

{t('Teams_channels_leaving_all')}

} + {t('Teams_leaving_team')}
); }; diff --git a/client/views/teams/contextualBar/info/Leave/index.js b/client/views/teams/contextualBar/info/Leave/index.js index 90a82ddcfb131..72bce78df829e 100644 --- a/client/views/teams/contextualBar/info/Leave/index.js +++ b/client/views/teams/contextualBar/info/Leave/index.js @@ -1,53 +1,39 @@ -import React, { useContext, useState, useEffect } from 'react'; - -import { useEndpoint } from '../../../../../contexts/ServerContext'; -import { UserContext } from '../../../../../contexts/UserContext'; +import { Skeleton } from '@rocket.chat/fuselage'; +import React, { useMemo } from 'react'; + +import GenericModal from '../../../../../components/GenericModal'; +import { useTranslation } from '../../../../../contexts/TranslationContext'; +import { useUserId } from '../../../../../contexts/UserContext'; +import { useEndpointData } from '../../../../../hooks/useEndpointData'; +import { AsyncStatePhase } from '../../../../../lib/asyncState'; import LeaveTeamModal from './LeaveTeamModal'; import StepOne from './StepOne'; import StepTwo from './StepTwo'; -const useJoinedRoomsWithLastOwner = (teamId) => { - const [roomList, setRoomList] = useState([]); - const { querySubscriptions } = useContext(UserContext); - const listRooms = useEndpoint('GET', 'teams.listRooms'); - const getUsersInRole = useEndpoint('GET', 'roles.getUsersInRole'); - - useEffect(() => { - const getFinalRoomList = async () => { - const { rooms } = await listRooms({ teamId }); - - const rids = rooms.map(({ _id }) => _id); - const query = { - rid: { - $in: rids, - }, - }; - - const subs = querySubscriptions(query, {}).getCurrentValue(); - - const finalRooms = await Promise.all( - subs.map(async (subscription) => { - const { users, total } = await getUsersInRole({ - role: 'owner', - roomId: subscription.rid, - }); - const isLastOwner = total === 1 && users[0]._id === subscription.u._id; - return { ...subscription, isLastOwner }; - }), - ); - - setRoomList(finalRooms); - }; - getFinalRoomList(); - }, [getUsersInRole, listRooms, querySubscriptions, teamId]); - - return roomList; -}; - const LeaveTeamModalWithRooms = ({ teamId, onCancel, onConfirm }) => { - const rooms = useJoinedRoomsWithLastOwner(teamId); - - return ; + const t = useTranslation(); + + const userId = useUserId(); + const { value, phase } = useEndpointData( + 'teams.listRoomsOfUser', + useMemo(() => ({ teamId, userId }), [teamId, userId]), + ); + + if (phase === AsyncStatePhase.LOADING) { + return ( + } + confirmText={t('Cancel')} + > + + + ); + } + + return ; }; export { StepOne, StepTwo }; diff --git a/client/views/teams/contextualBar/members/RemoveUsersModal/BaseRemoveUsersModal.js b/client/views/teams/contextualBar/members/RemoveUsersModal/BaseRemoveUsersModal.js index 281a436dcdf09..96d8bc1b9cabf 100644 --- a/client/views/teams/contextualBar/members/RemoveUsersModal/BaseRemoveUsersModal.js +++ b/client/views/teams/contextualBar/members/RemoveUsersModal/BaseRemoveUsersModal.js @@ -1,5 +1,5 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { usePermission } from '../../../../../contexts/AuthorizationContext'; import RemoveUsersFirstStep from './RemoveUsersFirstStep'; @@ -20,35 +20,30 @@ const BaseRemoveUsersModal = ({ }) => { const [step, setStep] = useState(currentStep); - const [deletedRooms, setDeletedRooms] = useState({}); - const [keptRooms, setKeptRooms] = useState({}); + const [selectedRooms, setSelectedRooms] = useState({}); const onContinue = useMutableCallback(() => setStep(STEPS.CONFIRM_DELETE)); const onReturn = useMutableCallback(() => setStep(STEPS.LIST_ROOMS)); const canViewUserRooms = usePermission('view-all-team-channels'); - const onChangeRoomSelection = useMutableCallback((room) => { - if (deletedRooms[room._id]) { - setDeletedRooms((deletedRooms) => ({ ...deletedRooms, [room._id]: undefined })); - return; - } - setDeletedRooms((deletedRooms) => ({ ...deletedRooms, [room._id]: room })); - }); + const eligibleRooms = rooms.filter(({ isLastOwner }) => !isLastOwner); + + const onChangeRoomSelection = useCallback((room) => { + setSelectedRooms((selectedRooms) => { + if (selectedRooms[room._id]) { + delete selectedRooms[room._id]; + return { ...selectedRooms }; + } + return { ...selectedRooms, [room._id]: room }; + }); + }, []); const onToggleAllRooms = useMutableCallback(() => { - if (Object.values(deletedRooms).filter(Boolean).length === 0) { - return setDeletedRooms(Object.fromEntries(rooms.map((room) => [room._id, room]))); + if (Object.values(selectedRooms).filter(Boolean).length === 0) { + return setSelectedRooms(Object.fromEntries(eligibleRooms.map((room) => [room._id, room]))); } - setDeletedRooms({}); - }); - - const onSelectRooms = useMutableCallback(() => { - const keptRooms = Object.fromEntries( - rooms.filter((room) => !deletedRooms[room._id]).map((room) => [room._id, room]), - ); - setKeptRooms(keptRooms); - onContinue(); + setSelectedRooms({}); }); if (step === STEPS.CONFIRM_DELETE || !canViewUserRooms) { @@ -57,9 +52,8 @@ const BaseRemoveUsersModal = ({ onConfirm={onConfirm} onClose={onClose} onCancel={rooms?.length > 0 ? onReturn : onCancel} - deletedRooms={deletedRooms} + deletedRooms={selectedRooms} rooms={rooms} - keptRooms={keptRooms} username={username} /> ); @@ -67,16 +61,16 @@ const BaseRemoveUsersModal = ({ return ( console.log(args)} onChangeRoomSelection={onChangeRoomSelection} - eligibleRoomsLength={rooms?.length} + eligibleRoomsLength={eligibleRooms.length} /> ); }; diff --git a/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersSecondStep.js b/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersSecondStep.js index f26d6869631c8..2b92b7f672db6 100644 --- a/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersSecondStep.js +++ b/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersSecondStep.js @@ -1,16 +1,14 @@ -import { Margins } from '@rocket.chat/fuselage'; +import { Icon } from '@rocket.chat/fuselage'; import React from 'react'; import GenericModal from '../../../../../components/GenericModal'; import { useTranslation } from '../../../../../contexts/TranslationContext'; -import RoomLinkList from '../../RoomLinkList'; const RemoveUsersSecondStep = ({ onClose, onCancel, onConfirm, deletedRooms = {}, - keptRooms = {}, username, rooms = [], ...props @@ -20,26 +18,16 @@ const RemoveUsersSecondStep = ({ return ( } cancelText={rooms?.length > 0 ? t('Back') : t('Cancel')} confirmText={t('Remove')} - icon='info' title={t('Confirmation')} onClose={onClose} onCancel={onCancel} onConfirm={() => onConfirm(deletedRooms)} {...props} > - - {rooms.length === 0 &&
{t('Teams_removing__username__from_team', { username })}
} - {rooms.length > 0 && - (Object.values(keptRooms).length > 0 ? ( -
- {t('Teams_kept__username__channels', { username })} -
- ) : ( -
{t('Teams_removing__username__from_team_and_channels', { username })}
- ))} -
+ {t('Teams_removing__username__from_team', { username })}
); }; diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 80d854e0164c1..19f24b4c32e3f 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3864,10 +3864,8 @@ "Teams": "Teams", "Teams_about_the_channels": "And about the Channels?", "Teams_channels_didnt_leave": "You did not select the following Channels so you are not leaving them:", - "Teams_channels_last_owner_cant_leave_list": "You are the last owner of the following Channels so now, you are not able to leave them:", "Teams_channels_last_owner_leave_channel_warning": "You are the last owner of this Channel. Once you leave the Team, the Channel will be kept inside the Team but you will managing it from outside.", - "Teams_channels_last_owner_leave_team_warning": "You are the owner of some Channels. Once you leave the Team, the Channel will be kept inside the Team but you will manage it from outside.", - "Teams_channels_leaving_all": "You are leaving this Team and all its Channels.", + "Teams_leaving_team": "You are leaving this Team.", "Teams_channels": "Team's Channels", "Teams_convert_channel_to_team": "Convert to Team", "Teams_delete_team_choose_channels": "Select the Channels you would like to delete. The ones you decide to keep, will be available on your workspace.",