<repo_name>dgdagadin87/test_redux<file_sep>/resources/js/service/reducers.jsx
import {combineReducers} from 'redux';
import application from '../reducers/application';
import books from '../reducers/books';
import errors from '../reducers/errors';

const allReducers = combineReducers({
    commonData: application,
    booksData: books,
    errorsData: errors
});

export default allReducers;<file_sep>/resources/js/core/coreUtils.js
function isEmpty(value){
    if (value === null || value === '' || value === undefined ){
        return true;
    }
    else {
        return false;
    }
}

function emptyFunction () {
    return;
}


function checkEmail (value) {
    return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(value);
}

function applyParams (object, config) {
    let property;
    if (object) {
        for (property in config) {
            object[property] = config[property];
        }
    }
    return object;
}

function createUrl (settings, url) {
    return settings['serverProtocol'] + '://' + settings['serverHost'] + ':' + settings['serverPort'] + url;
}

export {isEmpty, createUrl, applyParams, emptyFunction, checkEmail};<file_sep>/resources/js/actions/errors.jsx
export const cleanErrors = (errorsData) => {
    return {
        type: 'ERRORS_CLEAN',
        payload: errorsData
    }
};<file_sep>/resources/js/config/settings.js
let defaultSettings = {
    'serverHost' : '127.0.0.1',
    'serverPort': 9001,
    'serverProtocol': 'http'
};

let pageSettings = {
    'start' : 1,
    'end': 1,
    'left': 2,
    'right': 2
};

let urlSettings = {
    'getCommonData'  : '/common',
    'getBooksData'  : '/mybooks',
    'sendToMail'     : '/sendtomail/',
    'deleteMyBook'   : '/deletebook/'
};

export {defaultSettings, pageSettings, urlSettings};<file_sep>/resources/js/components/rootComponents/ErrorsModalComponent.jsx
import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';
import {cleanErrors} from '../../actions/errors';

const mapStateToProps = state => {
    return {
        errors: state.errorsData.errors
    }
};

function matchDispatchToProps(dispatch) {
    return bindActionCreators({
        cleanErrors: cleanErrors
    }, dispatch);
}

class Errors extends Component {

    _onClickHandler() {

        const {cleanErrors} = this.props;

        cleanErrors(null);
    }

    _renderErrorTemplate(error, index) {

        const errorText = !!error ? error : 'Неизвестная ошика';

        return (
            <div key={index}>{errorText}</div>
        );
    }

    render () {

        const {errors = []} = this.props;

        if (errors.length > 0) {
            return (
                <div>
                    {errors.map((error, index) => this._renderErrorTemplate(error, index))}
                    <button onClick={this._onClickHandler.bind(this)}>Закрыть</button>
                </div>
            );
            return errors
        }
        else {
            return null;
        }
    }
}

export default connect(mapStateToProps, matchDispatchToProps)(Errors);<file_sep>/resources/js/components/moduleComponents/HomeComponent.jsx
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';

import {setTitle} from '../../actions/application';

const mapStateToProps = () => {
    return {};
};

function matchDispatchToProps(dispatch) {
    return bindActionCreators({
        setTitle: setTitle
    }, dispatch);
}

class Home extends Component {

    componentDidMount() {
console.log(this.props);
        let {setTitle} = this.props;

        setTitle('Домашняя страница');
    }

    render () {

        return (
            <div>Домашняя страница</div>
        );
    }

}

export default connect(mapStateToProps, matchDispatchToProps)(Home);<file_sep>/resources/js/reducers/books.jsx
const initialState = {
    collection: false,
    sortField: 'bookName',
    sortType: 'ASC',
    searchTerm: '',
    page: 1,
    pages: 1,
    totalCount: 0,
    disabled: false,
    globalLoading: false
};

