appbaseio/reactivesearch

View on GitHub
packages/web/src/components/basic/ReactiveBase.js

Summary

Maintainability
C
1 day
Test Coverage
/* eslint-disable global-require */

import React, { Component } from 'react';
import { createProvider } from 'react-redux';
import Appbase from 'appbase-js';
import { ThemeProvider } from 'emotion-theming';

import configureStore, { storeKey } from '@appbaseio/reactivecore';
import { checkSomePropChange } from '@appbaseio/reactivecore/lib/utils/helper';
import types from '@appbaseio/reactivecore/lib/utils/types';
import URLParamsProvider from './URLParamsProvider';

import getTheme from '../../styles/theme';
import { composeThemeObject } from '../../utils';

const URLSearchParams = require('url-search-params');

/* use a custom store key so reactivesearch does not interfere
   with a different redux store in a nested context */
const Provider = createProvider(storeKey);

class ReactiveBase extends Component {
    constructor(props) {
        super(props);

        this.state = {
            key: '__REACTIVE_BASE__',
        };

        this.setStore(props);
    }

    componentWillReceiveProps(nextProps) {
        checkSomePropChange(
            this.props,
            nextProps,
            ['app', 'url', 'type', 'credentials', 'mapKey', 'headers'],
            () => {
                this.setStore(nextProps);
                this.setState(state => ({
                    key: `${state.key}-0`,
                }));
            },
        );
    }

    componentDidCatch() {
        console.error(
            "An error has occured. You're using Reactivesearch Version:",
            `${process.env.VERSION || require('../../../package.json').version}.`,
            'If you think this is a problem with Reactivesearch, please try updating',
            "to the latest version. If you're already at the latest version, please open",
            'an issue at https://github.com/appbaseio/reactivesearch/issues',
        );
    }

    setStore = (props) => {
        this.type = props.type ? props.type : '*';

        const credentials
            = props.url && props.url.trim() !== '' && !props.credentials ? null : props.credentials;

        const config = {
            url: props.url && props.url.trim() !== '' ? props.url : 'https://scalr.api.appbase.io',
            app: props.app,
            credentials,
            type: this.type,
            transformRequest: props.transformRequest,
            analytics: props.analytics,
        };

        let queryParams = '';
        if (typeof window !== 'undefined') {
            queryParams = props.getSearchParams ? props.getSearchParams() : window.location.search;
        } else {
            queryParams = props.queryParams || '';
        }

        const params = new URLSearchParams(queryParams);
        let selectedValues = {};

        try {
            Array.from(params.keys()).forEach((key) => {
                const parsedParams = JSON.parse(params.get(key));
                const selectedValue = {};
                if (parsedParams.value) {
                    selectedValue.value = parsedParams.value;
                } else {
                    selectedValue.value = parsedParams;
                }
                if (parsedParams.category) selectedValue.category = parsedParams.category;
                selectedValues = {
                    ...selectedValues,
                    [key]: selectedValue,
                };
            });
        } catch (e) {
            // Do not add to selectedValues if JSON parsing fails.
        }

        const { headers = {}, themePreset } = props;
        const appbaseRef = Appbase(config);
        if (this.props.transformRequest) {
            appbaseRef.transformRequest = this.props.transformRequest;
        }

        const initialState = {
            config: { ...config, mapKey: props.mapKey, themePreset },
            appbaseRef,
            selectedValues,
            headers,
            ...this.props.initialState,
        };
        this.store = configureStore(initialState);
    };

    render() {
        const theme = composeThemeObject(getTheme(this.props.themePreset), this.props.theme);

        return (
            <ThemeProvider theme={theme} key={this.state.key}>
                <Provider store={this.store}>
                    <URLParamsProvider
                        headers={this.props.headers}
                        style={this.props.style}
                        className={this.props.className}
                        getSearchParams={this.props.getSearchParams}
                        setSearchParams={this.props.setSearchParams}
                    >
                        {this.props.children}
                    </URLParamsProvider>
                </Provider>
            </ThemeProvider>
        );
    }
}

ReactiveBase.defaultProps = {
    theme: {},
    themePreset: 'light',
    initialState: {},
    analytics: false,
};

ReactiveBase.propTypes = {
    app: types.stringRequired,
    children: types.children,
    credentials: types.string,
    headers: types.headers,
    queryParams: types.string,
    theme: types.style,
    themePreset: types.themePreset,
    type: types.string,
    url: types.string,
    transformRequest: types.func,
    mapKey: types.string,
    style: types.style,
    className: types.string,
    initialState: types.children,
    analytics: types.bool,
    getSearchParams: types.func,
    setSearchParams: types.func,
};

export default ReactiveBase;