Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
February 20, 2021 02:50 am GMT

Build an E-Commerce Website with MERN Stack - Part 6 (Redux Actions and Auth Components)

Hello friends! So, this is the sixth part of the MERN Stack series. In the first four parts, we discussed the backend part of our application in complete detail from setting up the routes to accepting payments via stripe, we did all the backend work in those four parts. Then in the fifth part, we started building our frontend side, setting up the Redux actions and store.

Notice: I will publish the complete detailed version of all the articles on the Medium website. Here I will give an overview and give the codes for the various pages part by part.
So, please click here to go to Medium and read it in completion. (These are friend links so do not worry about paywall)

So, lets start to build the reducer files first. We would create a folder inside the client folder which we would name as reducers. Inside this folder, we would create six files index, authReducer, itemReducer, errorReducer, cartReducer and orderReducer.

authReducer

import {    USER_LOADING,    USER_LOADED,    AUTH_ERROR,    LOGIN_SUCCESS,    LOGIN_FAIL,    LOGOUT_SUCCESS,    REGISTER_SUCCESS,    REGISTER_FAIL} from '../actions/types';const initialState = {    token: localStorage.getItem('token'),    isAuthenticated: null,    isLoading: false,    user: null}export default function(state=initialState, action){    switch(action.type){        case USER_LOADING:            return {                ...state,                isLoading: true            };        case USER_LOADED:            return{                ...state,                isAuthenticated: true,                isLoading: false,                user: action.payload            }        case LOGIN_SUCCESS:        case REGISTER_SUCCESS:            localStorage.setItem('token',action.payload.token);            return{                ...state,                ...action.payload,                isAuthenticated: true,                isLoading: false            };        case AUTH_ERROR:        case LOGIN_FAIL:        case LOGOUT_SUCCESS:        case REGISTER_FAIL:            localStorage.removeItem('token');            return{                ...state,                token: null,                user: null,                isAuthenticated: false,                isLoading: false            };        default:            return state;    }}
Enter fullscreen mode Exit fullscreen mode

itemReducer

import { GET_ITEMS, ADD_ITEM, UPDATE_ITEM, DELETE_ITEM, ITEMS_LOADING } from '../actions/types';const initialState = {    items: [],    loading: false}export default function(state=initialState, action){    switch(action.type){        case GET_ITEMS:            return{                ...state,                items: action.payload,                loading: false            }        case ADD_ITEM:            return{                ...state,                items: [action.payload, ...state.items]            }        case DELETE_ITEM:            return{                ...state,                items: state.items.filter(item => item._id!==action.payload)                            };        case UPDATE_ITEM:            const { id, data } = action.payload;            return{                ...state,                items: state.items.map(item => {                    if(item._id===id){                        item = data;                    }                })            }        case ITEMS_LOADING:            return{                ...state,                loading: true            }        default:            return state;    }}
Enter fullscreen mode Exit fullscreen mode

errorReducer

import { GET_ERRORS, CLEAR_ERRORS } from '../actions/types';const initialState = {    msg: {},    status: null,    id: null}export default function(state=initialState, action){    switch(action.type){        case GET_ERRORS:            return{                msg: action.payload.msg,                status: action.payload.status,                id: action.payload.id            };        case CLEAR_ERRORS:            return{                msg: {},                status: null,                id: null            };        default:            return state;    }}
Enter fullscreen mode Exit fullscreen mode

cartReducer

import { GET_CART, ADD_TO_CART, DELETE_FROM_CART, CART_LOADING } from '../actions/types';const initialState = {    cart: null,    loading: false}export default function(state=initialState, action){    switch(action.type){        case GET_CART:            return {                ...state,                cart: action.payload,                loading: false            }        case ADD_TO_CART:            return {                ...state,                cart: action.payload            }        case DELETE_FROM_CART:            return {                ...state,                cart: action.payload            }        case CART_LOADING:            return {                ...state,                 loading: true            }        default:            return state;    }}
Enter fullscreen mode Exit fullscreen mode

orderReducer

