RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/providers/UserProvider/UserProvider.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import type { IRoom, ISubscription, IUser } from '@rocket.chat/core-typings';
import { useLocalStorage } from '@rocket.chat/fuselage-hooks';
import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts';
import { UserContext, useEndpoint } from '@rocket.chat/ui-contexts';
import { Meteor } from 'meteor/meteor';
import type { ContextType, ReactElement, ReactNode } from 'react';
import React, { useEffect, useMemo, useRef } from 'react';

import { Subscriptions, ChatRoom } from '../../../app/models/client';
import { getUserPreference } from '../../../app/utils/client';
import { sdk } from '../../../app/utils/client/lib/SDKClient';
import { afterLogoutCleanUpCallback } from '../../../lib/callbacks/afterLogoutCleanUpCallback';
import { useReactiveValue } from '../../hooks/useReactiveValue';
import { createReactiveSubscriptionFactory } from '../../lib/createReactiveSubscriptionFactory';
import { queryClient } from '../../lib/queryClient';
import { useCreateFontStyleElement } from '../../views/account/accessibility/hooks/useCreateFontStyleElement';
import { useClearRemovedRoomsHistory } from './hooks/useClearRemovedRoomsHistory';
import { useDeleteUser } from './hooks/useDeleteUser';
import { useEmailVerificationWarning } from './hooks/useEmailVerificationWarning';
import { useUpdateAvatar } from './hooks/useUpdateAvatar';

const getUserId = (): string | null => Meteor.userId();

const getUser = (): IUser | null => Meteor.user() as IUser | null;

const logout = (): Promise<void> =>
    new Promise((resolve, reject) => {
        const user = getUser();

        if (!user) {
            return resolve();
        }

        Meteor.logout(async () => {
            await afterLogoutCleanUpCallback.run(user);
            sdk.call('logoutCleanUp', user).then(resolve, reject);
        });
    });

type UserProviderProps = {
    children: ReactNode;
};

const UserProvider = ({ children }: UserProviderProps): ReactElement => {
    const userId = useReactiveValue(getUserId);
    const previousUserId = useRef(userId);
    const user = useReactiveValue(getUser);
    const [userLanguage, setUserLanguage] = useLocalStorage('userLanguage', '');
    const [preferedLanguage, setPreferedLanguage] = useLocalStorage('preferedLanguage', '');

    const setUserPreferences = useEndpoint('POST', '/v1/users.setPreferences');

    const createFontStyleElement = useCreateFontStyleElement();
    createFontStyleElement(user?.settings?.preferences?.fontSize);

    useEmailVerificationWarning(user ?? undefined);
    useClearRemovedRoomsHistory(userId);

    useDeleteUser();
    useUpdateAvatar();

    const contextValue = useMemo(
        (): ContextType<typeof UserContext> => ({
            userId,
            user,
            queryPreference: createReactiveSubscriptionFactory(
                <T,>(key: string, defaultValue?: T) => getUserPreference(userId, key, defaultValue) as T,
            ),
            querySubscription: createReactiveSubscriptionFactory<ISubscription | undefined>((query, fields, sort) =>
                Subscriptions.findOne(query, { fields, sort }),
            ),
            queryRoom: createReactiveSubscriptionFactory<IRoom | undefined>((query, fields) => ChatRoom.findOne(query, { fields })),
            querySubscriptions: createReactiveSubscriptionFactory<SubscriptionWithRoom[]>((query, options) => {
                if (userId) {
                    return Subscriptions.find(query, options).fetch();
                }

                return ChatRoom.find(query, options).fetch();
            }),
            logout,
        }),
        [userId, user],
    );

    useEffect(() => {
        if (!!userId && preferedLanguage !== userLanguage) {
            setUserPreferences({ data: { language: preferedLanguage } });
            setUserLanguage(preferedLanguage);
        }

        if (user?.language !== undefined && user.language !== userLanguage) {
            setUserLanguage(user.language);
            setPreferedLanguage(user.language);
        }
    }, [preferedLanguage, setPreferedLanguage, setUserLanguage, user?.language, userLanguage, userId, setUserPreferences]);

    useEffect(() => {
        if (previousUserId.current && previousUserId.current !== userId) {
            queryClient.clear();
        }

        previousUserId.current = userId;
    }, [userId]);

    return <UserContext.Provider children={children} value={contextValue} />;
};

export default UserProvider;