Home Reference Source

app/components/Sidebar.jsx

import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import { connect } from 'react-redux';
import EventListener, { withOptions } from 'react-event-listener';
import keycode from 'keycode';

// - Import API
import * as AuthAPI from 'AuthAPI';

// - Import actions
import * as authorizeActions from 'authorizeActions';
import * as globalActions from 'globalActions';

// - Fields
const sizeCondition = (width) => (width >= 750);

export class Sidebar extends Component {

    /**
     * Component constructor
     * @param  {object} props is an object properties of component
     */
    constructor(props) {
        super(props);

        // Default state
        this.state = {
            sidebarClass: "",

            overlay: false,

            mainStyle: { marginLeft: "0px" },

            // Is sidebar open or not
            open: false,

            // If sidebar is closed by resizing or not
            auto: false,

            // If overlay should be open or not
            overlayOpen: false,

            // If side bar should be closed
            shouldBeClosed: false
        };
    }

    /**
     * Handle open sidebar
     * @param  {boolean} status if is true, sidebar will be open
     * @param  {string} source is the element that fired the function
     */
    open = (status, source) => {
        const width = window.innerWidth;

        if (status) {
            // Sidebar style when it's open
            const openStyle = {
                width: "210px",
                transform: "translate(0px, 0px)",
                transition: "transform 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms"
            };

            this.setState({
                open: true,
                mainStyle: { marginLeft: "210px" },
                sidebarStyle: openStyle,
                sidebarClass: (sizeCondition(width)) ? "sidebar  sidebar__large" : "sidebar  sidebar__over",
                overlay: (sizeCondition(width)) ? false : true
            });

            if (sizeCondition(width)) {
                this.setState({
                    auto: false,
                    shouldBeClosed: false
                });
            } 
            
            else {
                this.setState({ overlayOpen: true });
            }

            /**
            * Callback function fired to determine sidebar and overlay sidebar status
            * @param {boolean} if true, the sidebar is open
            */
            this.props.status(true);
        }

        // If it's false sidebar should be closed
        else {
            // Sidebar style when it's closed
            const closeStyle = {
                transform: "translate(-100%, 0px)",
                transition: "transform 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms"
            }

            this.setState({
                open: false,
                mainStyle: { marginLeft: "0px" },
                sidebarStyle: closeStyle,
                sidebarClass: (sizeCondition(width)) ? "sidebar  sidebar__large"
                    : ((source === 'auto') ? "sidebar " : "sidebar  sidebar__over"),
                overlay: false
            });

            if (source === 'auto') {
                this.setState({ auto: true });
            }

            else if (source === 'overlay') {
                this.setState({ shouldBeClosed: true });
            }

            /**
            * Callback function fired to determine sidebar and overlay sidebar status
            * @param {boolean} if true, the sidebar is open
            */
            this.props.status(false);
        }

        this.props.overlay((sizeCondition(width)) ? false : true);
    }

    /**
     * Handle resize event for window to change sidebar status
     * @param  {event} evt is the event is passed by winodw resize event
     */
    handleResize = (evt) => {
        const width = window.innerWidth;

        if (sizeCondition(width)) {
            this.setState({
                sidebarClass: "sidebar  sidebar__large",
                overlay: false,
                overlayOpen: false
            });

            this.props.overlay(false);

            if (this.state.auto && !this.state.shouldBeClosed) {
                this.open(true);
                this.setState({ auto: false });
            }
        }

        else {
            if (!this.state.overlayOpen) {
                if (!this.state.auto && this.state.open) {
                    this.open(false, 'auto');

                } 
                
                else {
                    this.setState({
                        overlayOpen: true,
                        overlay: true
                    });
                }
            }
            
            else {
                this.setState({ sidebarClass: "sidebar  sidebar__over", overlay: true });
                this.props.overlay(true);
            }
        }
    }


    // Handle logout user
    handleLogout = () => {
        this.props.dispatch(authorizeActions.dbLogout());
    }

    /**
     * Handle keyup event for window to close sidebar
     * @param  {event} evt is the event is passed by winodw key event
     */
    handleKeyUp = (evt) => {
        if (this.state.overlayOpen) {
            if (this.state.open && keycode(event) === 'esc') {
                this.open(false);
            }
        }
    }

    componentWillMount = () => {
        this.props.open(this.open);
    }

    getChildren = () => {
        return React.Children.map(this.props.children, (childe) => {
            if (childe.type.qcName === 'SidebarContent') {
                const sideBarContent = React.cloneElement(childe, {
                    className: this.state.sidebarClass,
                    cstyle: this.state.sidebarStyle,
                    sidebar: this.open,
                    overlay: this.state.overlay
                });

                return sideBarContent;
            }
            
            else if (childe.type.qcName === 'SidebarMain') {
                return React.cloneElement(childe, { cstyle: this.state.mainStyle });
            }
        });
    }

    componentDidMount = () => {
        this.handleResize();
    }

    /**
    * Reneder component DOM
    * @return {react element} return the DOM which rendered by component
    */
    render() {
        return (
            <div id='sidebar'>
                <EventListener
                    target="window"
                    onResize={this.handleResize}
                    onKeyUp={this.handleKeyUp}
                />
                {this.getChildren()}
            </div>
        )
    }
}

/**
 * Map dispatch to props
 * @param  {func} dispatch is the function to dispatch action to reducers
 * @param  {object} ownProps is the props belong to component
 * @return {object}          props of component
 */
const mapDispatchToProps = (dispatch, ownProps) => {
    return {

    }
}

/**
 * Map state to props
 * @param  {object} state is the obeject from redux store
 * @param  {object} ownProps is the props belong to component
 * @return {object}          props of component
 */
const mapStateToProps = (state, ownProps) => {
    return {
    }
}


// - Connect component to redux store
export default connect(mapStateToProps, mapDispatchToProps)(Sidebar)