RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersWithData.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import type { IRoom, IUser } from '@rocket.chat/core-typings';
import { isRoomFederated, isDirectMessageRoom, isTeamRoom } from '@rocket.chat/core-typings';
import { useMutableCallback, useDebouncedValue, useLocalStorage } from '@rocket.chat/fuselage-hooks';
import { useUserRoom, useAtLeastOnePermission, useUser, usePermission, useUserSubscription } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useCallback, useMemo, useState } from 'react';

import * as Federation from '../../../../lib/federation/Federation';
import { useMembersList } from '../../../hooks/useMembersList';
import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
import UserInfoWithData from '../UserInfo';
import AddUsers from './AddUsers';
import InviteUsers from './InviteUsers';
import RoomMembers from './RoomMembers';

enum ROOM_MEMBERS_TABS {
    INFO = 'user-info',
    INVITE = 'invite-users',
    ADD = 'add-users',
    LIST = 'users-list',
}

type validRoomType = 'd' | 'p' | 'c';

const RoomMembersWithData = ({ rid }: { rid: IRoom['_id'] }): ReactElement => {
    const user = useUser();
    const room = useUserRoom(rid);
    const { closeTab } = useRoomToolbox();
    const [type, setType] = useLocalStorage<'online' | 'all'>('members-list-type', 'online');
    const [text, setText] = useState('');
    const subscription = useUserSubscription(rid);

    const isTeam = room && isTeamRoom(room);
    const isDirect = room && isDirectMessageRoom(room);
    const hasPermissionToCreateInviteLinks = usePermission('create-invite-links', rid);
    const isFederated = room && isRoomFederated(room);

    const canCreateInviteLinks =
        room && user && isFederated ? Federation.canCreateInviteLinks(user, room, subscription) : hasPermissionToCreateInviteLinks;

    const [state, setState] = useState<{ tab: ROOM_MEMBERS_TABS; userId?: IUser['_id'] }>({
        tab: ROOM_MEMBERS_TABS.LIST,
        userId: undefined,
    });

    const debouncedText = useDebouncedValue(text, 800);

    const { data, fetchNextPage, isLoading, refetch, hasNextPage } = useMembersList(
        useMemo(() => ({ rid, type, limit: 50, debouncedText, roomType: room?.t as validRoomType }), [rid, type, debouncedText, room?.t]),
    );

    const hasPermissionToAddUsers = useAtLeastOnePermission(
        useMemo(() => [room?.t === 'p' ? 'add-user-to-any-p-room' : 'add-user-to-any-c-room', 'add-user-to-joined-room'], [room?.t]),
        rid,
    );

    const canAddUsers = room && user && isFederated ? Federation.isEditableByTheUser(user, room, subscription) : hasPermissionToAddUsers;

    const handleTextChange = useCallback((event) => {
        setText(event.currentTarget.value);
    }, []);

    const openUserInfo = useMutableCallback((e) => {
        const { userid } = e.currentTarget.dataset;
        setState({
            tab: ROOM_MEMBERS_TABS.INFO,
            userId: userid,
        });
    });

    const openInvite = useMutableCallback(() => {
        setState({ tab: ROOM_MEMBERS_TABS.INVITE });
    });

    const openAddUser = useMutableCallback(() => {
        setState({ tab: ROOM_MEMBERS_TABS.ADD });
    });

    const handleBack = useCallback(() => {
        setState({ tab: ROOM_MEMBERS_TABS.LIST });
    }, [setState]);

    if (state.tab === ROOM_MEMBERS_TABS.INFO && state.userId) {
        return <UserInfoWithData rid={rid} uid={state.userId} onClose={closeTab} onClickBack={handleBack} />;
    }

    if (state.tab === ROOM_MEMBERS_TABS.INVITE) {
        return <InviteUsers rid={rid} onClickBack={handleBack} />;
    }

    if (state.tab === ROOM_MEMBERS_TABS.ADD) {
        return <AddUsers rid={rid} onClickBack={handleBack} reload={refetch} />;
    }

    return (
        <RoomMembers
            rid={rid}
            isTeam={isTeam}
            isDirect={isDirect}
            loading={isLoading}
            type={type}
            text={text}
            setText={handleTextChange}
            setType={setType}
            members={data?.pages?.flatMap((page) => page.members) ?? []}
            total={data?.pages[data.pages.length - 1].total ?? 0}
            onClickClose={closeTab}
            onClickView={openUserInfo}
            loadMoreItems={hasNextPage ? fetchNextPage : () => undefined}
            reload={refetch}
            onClickInvite={canCreateInviteLinks && canAddUsers ? openInvite : undefined}
            onClickAdd={canAddUsers ? openAddUser : undefined}
        />
    );
};

export default RoomMembersWithData;