Friday, 14 June 2019

django 46 react toggle flippy card

initial page

flip 4 middle cards by clicking the flip button 
manu-flip is added to the DOM class of flipped elements

flip back 2 middle cards by click the flip buttons again
manu-flip class is removed from the DOM classlist

//pages/albums

import React, { Component } from 'react';
import '../App.css';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import FlippyCard from '../partials/flippyCard';
import { Row, Col } from 'reactstrap'
import { getAlbums } from '../redux/actions/getAlbums';
import { getUsers } from '../redux/actions/getUser'

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

        this.state = {
            AlbumAuthorData: [],
            AlbumAuthorIntegrated: false,
        };
    }

    componentDidMount() {

        //start fetching database once logged in
        if (this.props.loggedin) {
            if (!this.props.gotUsers) {
                this.props.dispatch(getUsers(this.props.token));
            }
            if (!this.props.gotAlbums) {
                this.props.dispatch(getAlbums(this.props.token));
            }
        }

        //check every 1 second to see if albums are fetched. If so, start integrating Albums and Authors
        const waitGetAlbums = setInterval(() => {
            if (this.props.gotAlbums && this.props.gotUsers) {
                let newAlbums = []

                this.props.albums.map((album, index) => {
                    const newAlbum = {
                        'id': album.id,
                        'album_title': album.album_title,
                        'artist': album.artist,
                        'genre': album.genre,
                        'date_posted': album.date_posted,
                        'author': this.props.users.filter(author => author.id == album.author)[0].username,
                        'album_logo': album.album_logo
                    }

                    newAlbums.push(newAlbum);
                });

                this.setState({ AlbumAuthorData: newAlbums, AlbumAuthorIntegrated: true });
                clearInterval(waitGetAlbums);
            }
        }, 1000)
    }

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

        const cards = [];

        if (this.state.AlbumAuthorIntegrated) {
            this.state.AlbumAuthorData.map((item, index) => {
                const card = <Col key={index}>
                    <FlippyCard data={item}></FlippyCard>
                </Col>

                cards.push(card);
            })
        }

        return (
            <div style={{ marginTop: '20px' }}>
                {this.props.error}

                {
                    this.state.AlbumAuthorIntegrated ?
                        <Row>
                            {cards}
                        </Row>
                        : <p>integrating authors and albums...</p>
                }
            </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,
            users: store.users.users,
            gotUsers: store.users.fetched,
        };
    }
)(Albums);

-----------------------------------------
//partials/flippyCard

import React, { Component } from 'react';
import '../App.css';
import { FaPenNib } from "react-icons/fa";
import { Button } from 'reactstrap';
import { MdEdit, MdDelete, MdFlip } from "react-icons/md";

export default class FlippyCard extends Component {
    constructor(props) {
        super(props);
        this.myRef = React.createRef();
    }

    flipClick = () => {
        this.myRef.current.classList.toggle('manu-flip');
        console.log('Album: ', this.props.data.album_title, ' DOM class: ', this.myRef.current.classList);
    }

    render() {
        const imgSrc = 'http://127.0.0.1:8000' + this.props.data.album_logo;
       
        //onTouchStart is for touch screen device, tigger flip click when element is touched.
        return (
            <div className="flip-container" ref={this.myRef} onTouchStart={()=>this.flipClick()} style={{ margin: '10px' }}>
                <div className="flipper">
                    <div className="front" style={{ backgroundColor: 'white' }}>
                        <img src={imgSrc}
                            style={{ height: '150px', width: '100%' }}></img>
                        <div style={{ height: '60px' }}>
                            <h6 style={{ textAlign: 'center', marginTop: '10px' }}>{this.props.data.album_title}</h6>
                        </div>
                        <div style={{ backgroundColor: '#F4F6F6', height: '30px', paddingLeft: '5px' }}>
                            <FaPenNib /> <span>{this.props.data.author}</span>
                        </div>
                        <MdFlip className='flip-button' onClick={() => this.flipClick()} />
                    </div>
                    <div className="back" style={{ backgroundColor: 'white' }}>
                        <div style={{ textAlign: 'center', height: '220px', paddingTop: '10px' }}>
                            <p>Artist: {this.props.data.artist}</p>
                            <p>Genre: {this.props.data.genre}</p>
                            <div style={{ display: 'flex', justifyContent: 'space-around', marginLeft: '5px', marginRight: '5px' }}>
                                <Button color='primary' size='sm'>View Detail</Button>
                                <Button outline size='sm'><MdEdit /></Button>
                                <Button outline size='sm'><MdDelete /></Button>
                            </div>
                        </div>
                        <div style={{ backgroundColor: '#F4F6F6', height: '30px', paddingLeft: '5px' }}>
                            <FaPenNib /> <span>{this.props.data.date_posted.split('.')[0].replace('T', ' ')}</span>
                        </div>
                        <MdFlip className='flip-button' onClick={() => this.flipClick()} />
                    </div>
                </div>
            </div>
        );
    }
}

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

/* entire container, keeps perspective */
.flip-container {
perspective: 1000px;
}
/* flip the pane when hovered, or flip button clicked */
.flip-container:hover .flipper, .flip-container.manu-flip .flipper {
transform: rotateY(180deg);
}

.flip-container, .front, .back {
width: 200px;
height: 250px;
}

/* flip speed goes here */
.flipper {
transition: 0.6s;
transform-style: preserve-3d;

position: relative;
}

/* hide back of pane during swap */
.front, .back {
backface-visibility: hidden;

position: absolute;
top: 0;
left: 0;
}

/* front pane, placed above back */
.front {
z-index: 2;
/* for firefox 31 */
transform: rotateY(0deg);
}

/* back, initially hidden pane */
.back {
transform: rotateY(180deg);
}

.flip-button{
  position: absolute;
  right: 0;
  bottom: 30px;
  font-size: 30px;
  cursor: pointer;
  transition: 1s;
  perspective: 1000px;
}

.flip-button:hover{
  transform: rotateY(180deg);
}

reference:
https://davidwalsh.name/css-flip
https://alligator.io/js/classlist/
https://reactjs.org/docs/refs-and-the-dom.html
http://chuanshuoge2.blogspot.com/2019/06/django-45-react-flippy-card-with-image.html


No comments:

Post a Comment