import { GET_ORDERS, CHECKOUT, ORDERS_LOADING } from '../actions/types';const initialState = {    orders: [],    loading: false}export default function(state=initialState, action){    switch(action.type){        case GET_ORDERS:            return{                ...state,                orders: action.payload,                loading: false            }        case CHECKOUT:            return{                ...state,                orders: [action.payload, ...state.orders]            }        case ORDERS_LOADING:            return{                ...state,                loading: true            }        default:            return state;    }}
Enter fullscreen mode Exit fullscreen mode

index (Combining Reducers)

import { combineReducers } from 'redux';import itemReducer from './itemReducer';import errorReducer from './errorReducer';import authReducer from './authReducer';import cartReducer from './cartReducer';import orderReducer from './orderReducer';export default combineReducers({    item: itemReducer,    error: errorReducer,    auth: authReducer,    cart: cartReducer,    order: orderReducer})
Enter fullscreen mode Exit fullscreen mode

Now, we have finished all the redux work. Now, we can focus on building components for our application.

So, we will deal with the components needed for authentication in this part and will deal with all the other components in the next part of the series.

First of all, we would create a folder called components inside the client folder. Since we will keep all the authentication components separate from the rest of our components, so will make another folder named auth inside the components folder.

Both of our Login and Register will be modal based which would be displayed in the Navbar.

loginModal

