Sunday 9 June 2019

django 42 react redux fetch data with token


data fetched with auth token


//pages/albums

import React, { Component } from 'react';
import '../App.css';
import { Table } from 'reactstrap';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { getAlbums } from '../redux/actions/getAlbums'

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

        this.state = {

        };
    }

    componentDidMount() {
        if (this.props.loggedin) {
            this.props.dispatch(getAlbums(this.props.token));
        }
    }

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

        const tableContent = [];

        if (this.props.gotAlbums) {
            this.props.albums.forEach(album => {
                tableContent.push(
                    <tr key={album.id}>
                        <td>{album.id}</td>
                        <td>{album.album_title}</td>
                        <td>{album.artist}</td>
                        <td>{album.genre}</td>
                        <td>{album.author}</td>
                        <td>{album.date_posted}</td>
                    </tr>
                )
            });
        }

        return (
            <div style={{ padding: '10px' }}>
                {this.props.error}
                {
                    this.props.gotAlbums ?
                        <div>
                            <Table bordered>
                                <thead>
                                    <tr>
                                        <th>ID</th>
                                        <th>Title</th>
                                        <th>Artist</th>
                                        <th>Genre</th>
                                        <th>Author</th>
                                        <th>Posted</th>
                                    </tr>
                                </thead>

                                <tbody>
                                    {tableContent}
                                </tbody>
                            </Table>
                        </div>
                        : null
                }
            </div>
        );
    }
}

export default connect(
    (store) => {
        return {
            token: store.login.token,
            loggedin: store.login.fetched,
            error: store.albums.error,
            albums: store.albums.albums,
            gotAlbums: store.albums.fetched
        };
    }
)(Albums);

--------------------------------------------
//redux/actions/getAlbums

import axios from 'axios';

export function getAlbums(token) {
    return {
        type: "fetch_albums",
        payload: axios({
            method: 'get',
            url: 'http://127.0.0.1:8000/api/album_list/',
            headers: {
                Authorization: 'Token ' + token
            },
        })
    }
}

-----------------------------------------
//redux/reducers/albumReducer

export default function reducer(
    state = {
        albums: [],
        fetching: false,
        fetched: false,
        error: ''
    },
    action
) {
    switch (action.type) {
        case "fetch_albums_PENDING": {
            return { ...state, fetching: true, fetched: false }
        }

        case "fetch_albums_FULFILLED": {
            return {
                ...state,
                fetching: false,
                fetched: true,
                albums: action.payload.data,
                error: ''
            }
        }

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

        default:
            break;
    }
    return state;
}

-------------------------------------
//redux/reducers/index

import { combineReducers } from 'redux';
import login from "./loginReduder";
import albums from "./albumReducer";

export default combineReducers(
    {
        login, albums
    })

---------------------------------
//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', position: 'sticky', top: 0, zIndex: 2 }}
                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);

--------------------------------------------
//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-size: 100%;
  overflow: auto;
}

-----------------------------------------
//partials/body

import React, { Component } from 'react';
import '../App.css';
import { Switch, Route } from 'react-router-dom';
import Albums from '../pages/albums';
import Login from '../pages/login';
import Logout from '../pages/logout';

export default class Body extends Component {

    render() {
        return (
            <main className='Body-Background'>
                <Switch>
                    <Route exact path='/' component={Albums} />
                    <Route path='/login/' component={Login} />
                    <Route path='/logout/' component={Logout} />
                </Switch>
            </main>
        );
    }
}

reference:
http://chuanshuoge2.blogspot.com/2019/06/django-40-django-react-redux-ftech-token.html
https://chuanshuoge2.blogspot.com/2019/05/django-38-rest-framework-authentication.html

No comments:

Post a Comment