From ec8e46a248f3f2b0942d88b4aa05a7b54ef6ccd5 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 11 Nov 2025 11:47:03 -0300 Subject: [PATCH 1/3] fix: check for subscription --- .../contextualBar/Info/hooks/actions/useRoomLeave.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx index 2f53b9d95ed37..485ebcf868d25 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx +++ b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx @@ -1,22 +1,23 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useRouter, useSetModal, useToastMessageDispatch, useMethod, useTranslation, usePermission } from '@rocket.chat/ui-contexts'; +import { useRouter, useSetModal, useToastMessageDispatch, useMethod, usePermission, useUserSubscription } from '@rocket.chat/ui-contexts'; +import { useTranslation } from 'react-i18next'; import { LegacyRoomManager } from '../../../../../../../app/ui-utils/client'; import { UiTextContext } from '../../../../../../../definition/IRoomTypeConfig'; import WarningModal from '../../../../../../components/WarningModal'; import { roomCoordinator } from '../../../../../../lib/rooms/roomCoordinator'; -// TODO implement joined -export const useRoomLeave = (room: IRoom, joined = true) => { - const t = useTranslation(); +export const useRoomLeave = (room: IRoom) => { + const { t } = useTranslation(); + const subscription = useUserSubscription(room._id); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); const leaveRoom = useMethod('leaveRoom'); const router = useRouter(); - const canLeave = usePermission(room.t === 'c' ? 'leave-c' : 'leave-p') && room.cl !== false && joined; + const canLeave = usePermission(room.t === 'c' ? 'leave-c' : 'leave-p') && room.cl !== false && Boolean(subscription); const handleLeave = useEffectEvent(() => { const leaveAction = async () => { From 8c2debbec866c6257eb16bfd52ead1466849d5c9 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 11 Nov 2025 11:47:12 -0300 Subject: [PATCH 2/3] test: add unit test --- .../Info/hooks/actions/useRoomLeave.spec.ts | 40 +++++++++++++++++++ .../src/MockedAppRootBuilder.tsx | 4 +- 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.spec.ts diff --git a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.spec.ts b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.spec.ts new file mode 100644 index 0000000000000..e864998f63781 --- /dev/null +++ b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.spec.ts @@ -0,0 +1,40 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts'; +import { renderHook } from '@testing-library/react'; + +import { useRoomLeave } from './useRoomLeave'; +import { createFakeRoom, createFakeSubscription } from '../../../../../../../tests/mocks/data'; + +const mockRoom = createFakeRoom({ _id: 'room1', t: 'c', name: 'room1', fname: 'Room 1' }); +const mockSubscription = createFakeSubscription({ name: 'room1', t: 'c', disableNotifications: false, rid: 'room1' }); + +jest.mock('../../../../../../../app/ui-utils/client', () => ({ + LegacyRoomManager: { + close: jest.fn(), + }, +})); + +jest.mock('../../../../../../../client/lib/rooms/roomCoordinator', () => ({ + roomCoordinator: { + getRoomDirectives: () => ({ + getUiText: () => 'leaveWarning', + }), + }, +})); + +it('should return leave function if user has subscription', () => { + const wrapper = mockAppRoot() + .withPermission('leave-c') + .withSubscriptions([{ ...mockSubscription, rid: 'room1' }] as unknown as SubscriptionWithRoom[]) + .build(); + + const { result } = renderHook(() => useRoomLeave(mockRoom), { wrapper }); + expect(typeof result.current).toBe('function'); +}); + +it('should return null if user does not have subscription', () => { + const wrapper = mockAppRoot().withPermission('leave-c').build(); + + const { result } = renderHook(() => useRoomLeave(mockRoom), { wrapper }); + expect(result.current).toBeNull(); +}); diff --git a/packages/mock-providers/src/MockedAppRootBuilder.tsx b/packages/mock-providers/src/MockedAppRootBuilder.tsx index c22cf7b992650..48305a3f14dc0 100644 --- a/packages/mock-providers/src/MockedAppRootBuilder.tsx +++ b/packages/mock-providers/src/MockedAppRootBuilder.tsx @@ -150,7 +150,7 @@ export class MockedAppRootBuilder { queryPreference: () => [() => () => undefined, () => undefined], queryRoom: () => [() => () => undefined, () => this.room], querySubscription: () => [() => () => undefined, () => this.subscriptions as unknown as ISubscription], - querySubscriptions: () => [() => () => undefined, () => this.subscriptions], // apply query and option + querySubscriptions: () => [() => () => undefined, () => this.subscriptions ?? []], // apply query and option user: null, userId: undefined, }; @@ -203,7 +203,7 @@ export class MockedAppRootBuilder { private room: IRoom | undefined = undefined; - private subscriptions: SubscriptionWithRoom[] = []; + private subscriptions: SubscriptionWithRoom[] | undefined = undefined; private modal: ModalContextValue = { currentModal: { component: null }, From 2c7e9884183723dc60d6f4d773b5e2ae45b979a4 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 11 Nov 2025 11:48:28 -0300 Subject: [PATCH 3/3] chore: changeset --- .changeset/modern-onions-repair.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/modern-onions-repair.md diff --git a/.changeset/modern-onions-repair.md b/.changeset/modern-onions-repair.md new file mode 100644 index 0000000000000..554aa93eeef0c --- /dev/null +++ b/.changeset/modern-onions-repair.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/mock-providers': patch +'@rocket.chat/meteor': patch +--- + +Fixes an issue where leave room action is available for users without subscription