Skip to content

Commit

Permalink
refactor: EditRoomInfo to typescript (#28318)
Browse files Browse the repository at this point in the history
  • Loading branch information
dougfabris authored and debdutdeb committed Oct 26, 2023
1 parent 4d25f11 commit 9f9d38a
Show file tree
Hide file tree
Showing 13 changed files with 765 additions and 682 deletions.
2 changes: 1 addition & 1 deletion apps/meteor/client/components/avatar/RoomAvatarEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const RoomAvatarEditor = ({ disabled = false, room, roomAvatar, onChangeAvatar }
danger
icon='trash'
title={t('Accounts_SetDefaultAvatar')}
disabled={roomAvatar === null || isRoomFederated(room) || disabled}
disabled={!roomAvatar || isRoomFederated(room) || disabled}
onClick={clickReset}
/>
</ButtonGroup>
Expand Down
97 changes: 17 additions & 80 deletions apps/meteor/client/views/admin/rooms/EditRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,17 @@ import {
TextAreaInput,
} from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useSetModal, useToastMessageDispatch, useRoute, usePermission, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useState, useMemo } from 'react';
import React, { useMemo } from 'react';

import { RoomSettingsEnum } from '../../../../definition/IRoomTypeConfig';
import { ContextualbarScrollableContent, ContextualbarFooter } from '../../../components/Contextualbar';
import GenericModal from '../../../components/GenericModal';
import RoomAvatarEditor from '../../../components/avatar/RoomAvatarEditor';
import { useEndpointAction } from '../../../hooks/useEndpointAction';
import { useForm } from '../../../hooks/useForm';
import { roomCoordinator } from '../../../lib/rooms/roomCoordinator';
import DeleteTeamModalWithRooms from '../../teams/contextualBar/info/DeleteTeam';
import { useDeleteRoom } from '../../hooks/roomActions/useDeleteRoom';

type EditRoomProps = {
room: Pick<IRoom, RoomAdminFieldsType>;
Expand Down Expand Up @@ -65,11 +64,6 @@ const getInitialValues = (room: Pick<IRoom, RoomAdminFieldsType>): EditRoomFormV
const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement => {
const t = useTranslation();

const [deleting, setDeleting] = useState(false);

const setModal = useSetModal();
const dispatchToastMessage = useToastMessageDispatch();

const { values, handlers, hasUnsavedChanges, reset } = useForm(getInitialValues(room));

const [canViewName, canViewTopic, canViewAnnouncement, canViewArchived, canViewDescription, canViewType, canViewReadOnly] =
Expand Down Expand Up @@ -119,9 +113,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>

const changeArchivation = archived !== !!room.archived;

const roomsRoute = useRoute('admin-rooms');

const canDelete = usePermission(`delete-${room.t}`);
const { handleDelete, canDeleteRoom, isDeleting } = useDeleteRoom(room, { reload: onDelete });

const archiveSelector = room.archived ? 'unarchive' : 'archive';
const archiveMessage = room.archived ? 'Room_has_been_unarchived' : 'Room_has_been_archived';
Expand Down Expand Up @@ -161,61 +153,6 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
handleRoomType(roomType === 'p' ? 'c' : 'p');
});

const deleteRoom = useEndpoint('POST', '/v1/rooms.delete');
const deleteTeam = useEndpoint('POST', '/v1/teams.delete');

const handleDelete = useMutableCallback(() => {
const handleDeleteTeam = async (roomsToRemove: IRoom['_id'][]) => {
try {
setDeleting(true);
setModal(null);
await deleteTeam({ teamId: room.teamId as string, ...(roomsToRemove.length && { roomsToRemove }) });
dispatchToastMessage({ type: 'success', message: t('Team_has_been_deleted') });
roomsRoute.push({});
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
setDeleting(false);
} finally {
onDelete();
}
};

if (room.teamMain) {
setModal(
<DeleteTeamModalWithRooms onConfirm={handleDeleteTeam} onCancel={(): void => setModal(null)} teamId={room.teamId as string} />,
);

return;
}

const handleDeleteRoom = async (): Promise<void> => {
try {
setDeleting(true);
setModal(null);
await deleteRoom({ roomId: room._id });
dispatchToastMessage({ type: 'success', message: t('Room_has_been_deleted') });
roomsRoute.push({});
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
setDeleting(false);
} finally {
onDelete();
}
};

setModal(
<GenericModal
variant='danger'
onConfirm={handleDeleteRoom}
onClose={(): void => setModal(null)}
onCancel={(): void => setModal(null)}
confirmText={t('Yes_delete_it')}
>
{t('Delete_Room_Warning')}
</GenericModal>,
);
});

return (
<>
<ContextualbarScrollableContent is='form' onSubmit={useMutableCallback((e) => e.preventDefault())}>
Expand All @@ -227,7 +164,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<Field>
<FieldLabel required>{t('Name')}</FieldLabel>
<FieldRow>
<TextInput disabled={deleting || !canViewName} value={roomName} onChange={handleRoomName} flexGrow={1} />
<TextInput disabled={isDeleting || !canViewName} value={roomName} onChange={handleRoomName} flexGrow={1} />
</FieldRow>
</Field>
{room.t !== 'd' && (
Expand All @@ -246,7 +183,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<FieldRow>
<TextAreaInput
rows={4}
disabled={deleting || isRoomFederated(room)}
disabled={isDeleting || isRoomFederated(room)}
value={roomDescription}
onChange={handleRoomDescription}
flexGrow={1}
Expand All @@ -260,7 +197,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<FieldRow>
<TextAreaInput
rows={4}
disabled={deleting || isRoomFederated(room)}
disabled={isDeleting || isRoomFederated(room)}
value={roomAnnouncement}
onChange={handleRoomAnnouncement}
flexGrow={1}
Expand All @@ -272,7 +209,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<Field>
<FieldLabel>{t('Topic')}</FieldLabel>
<FieldRow>
<TextAreaInput rows={4} disabled={deleting} value={roomTopic} onChange={handleRoomTopic} flexGrow={1} />
<TextAreaInput rows={4} disabled={isDeleting} value={roomTopic} onChange={handleRoomTopic} flexGrow={1} />
</FieldRow>
</Field>
)}
Expand All @@ -281,7 +218,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<Box display='flex' flexDirection='row' justifyContent='space-between' flexGrow={1}>
<FieldLabel>{t('Private')}</FieldLabel>
<FieldRow>
<ToggleSwitch disabled={deleting || isRoomFederated(room)} checked={roomType === 'p'} onChange={changeRoomType} />
<ToggleSwitch disabled={isDeleting || isRoomFederated(room)} checked={roomType === 'p'} onChange={changeRoomType} />
</FieldRow>
</Box>
<FieldHint>{t('Just_invited_people_can_access_this_channel')}</FieldHint>
Expand All @@ -292,7 +229,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<Box display='flex' flexDirection='row' justifyContent='space-between' flexGrow={1}>
<FieldLabel>{t('Read_only')}</FieldLabel>
<FieldRow>
<ToggleSwitch disabled={deleting || isRoomFederated(room)} checked={readOnly} onChange={handleReadOnly} />
<ToggleSwitch disabled={isDeleting || isRoomFederated(room)} checked={readOnly} onChange={handleReadOnly} />
</FieldRow>
</Box>
<FieldHint>{t('Only_authorized_users_can_write_new_messages')}</FieldHint>
Expand All @@ -314,7 +251,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<Box display='flex' flexDirection='row' justifyContent='space-between' flexGrow={1}>
<FieldLabel>{t('Room_archivation_state_true')}</FieldLabel>
<FieldRow>
<ToggleSwitch disabled={deleting || isRoomFederated(room)} checked={archived} onChange={handleArchived} />
<ToggleSwitch disabled={isDeleting || isRoomFederated(room)} checked={archived} onChange={handleArchived} />
</FieldRow>
</Box>
</Field>
Expand All @@ -325,38 +262,38 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement =>
<Box display='flex' flexDirection='row' justifyContent='space-between' flexGrow={1}>
<FieldLabel>{t('Default')}</FieldLabel>
<FieldRow>
<ToggleSwitch disabled={deleting || isRoomFederated(room)} checked={isDefault} onChange={handleIsDefault} />
<ToggleSwitch disabled={isDeleting || isRoomFederated(room)} checked={isDefault} onChange={handleIsDefault} />
</FieldRow>
</Box>
</Field>
<Field>
<Box display='flex' flexDirection='row' justifyContent='space-between' flexGrow={1}>
<FieldLabel>{t('Favorite')}</FieldLabel>
<FieldRow>
<ToggleSwitch disabled={deleting} checked={favorite} onChange={handleFavorite} />
<ToggleSwitch disabled={isDeleting} checked={favorite} onChange={handleFavorite} />
</FieldRow>
</Box>
</Field>
<Field>
<Box display='flex' flexDirection='row' justifyContent='space-between' flexGrow={1}>
<FieldLabel>{t('Featured')}</FieldLabel>
<FieldRow>
<ToggleSwitch disabled={deleting || isRoomFederated(room)} checked={featured} onChange={handleFeatured} />
<ToggleSwitch disabled={isDeleting || isRoomFederated(room)} checked={featured} onChange={handleFeatured} />
</FieldRow>
</Box>
</Field>
</ContextualbarScrollableContent>
<ContextualbarFooter>
<ButtonGroup stretch>
<Button type='reset' disabled={!hasUnsavedChanges || deleting} onClick={reset}>
<Button type='reset' disabled={!hasUnsavedChanges || isDeleting} onClick={reset}>
{t('Reset')}
</Button>
<Button disabled={!hasUnsavedChanges || deleting} onClick={handleSave}>
<Button disabled={!hasUnsavedChanges || isDeleting} onClick={handleSave}>
{t('Save')}
</Button>
</ButtonGroup>
<ButtonGroup mbs={8} stretch>
<Button icon='trash' danger disabled={deleting || !canDelete || isRoomFederated(room)} onClick={handleDelete}>
<Button icon='trash' danger disabled={isDeleting || !canDeleteRoom || isRoomFederated(room)} onClick={handleDelete}>
{t('Delete')}
</Button>
</ButtonGroup>
Expand Down
89 changes: 89 additions & 0 deletions apps/meteor/client/views/hooks/roomActions/useDeleteRoom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { IRoom, RoomAdminFieldsType } from '@rocket.chat/core-typings';
import { isRoomFederated } from '@rocket.chat/core-typings';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useSetModal, useToastMessageDispatch, useRouter, usePermission, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import React from 'react';

import GenericModal from '../../../components/GenericModal';
import DeleteTeamModal from '../../teams/contextualBar/info/DeleteTeam';

export const useDeleteRoom = (room: IRoom | Pick<IRoom, RoomAdminFieldsType>, { reload }: { reload?: () => void } = {}) => {
const t = useTranslation();
const router = useRouter();
const setModal = useSetModal();
const dispatchToastMessage = useToastMessageDispatch();
const hasPermissionToDelete = usePermission(`delete-${room.t}`, room._id);
const canDeleteRoom = isRoomFederated(room) ? false : hasPermissionToDelete;

const isAdminRoute = router.getRouteName() === 'admin-rooms';

const deleteRoomEndpoint = useEndpoint('POST', '/v1/rooms.delete');
const deleteTeamEndpoint = useEndpoint('POST', '/v1/teams.delete');

const deleteRoomMutation = useMutation({
mutationFn: deleteRoomEndpoint,
onSuccess: () => {
dispatchToastMessage({ type: 'success', message: t('Room_has_been_deleted') });
if (isAdminRoute) {
return router.navigate('/admin/rooms');
}

return router.navigate('/home');
},
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
onSettled: () => {
setModal(null);
reload?.();
},
});

const deleteTeamMutation = useMutation({
mutationFn: deleteTeamEndpoint,
onSuccess: () => {
dispatchToastMessage({ type: 'success', message: t('Team_has_been_deleted') });
if (isAdminRoute) {
return router.navigate('/admin/rooms');
}

return router.navigate('/home');
},
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
onSettled: () => {
setModal(null);
reload?.();
},
});

const isDeleting = deleteTeamMutation.isLoading || deleteRoomMutation.isLoading;

const handleDelete = useMutableCallback(() => {
const handleDeleteTeam = async (roomsToRemove: IRoom['_id'][]) => {
if (!room.teamId) {
return;
}

deleteTeamMutation.mutateAsync({ teamId: room.teamId, ...(roomsToRemove.length && { roomsToRemove }) });
};

if (room.teamMain && room.teamId) {
return setModal(<DeleteTeamModal onConfirm={handleDeleteTeam} onCancel={(): void => setModal(null)} teamId={room.teamId} />);
}

const handleDeleteRoom = async () => {
deleteRoomMutation.mutateAsync({ roomId: room._id });
};

setModal(
<GenericModal variant='danger' onConfirm={handleDeleteRoom} onCancel={(): void => setModal(null)} confirmText={t('Yes_delete_it')}>
{t('Delete_Room_Warning')}
</GenericModal>,
);
});

return { handleDelete, canDeleteRoom, isDeleting };
};
Loading

0 comments on commit 9f9d38a

Please sign in to comment.