RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/views/room/providers/RoomProvider.tsx

Summary

Maintainability
A
55 mins
Test Coverage
import type { IRoom } from '@rocket.chat/core-typings';
import { useRouter } from '@rocket.chat/ui-contexts';
import type { ReactNode, ContextType, ReactElement } from 'react';
import React, { useMemo, memo, useEffect, useCallback } from 'react';

import { ChatSubscription } from '../../../../app/models/client';
import { RoomHistoryManager } from '../../../../app/ui-utils/client';
import { UserAction } from '../../../../app/ui/client/lib/UserAction';
import { useReactiveQuery } from '../../../hooks/useReactiveQuery';
import { useReactiveValue } from '../../../hooks/useReactiveValue';
import { RoomManager } from '../../../lib/RoomManager';
import { roomCoordinator } from '../../../lib/rooms/roomCoordinator';
import ImageGalleryProvider from '../../../providers/ImageGalleryProvider';
import RoomNotFound from '../RoomNotFound';
import RoomSkeleton from '../RoomSkeleton';
import { useRoomRolesManagement } from '../body/hooks/useRoomRolesManagement';
import { RoomContext } from '../contexts/RoomContext';
import ComposerPopupProvider from './ComposerPopupProvider';
import RoomToolboxProvider from './RoomToolboxProvider';
import UserCardProvider from './UserCardProvider';
import { useRedirectOnSettingsChanged } from './hooks/useRedirectOnSettingsChanged';
import { useRoomQuery } from './hooks/useRoomQuery';
import { useUsersNameChanged } from './hooks/useUsersNameChanged';

type RoomProviderProps = {
    children: ReactNode;
    rid: IRoom['_id'];
};

const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => {
    useRoomRolesManagement(rid);

    const { data: room, isSuccess } = useRoomQuery(rid);

    // TODO: the following effect is a workaround while we don't have a general and definitive solution for it
    const router = useRouter();
    useEffect(() => {
        if (isSuccess && !room) {
            router.navigate('/home');
        }
    }, [isSuccess, room, router]);

    const subscriptionQuery = useReactiveQuery(['subscriptions', { rid }], () => ChatSubscription.findOne({ rid }) ?? null);

    useRedirectOnSettingsChanged(subscriptionQuery.data);

    useUsersNameChanged();

    const pseudoRoom = useMemo(() => {
        if (!room) {
            return null;
        }

        return {
            ...subscriptionQuery.data,
            ...room,
            name: roomCoordinator.getRoomName(room.t, room),
            federationOriginalName: room.name,
        };
    }, [room, subscriptionQuery.data]);

    const { hasMorePreviousMessages, hasMoreNextMessages, isLoadingMoreMessages } = useReactiveValue(
        useCallback(() => {
            const { hasMore, hasMoreNext, isLoading } = RoomHistoryManager.getRoom(rid);

            return {
                hasMorePreviousMessages: hasMore.get(),
                hasMoreNextMessages: hasMoreNext.get(),
                isLoadingMoreMessages: isLoading.get(),
            };
        }, [rid]),
    );

    const context = useMemo((): ContextType<typeof RoomContext> => {
        if (!pseudoRoom) {
            return null;
        }

        return {
            rid,
            room: pseudoRoom,
            subscription: subscriptionQuery.data ?? undefined,
            hasMorePreviousMessages,
            hasMoreNextMessages,
            isLoadingMoreMessages,
        };
    }, [hasMoreNextMessages, hasMorePreviousMessages, isLoadingMoreMessages, pseudoRoom, rid, subscriptionQuery.data]);

    useEffect(() => {
        RoomManager.open(rid);
        return (): void => {
            RoomManager.back(rid);
        };
    }, [rid]);

    const subscribed = !!subscriptionQuery.data;

    useEffect(() => {
        if (!subscribed) {
            return;
        }

        return UserAction.addStream(rid);
    }, [rid, subscribed]);

    if (!pseudoRoom) {
        return isSuccess && !room ? <RoomNotFound /> : <RoomSkeleton />;
    }

    return (
        <RoomContext.Provider value={context}>
            <RoomToolboxProvider>
                <ImageGalleryProvider>
                    <UserCardProvider>
                        <ComposerPopupProvider room={pseudoRoom}>{children}</ComposerPopupProvider>
                    </UserCardProvider>
                </ImageGalleryProvider>
            </RoomToolboxProvider>
        </RoomContext.Provider>
    );
};

export default memo(RoomProvider);