Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .changeset/eight-clouds-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes intermittent "Channel Not Joined" screen when opening rooms in embedded mode.
38 changes: 5 additions & 33 deletions apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import type { RoomType } from '@rocket.chat/core-typings';
import type { ISubscription, RoomType } from '@rocket.chat/core-typings';
import { Box, States, StatesIcon, StatesSubtitle, StatesTitle } from '@rocket.chat/fuselage';
import { Header } from '@rocket.chat/ui-client';
import { useEndpoint, useStream, useUserId } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import { useStream, useUserId } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import { lazy, Suspense, useEffect } from 'react';
import { useTranslation } from 'react-i18next';

import NotSubscribedRoom from './NotSubscribedRoom';
import RoomSkeleton from './RoomSkeleton';
import { useOpenRoom } from './hooks/useOpenRoom';
import { LegacyRoomManager } from '../../../app/ui-utils/client';
import { SubscriptionsCachedStore } from '../../cachedStores';
import { getErrorMessage } from '../../lib/errorHandling';
import { NotAuthorizedError } from '../../lib/errors/NotAuthorizedError';
import { NotSubscribedToRoomError } from '../../lib/errors/NotSubscribedToRoomError';
import { OldUrlRoomError } from '../../lib/errors/OldUrlRoomError';
import { RoomNotFoundError } from '../../lib/errors/RoomNotFoundError';
import { subscriptionsQueryKeys } from '../../lib/queryKeys';
import { mapSubscriptionFromApi } from '../../lib/utils/mapSubscriptionFromApi';

const RoomProvider = lazy(() => import('./providers/RoomProvider'));
const RoomNotFound = lazy(() => import('./RoomNotFound'));
Expand All @@ -34,47 +30,23 @@ type RoomOpenerProps = {
const RoomOpenerEmbedded = ({ type, reference }: RoomOpenerProps): ReactElement => {
const { data, error, isSuccess, isError, isLoading } = useOpenRoom({ type, reference });
const uid = useUserId();

const getSubscription = useEndpoint('GET', '/v1/subscriptions.getOne');

const subscribeToNotifyUser = useStream('notify-user');

const rid = data?.rid;
const { data: subscriptionData, refetch } = useQuery({
queryKey: rid ? subscriptionsQueryKeys.subscription(rid) : [],
queryFn: () => {
if (!rid) {
throw new Error('Room not found');
}
return getSubscription({ roomId: rid });
},
enabled: !!rid,
});

useEffect(() => {
if (!subscriptionData?.subscription) {
if (!uid || !rid) {
return;
}

SubscriptionsCachedStore.upsertSubscription(mapSubscriptionFromApi(subscriptionData.subscription));

// yes this must be done here, this is already called in useOpenRoom, but it skips subscription streams because of the subscriptions list is empty
// now that we inserted the subscription, we can open the room
LegacyRoomManager.open({ typeName: type + reference, rid: subscriptionData.subscription.rid });
}, [subscriptionData, type, rid, reference]);

useEffect(() => {
if (!uid) {
return;
}
return subscribeToNotifyUser(`${uid}/subscriptions-changed`, (event, sub) => {
if (sub.rid !== rid || event === 'removed') {
return;
}

refetch();
SubscriptionsCachedStore.upsertSubscription(sub as ISubscription);
Comment thread
yash-rajpal marked this conversation as resolved.
});
}, [refetch, rid, subscribeToNotifyUser, uid]);
}, [rid, subscribeToNotifyUser, uid]);

const { t } = useTranslation();

Expand Down
66 changes: 61 additions & 5 deletions apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,75 @@
import { useEndpoint, useMethod, useRouter, useUserId } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { ReactElement, ReactNode } from 'react';
import { useEffect } from 'react';
import { useEffect, useMemo } from 'react';

import { RoomsCachedStore, SubscriptionsCachedStore } from '../../../cachedStores';
import { roomsQueryKeys } from '../../../lib/queryKeys';
import { roomCoordinator } from '../../../lib/rooms/roomCoordinator';
import { mapSubscriptionFromApi } from '../../../lib/utils/mapSubscriptionFromApi';
import PageLoading from '../PageLoading';
import { useMainReady } from '../hooks/useMainReady';

const EmbeddedPreload = ({ children }: { children: ReactNode }): ReactElement => {
const ready = useMainReady();
const router = useRouter();
const uid = useUserId();

const roomParams = useMemo(() => {
const routeName = router.getRouteName();
if (!routeName) {
return null;
}

const identifier = roomCoordinator.getRouteNameIdentifier(routeName);
if (!identifier) {
return null;
}

const directives = roomCoordinator.getRoomDirectives(identifier);
if (!directives?.extractOpenRoomParams) {
return null;
}

return directives.extractOpenRoomParams(router.getRouteParameters());
}, [router]);
Comment thread
ricardogarim marked this conversation as resolved.

const getRoomByTypeAndName = useMethod('getRoomByTypeAndName');
const getSubscription = useEndpoint('GET', '/v1/subscriptions.getOne');

const shouldFetch = !!roomParams && !!uid;

const { isLoading, isSuccess, isError } = useQuery({
queryKey: roomParams ? roomsQueryKeys.roomReference(roomParams.reference, roomParams.type, uid ?? undefined) : [],
queryFn: async () => {
if (!roomParams) {
return null;
}

const roomData = await getRoomByTypeAndName(roomParams.type, roomParams.reference);
if (!roomData?._id) {
return null;
}

const subResult = await getSubscription({ roomId: roomData._id });
if (subResult.subscription) {
SubscriptionsCachedStore.upsertSubscription(mapSubscriptionFromApi(subResult.subscription));
}

return subResult;
},
enabled: shouldFetch,
retry: false,
});

useEffect(() => {
SubscriptionsCachedStore.setReady(true);
RoomsCachedStore.setReady(true);
}, [ready]);
if (!shouldFetch || isSuccess || isError) {
SubscriptionsCachedStore.setReady(true);
RoomsCachedStore.setReady(true);
}
}, [shouldFetch, isSuccess, isError]);
Comment thread
ricardogarim marked this conversation as resolved.

if (!ready) {
if (!ready || (shouldFetch && isLoading)) {
return <PageLoading />;
}

Expand Down
Loading