Thursday, 6 June 2019

django 41 react redux navbar

logging in 

logged in

logged out


//partials/header

import React, { Component } from 'react';
import '../App.css';
import { Menu, Input } from 'antd';
import { Link } from 'react-router-dom'
import { FaCompactDisc, FaPlus, FaEdit, FaBarcode, FaUser, FaSearch } from "react-icons/fa";
import { GiLoveSong } from "react-icons/gi";
import { IoIosLogOut, IoIosLogIn } from "react-icons/io";
import { connect } from 'react-redux';
import { reset } from '../redux/actions/logoutAction'

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

        this.state = {
            menu_mode: null,
            current: 'albums',
        };
    }

    componentWillMount() {
        //change menu mode based on screen width
        const mode = window.innerWidth > 434 ? "horizontal" : "inline";
        this.setState({ menu_mode: mode });
    }

    handleClick = (e) => {

        this.setState({
            current: e.key,
        });
    }

    logout = () => {
        this.props.dispatch(reset())
    }

    render() {
        return (
            <Menu
                style={{ backgroundColor: '#fcefe5' }}
                onClick={this.handleClick}
                selectedKeys={[this.state.current]}
                mode={this.state.menu_mode}
            >
                <Menu.Item key="home">
                    <Link to='/'><span className='Nav-Brand'>Django</span></Link>
                </Menu.Item>
                <Menu.Item key="albums">
                    <Link to='/'> <FaCompactDisc /> Albums</Link>
                </Menu.Item>
                <Menu.Item key="songs">
                    <Link to='/'> <GiLoveSong /> Songs</Link>
                </Menu.Item>
                <Menu.Item key="search">
                    <Input type='text' size='small'
                        suffix={<FaSearch style={{ color: 'rgba(0,0,0,.25)', cursor: 'text' }} />}
                        placeholder='Search'
                        style={{ width: 150 }}></Input>
                </Menu.Item>
                {
                    this.props.loggedin ?
                        <Menu.SubMenu title={<span><FaUser /> {this.props.username}</span>} style={{ float: 'right' }}>
                            <Menu.Item key="0" onClick={() => this.logout()}>
                                <Link to='/logout'> <IoIosLogOut /> Logout</Link>
                            </Menu.Item>
                            <Menu.Item key="1">
                                <Link to='/'> <FaEdit /> Update Profile</Link>
                            </Menu.Item>
                            <Menu.Item key="2">
                                <Link to='/'> <FaBarcode /> Change Password</Link>
                            </Menu.Item>
                        </Menu.SubMenu>
                        :
                        <Menu.Item key="login" style={{ float: 'right' }}>
                            <Link to='/login'> <IoIosLogIn /> Login</Link>
                        </Menu.Item>
                }
                <Menu.Item key="add" style={{ float: 'right' }}>
                    <Link to='/'> <FaPlus /> Add Album</Link>
                </Menu.Item>
            </Menu>
        );
    }
}

export default connect(
    (store) => {
        return {
            username: store.login.username,
            token: store.login.token,
            loggingin: store.login.fetching,
            loggedin: store.login.fetched,
            error: store.login.error
        };
    }
)(Header);

-------------------------------------
//redux/actions/logoutAction

export function reset() {
    return {
        type: "reset",
    }
}

----------------------------------
//redux/reducers/loginReducer

export default function reducer(
    state = {
        username: '',
        token: '',
        fetching: false,
        fetched: false,
        error: ''
    },
    action
) {
    switch (action.type) {
        case "fetch_token_PENDING": {
            return { ...state, fetching: true, fetched: false }
        }

        case "fetch_token_FULFILLED": {
            return {
                ...state,
                fetching: false,
                fetched: true,
                token: action.payload.data.token,
                username: JSON.parse(action.payload.config.data).username,
                error: ''
            }
        }

        case "fetch_token_REJECTED": {
            return {
                ...state,
                fetching: false,
                error: action.payload.toString()
            }
        }

        case "reset": {
            return {
                ...state,
                username: '',
                token: '',
                fetching: false,
                fetched: false,
                error: ''
            }
        }

        default:
            break;
    }
    return state;
}
------------------------------------------
//pages/login

import React, { Component } from 'react';
import '../App.css';
import { Input } from 'antd';
import { FaUser, FaBarcode } from "react-icons/fa";
import { Button } from 'reactstrap';
import { connect } from 'react-redux';
import { fetchToken } from '../redux/actions/loginAction'
import { Redirect } from 'react-router-dom'

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

        this.state = {
            username: '',
            password: '',
        };
    }

    inputChange = (e, p) => {
        this.setState({ [p]: e.target.value });
    }

    formSubmit = (e) => {
        e.preventDefault();

        this.props.dispatch(fetchToken(this.state.username, this.state.password))
    }

    render() {
        if (this.props.loggedin) {
            return <Redirect to='/' />
        }

        return (
            <form style={{ marginLeft: '10px', width: '300px' }}
                onSubmit={(e) => this.formSubmit(e)}>
                <legend>Login</legend>
                <hr />
                <p style={{ color: 'red' }}>{this.props.error}</p>
                <p style={{ color: 'blue' }}>Token: {this.props.token}</p>
                <Input placeholder="username" required='required'
                    prefix={<FaUser style={{ color: 'rgba(0,0,0,.25)' }} />}
                    onChange={(e) => this.inputChange(e, 'username')}
                    style={{ marginTop: '5px' }}
                />
                <Input placeholder="password" required='required' type='password'
                    prefix={<FaBarcode style={{ color: 'rgba(0,0,0,.25)' }} />}
                    onChange={(e) => this.inputChange(e, 'password')}
                    style={{ marginTop: '15px' }}
                />
                <Button color="success" type='submit' size='sm'
                    style={{ marginTop: '15px' }}
                >Submit</Button>
            </form>
        );
    }
}

export default connect(
    (store) => {
        return {
            username: store.login.username,
            token: store.login.token,
            loggingin: store.login.fetching,
            loggedin: store.login.fetched,
            error: store.login.error
        };
    }
)(Login);

-----------------------------------
app.css

@import url(//fonts.googleapis.com/css?family=Srisakdi);

.Nav-Brand{
  font-family: 'Srisakdi', serif;
  font-weight: bold;
  text-shadow: 4px 4px 4px #aaa;
  font-size: 20px;
}

.Body-Background{
  height: 100vh;
  background-image: url("images/background.jpg");
  background-repeat: repeat-y;
  background-size: 100% 100%;
}


reference:

No comments:

Post a Comment