RocketChat/Rocket.Chat

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

Summary

Maintainability
A
1 hr
Test Coverage
import type { ISetting } from '@rocket.chat/core-typings';
import type { SettingsContextValue } from '@rocket.chat/ui-contexts';
import { SettingsContext, useAtLeastOnePermission, useMethod } from '@rocket.chat/ui-contexts';
import { Tracker } from 'meteor/tracker';
import type { ReactNode } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';

import { createReactiveSubscriptionFactory } from '../lib/createReactiveSubscriptionFactory';
import { queryClient } from '../lib/queryClient';
import { PrivateSettingsCachedCollection } from '../lib/settings/PrivateSettingsCachedCollection';
import { PublicSettingsCachedCollection } from '../lib/settings/PublicSettingsCachedCollection';

type SettingsProviderProps = {
    children?: ReactNode;
    privileged?: boolean;
};

const SettingsProvider = ({ children, privileged = false }: SettingsProviderProps) => {
    const hasPrivilegedPermission = useAtLeastOnePermission(
        useMemo(() => ['view-privileged-setting', 'edit-privileged-setting', 'manage-selected-settings'], []),
    );

    const hasPrivateAccess = privileged && hasPrivilegedPermission;

    const cachedCollection = useMemo(
        () => (hasPrivateAccess ? PrivateSettingsCachedCollection : PublicSettingsCachedCollection),
        [hasPrivateAccess],
    );

    const [isLoading, setLoading] = useState(() => Tracker.nonreactive(() => !cachedCollection.ready.get()));

    useEffect(() => {
        let mounted = true;

        const initialize = async (): Promise<void> => {
            if (!Tracker.nonreactive(() => cachedCollection.ready.get())) {
                await cachedCollection.init();
            }

            if (!mounted) {
                return;
            }

            setLoading(false);
        };

        initialize();

        return (): void => {
            mounted = false;
        };
    }, [cachedCollection]);

    const querySetting = useMemo(
        () =>
            createReactiveSubscriptionFactory((_id): ISetting | undefined => {
                const subscription = cachedCollection.collection.findOne(_id);
                return subscription ? { ...subscription } : undefined;
            }),
        [cachedCollection],
    );

    const querySettings = useMemo(
        () =>
            createReactiveSubscriptionFactory((query = {}) =>
                cachedCollection.collection
                    .find(
                        {
                            ...('_id' in query && Array.isArray(query._id) && { _id: { $in: query._id } }),
                            ...('_id' in query && !Array.isArray(query._id) && { _id: query._id }),
                            ...('group' in query && { group: query.group }),
                            ...('section' in query &&
                                (query.section
                                    ? { section: query.section }
                                    : {
                                            $or: [{ section: { $exists: false } }, { section: undefined }],
                                      })),
                        },
                        {
                            sort: {
                                section: 1,
                                sorter: 1,
                                i18nLabel: 1,
                            },
                        },
                    )
                    .fetch(),
            ),
        [cachedCollection],
    );

    const settingsChangeCallback = (changes: { _id: string }[]): void => {
        changes.forEach((val) => {
            switch (val._id) {
                case 'Enterprise_License':
                    queryClient.invalidateQueries(['licenses']);
                    break;

                default:
                    break;
            }
        });
    };

    const saveSettings = useMethod('saveSettings');
    const dispatch = useCallback(
        async (changes) => {
            settingsChangeCallback(changes);
            await saveSettings(changes);
        },
        [saveSettings],
    );

    const contextValue = useMemo<SettingsContextValue>(
        () => ({
            hasPrivateAccess,
            isLoading,
            querySetting,
            querySettings,
            dispatch,
        }),
        [hasPrivateAccess, isLoading, querySetting, querySettings, dispatch],
    );

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

export default SettingsProvider;

// '[subscribe: (onStoreChange: () => void) => () => void, getSnapshot: () => {}]'
// '[subscribe: (onStoreChange: () => void) => () => void, getSnapshot: () => ISetting | undefined]'