import { Component } from 'react';import {    Button,    Modal,    ModalHeader,    ModalBody,    Form,    FormGroup,    Label,    Input,    NavLink,    Alert} from 'reactstrap';import { connect } from 'react-redux';import PropTypes from 'prop-types';import { login } from '../../actions/authActions';import { clearErrors } from '../../actions/errorActions';class LoginModal extends Component {    state = {        modal: false,        email: '',        password: '',        msg: null    };    static propTypes = {        isAuthenticated: PropTypes.bool,        error: PropTypes.object.isRequired,        login: PropTypes.func.isRequired,        clearErrors: PropTypes.func.isRequired    }    componentDidUpdate(prevProps) {        const { error, isAuthenticated } = this.props;        if(error !== prevProps.error){            // Check for login error            if(error.id === 'LOGIN_FAIL'){                this.setState({msg: error.msg.msg});            }            else{                this.setState({msg:null});            }        }        // If authenticated, close modal        if(this.state.modal){            if(isAuthenticated){                this.toggle();            }        }    }    toggle = () => {        // Clear errors        this.props.clearErrors();        this.setState({            modal: !this.state.modal        });    }    onChange = (e) => {        this.setState({[e.target.name]:e.target.value});    }    onSubmit = (e) => {        e.preventDefault();         const {email, password} = this.state;        const user = {email, password};        // Attempt to login        this.props.login(user);    }    render(){        return(            <div className="container">                <Button color="success" className="btn btn-sm"><NavLink onClick={this.toggle} href="#"><span className="text-dark"><b>Login</b></span></NavLink></Button>                <Modal                    isOpen={this.state.modal}                    toggle={this.toggle}                >                    <ModalHeader toggle={this.toggle}>                        Login                    </ModalHeader>                    <ModalBody>                        {this.state.msg ? (<Alert color="danger">{this.state.msg}</Alert>):null}                        <Form onSubmit={this.onSubmit}>                            <FormGroup>                                <Label for="email">Email</Label>                                <Input                                    type="email"                                    name="email"                                    id="email"                                    placeholder="Email"                                    className="mb-3"                                    onChange={this.onChange}                                />                                <Label for="password">Password</Label>                                <Input                                    type="password"                                    name="password"                                    id="password"                                    placeholder="Password"                                    className="mb-3"                                    onChange={this.onChange}                                />                                <Button                                    color="dark"                                    style={{marginTop: '2rem'}}                                    block                                >Login</Button>                            </FormGroup>                        </Form>                    </ModalBody>                </Modal>            </div>        );    }}const mapStateToProps = (state) => ({    isAuthenticated: state.auth.isAuthenticated,    error: state.error});export default connect(mapStateToProps,{login, clearErrors})(LoginModal);
Enter fullscreen mode Exit fullscreen mode

registerModal

import { Component } from 'react';import {    Button,    Modal,    ModalHeader,    ModalBody,    Form,    FormGroup,    Label,    Input,    NavLink,    Alert} from 'reactstrap';import { connect } from 'react-redux';import PropTypes from 'prop-types';import { register } from '../../actions/authActions';import { clearErrors } from '../../actions/errorActions';class RegisterModal extends Component {    state = {        modal: false,        name: '',        email: '',        password: '',        msg: null    };    static propTypes = {        isAuthenticated: PropTypes.bool,        error: PropTypes.object.isRequired,        register: PropTypes.func.isRequired,        clearErrors: PropTypes.func.isRequired    }    componentDidUpdate(prevProps) {        const { error, isAuthenticated } = this.props;        if(error !== prevProps.error){            // Check for register error            if(error.id === 'REGISTER_FAIL'){                this.setState({msg: error.msg.msg});            }            else{                this.setState({msg:null});            }        }        // If authenticated, close modal        if(this.state.modal){            if(isAuthenticated){                this.toggle();            }        }    }    toggle = () => {        // Clear errors        this.props.clearErrors();        this.setState({            modal: !this.state.modal        });    }    onChange = (e) => {        this.setState({[e.target.name]:e.target.value});    }    onSubmit = (e) => {        e.preventDefault();          const { name, email, password } = this.state;        // Crete user object        const newUser = { name, email, password};        // Attempt to register        this.props.register(newUser);    }    render(){        return(            <div className="container">                <Button color="info" className="btn btn-sm"><NavLink onClick={this.toggle} href="#"><span className="text-dark"><b>Register</b></span></NavLink></Button>                <Modal                    isOpen={this.state.modal}                    toggle={this.toggle}                >                    <ModalHeader toggle={this.toggle}>                        Register                    </ModalHeader>                    <ModalBody>                        {this.state.msg ? (<Alert color="danger">{this.state.msg}</Alert>):null}                        <Form onSubmit={this.onSubmit}>                            <FormGroup>                                <Label for="name">Name</Label>                                <Input                                    type="text"                                    name="name"                                    id="name"                                    placeholder="Name"                                    className="mb-3"                                    onChange={this.onChange}                                />                                <Label for="email">Email</Label>                                <Input                                    type="email"                                    name="email"                                    id="email"                                    placeholder="Email"                                    className="mb-3"                                    onChange={this.onChange}                                />                                <Label for="password">Password</Label>                                <Input                                    type="password"                                    name="password"                                    id="password"                                    placeholder="Password"                                    className="mb-3"                                    onChange={this.onChange}                                />                                <Button                                    color="dark"                                    style={{marginTop: '2rem'}}                                    block                                >Register</Button>                            </FormGroup>                        </Form>                    </ModalBody>                </Modal>            </div>        );    }}const mapStateToProps = (state) => ({    isAuthenticated: state.auth.isAuthenticated,    error: state.error});export default connect(mapStateToProps,{register, clearErrors})(RegisterModal);
Enter fullscreen mode Exit fullscreen mode

Logout

import { Component, Fragment } from 'react';import { logout } from '../../actions/authActions';import { connect } from 'react-redux';import {NavLink, Button} from 'reactstrap';import PropTypes from 'prop-types';export class Logout extends Component {    static propTypes = {        logout: PropTypes.func.isRequired    }    render() {        return (            <div>                <Fragment>                    <Button color="danger" className="btn btn-sm"><NavLink onClick={this.props.logout} href="#"><span className="text-light"><b>Logout</b></span></NavLink></Button>                </Fragment>            </div>        )    }}export default connect(null,{logout})(Logout);
Enter fullscreen mode Exit fullscreen mode

So, this is all for this part. We have finished off the Redux part and also built out the components needed for the authentication.

In the next part which will be the final one, we will be building the rest of the components and will finish off this series. I hope it helped you learn something and was exciting for you.

To read the complete tutorial, please move to Medium and read the complete article.


Original Link: https://dev.to/shubham1710/build-an-e-commerce-website-with-mern-stack-part-6-redux-actions-and-auth-components-2m6l

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To