Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions client/components/GenericModal.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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;
Expand All @@ -35,6 +35,22 @@ const getButtonProps = (variant: VariantType): ComponentProps<typeof Button> =>
}
};

const renderIcon = (icon: GenericModalProps['icon'], variant: VariantType): ReactNode => {
if (icon === null) {
return null;
}

if (icon === undefined) {
return <Icon color={variant} name={iconMap[variant]} size={24} />;
}

if (typeof icon === 'string') {
return <Icon color={variant} name={icon} size={24} />;
}

return icon;
};

const GenericModal: FC<GenericModalProps> = ({
variant = 'info',
children,
Expand All @@ -53,7 +69,7 @@ const GenericModal: FC<GenericModalProps> = ({
return (
<Modal {...props}>
<Modal.Header>
{icon !== null && <Icon color={variant} name={icon ?? iconMap[variant]} size={24} />}
{renderIcon(icon, variant)}
<Modal.Title>{title ?? t('Are_you_sure')}</Modal.Title>
<Modal.Close onClick={onClose} />
</Modal.Header>
Expand Down
32 changes: 11 additions & 21 deletions client/views/teams/contextualBar/info/Leave/LeaveTeamModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,49 @@ import React, { useState, useCallback } from 'react';

import { StepOne, StepTwo } from '.';

export const LeaveRoomModal = ({ onCancel, onConfirm, rooms }) => {
export const LeaveTeamModal = ({ onCancel, onConfirm, rooms }) => {
const [step, setStep] = useState(() => {
Comment thread
dougfabris marked this conversation as resolved.
if (rooms.length === 0) {
return 2;
}
return 1;
});
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(2), []);

const onReturn = useCallback(() => setStep((step) => step - 1), []);
const onReturn = useCallback(() => setStep(1), []);

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 };
});
}, []);

const onToggleAllRooms = useMutableCallback(() => {
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]),
);
}

return {};
});
});

const onSelectRooms = useMutableCallback(() => {
const keptRooms = Object.fromEntries(
rooms.filter((room) => !selectedRooms[room.rid]).map((room) => [room.rid, room]),
);
setKeptRooms(keptRooms);
onContinue();
});

if (step === 2) {
return (
<StepTwo
onConfirm={onConfirm}
onCancel={rooms.length > 1 && onReturn}
onCancel={rooms.length > 0 && onReturn}
onClose={onCancel}
lastOwnerRooms={Object.fromEntries(lastOwnerRooms.map((room) => [room._id, room]))}
keptRooms={keptRooms}
rooms={rooms}
/>
);
Expand All @@ -70,10 +60,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;
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,4 @@ export const Default = () => <LeaveTeamModal rooms={rooms} />;

export const ModalStepOne = () => <StepOne rooms={rooms} selectedRooms={{}} {...commonProps} />;

export const ModalStepTwo = () => (
<StepTwo keptRooms={rooms} lastOwnerRooms={{}} {...commonProps} />
);
export const ModalStepTwo = () => <StepTwo {...commonProps} />;
2 changes: 2 additions & 0 deletions client/views/teams/contextualBar/info/Leave/StepOne.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const StepOne = ({
onChangeRoomSelection,
onConfirm,
onCancel,
eligibleRoomsLength,
selectedRooms,
}) => {
const t = useTranslation();
Expand All @@ -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={() => {}}
Expand Down
29 changes: 4 additions & 25 deletions client/views/teams/contextualBar/info/Leave/StepTwo.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,24 @@
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 (
<GenericModal
icon={<Icon name='modal-warning' size={24} color='warning' />}
variant='danger'
icon='info-circled'
title={t('Confirmation')}
onConfirm={onConfirm}
onCancel={onCancel}
onClose={onClose}
confirmText={t('Leave')}
cancelText={t('Back')}
>
{showLastOwnerWarning && (
<>
<p>{t('Teams_channels_last_owner_leave_team_warning')}</p>
<br />
<p>
{t('Teams_channels_last_owner_cant_leave_list')} <RoomLinkList rooms={lastOwnerRooms} />
</p>
<br />
</>
)}
{showKeptChannels && (
<>
<p>
{t('Teams_channels_didnt_leave')} <RoomLinkList rooms={keptRooms} />
</p>
</>
)}
{showLeavingAllChannels && <p>{t('Teams_channels_leaving_all')}</p>}
{t('Teams_leaving_team')}
</GenericModal>
);
};
Expand Down
76 changes: 31 additions & 45 deletions client/views/teams/contextualBar/info/Leave/index.js
Original file line number Diff line number Diff line change
@@ -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 <LeaveTeamModal onCancel={onCancel} onConfirm={onConfirm} rooms={rooms} />;
const t = useTranslation();

const userId = useUserId();
const { value, phase } = useEndpointData(
'teams.listRoomsOfUser',
useMemo(() => ({ teamId, userId }), [teamId, userId]),
);

if (phase === AsyncStatePhase.LOADING) {
return (
<GenericModal
variant='warning'
onClose={onCancel}
onConfirm={onCancel}
title={<Skeleton width='50%' />}
confirmText={t('Cancel')}
>
<Skeleton width='full' />
</GenericModal>
);
}

return <LeaveTeamModal onCancel={onCancel} onConfirm={onConfirm} rooms={value.rooms} />;
};

export { StepOne, StepTwo };
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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) {
Expand All @@ -57,26 +52,25 @@ const BaseRemoveUsersModal = ({
onConfirm={onConfirm}
onClose={onClose}
onCancel={rooms?.length > 0 ? onReturn : onCancel}
deletedRooms={deletedRooms}
deletedRooms={selectedRooms}
rooms={rooms}
keptRooms={keptRooms}
username={username}
/>
);
}

return (
<RemoveUsersFirstStep
onConfirm={onSelectRooms}
onConfirm={onContinue}
onClose={onClose}
onCancel={onCancel}
rooms={rooms}
params={{}}
selectedRooms={deletedRooms}
selectedRooms={selectedRooms}
onToggleAllRooms={onToggleAllRooms}
// onChangeParams={(...args) => console.log(args)}
onChangeRoomSelection={onChangeRoomSelection}
eligibleRoomsLength={rooms?.length}
eligibleRoomsLength={eligibleRooms.length}
/>
);
};
Expand Down
Loading