export default function (state = null, action) {

    let {payload} = action;

    let returnState = !!state ? state : initialState;

    switch (action.type) {
        case 'BOOKS_LIST_LOADED':
            return {...payload, disabled: false, globalLoading: false};
        case 'START_BOOKS_LOADING':
            return {...returnState, ...payload, disabled: true, globalLoading: false};
        case 'START_BOOKS_GLOBAL_LOADING':
            return {...returnState, ...payload, disabled: false, globalLoading: true};
        case 'ERROR_BOOKS_LOADING':
            return {...returnState, disabled: false, globalLoading: false};
        default:
            return returnState;

    }
}<file_sep>/resources/js/actions/application.jsx
export const loadApplication = (appData) => {
    return {
        type: 'APP_COMMON_LOAD',
        payload: appData
    }
};

export const setTitle = (headerData) => {
    return {
        type: 'APP_SET_HEADER',
        payload: headerData
    }
};

export const errorAppLoading = (appData) => {
    return {
        type: 'ERROR_APP_LOADING',
        payload: appData
    }
};

export const errorDefaultLoading = (errorData) => {
    return {
        type: 'ERROR_DEFAULT_LOADING',
        payload: errorData
    }
};<file_sep>/resources/js/reducers/errors.jsx
const initialState = {
    errors: []
};

export default function (state = null, action) {

    let {payload} = action;

    let returnState = !!state ? state : initialState;

    switch (action.type) {
        case 'ERROR_APP_LOADING':
        case 'ERROR_DEFAULT_LOADING':
        case 'ERROR_BOOKS_LOADING':
            const {errorMessage = null} = payload;
            const errors = returnState.errors || [];
            const returnResult = {
                errors: errors.concat([errorMessage])
            };
            return returnResult;
        case 'ERRORS_CLEAN':
            return initialState;
        default:
            return returnState;

    }
}<file_sep>/resources/js/components/AppContainer.jsx
import '../../css/style.css';

import React, {Component} from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import { Route, Switch } from 'react-router-dom';

import Axios from 'axios';

import {loadApplication, errorAppLoading} from '../actions/application';

import {defaultSettings, urlSettings} from '../config/settings';
import {createUrl} from '../core/coreUtils';

import HeaderComponent from './rootComponents/Header';
import ErrorsComponent from './rootComponents/ErrorsModalComponent';
import HomeComponent from './moduleComponents/HomeComponent';
import BooksComponent from './moduleComponents/BooksComponent';
import AboutComponent from './moduleComponents/AboutComponent';

const mapStateToProps = state => {
    return {
        isLoaded: state.commonData.isLoaded,
        appData: state.commonData.data,
        title: state.commonData.title
    }
};

function matchDispatchToProps(dispatch) {
    return bindActionCreators({
        loadApplication: loadApplication,
        errorAppLoading: errorAppLoading
    }, dispatch);
}

class AppContainer extends Component {

    componentDidMount() {

        const {loadApplication, errorAppLoading} = this.props;

        Axios.get(createUrl(defaultSettings, urlSettings['getCommonData']))
        .then( (response) => {
            const {data : {data = {}}} = response;
            loadApplication(Object.assign({data: data}, {isLoaded: true, title: 'Начало работы'}));
        })
        .catch((error) => {
            const {message = ''} = error;
            errorAppLoading({
                errorMessage: message
            });
        });
    }

    render () {

        const {isLoaded, appData, title} = this.props;

        if (!isLoaded) {
            return (
                <div>
                    <div>Wait, application is loading...</div>
                    <ErrorsComponent />
                </div>
            );
        }

        return (
            <div>
                <HeaderComponent commonData={appData} title={title} />

                <Switch>
                    <Route exact path="/" render={ (props) => <HomeComponent {...props} /> } />
                    <Route path="/books" render={ (props) => <BooksComponent{...props} /> } />
                    <Route path="/about" render={ (props) => <AboutComponent {...props} /> } />
                </Switch>

                <ErrorsComponent />
            </div>
        );
    }

}

export default connect(mapStateToProps, matchDispatchToProps)(AppContainer);