tahnik/devRantron

View on GitHub
app/src/js/components/item/bottom_bar.js

Summary

Maintainability
B
4 hrs
Test Coverage
/**
 * Reusable bottom bar for all the item cards.
 * Controls upvotes and downvotes
 */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { ITEM } from '../../consts/types';

class BottomBar extends Component {
  constructor() {
    super();
    this.state = {
      isVoted: 0,
      score: 0,
      triggerActive: false,
      favorited: false,
      subscribed: false,
      plusHover: false,
      minusHover: false,
    };
  }
  componentWillMount() {
    const { isUser, item } = this.props;
    let nextIsUpvoted = item.vote_state;
    let favorited = false;
    if (item.favorited) {
      favorited = true;
    }
    if (isUser) {
      nextIsUpvoted = 0;
    }
    this.setState({
      isVoted: nextIsUpvoted,
      score: item.score,
      favorited,
    });
  }
  onFavorite() {
    const favorited = !this.state.favorited;
    this.setState({ favorited });
    this.props.onFavorite(favorited);
  }
  onSubscribe() {
    const subscribed = !this.state.subscribed;
    this.setState({ subscribed });
    this.props.onSubscribe(subscribed);
  }
  vote(state) {
    if (this.props.isUser) {
      return;
    }
    const { isVoted } = this.state;
    const { item } = this.props;
    let nextScore = this.state.score;
    let nextIsVoted = 0;
    if (isVoted === state) {
      nextScore -= isVoted;
    } else if (isVoted !== 0) {
      nextScore -= (2 * isVoted);
      nextIsVoted = state;
    } else {
      nextScore += state;
      nextIsVoted = state;
    }
    const { vote, type } = this.props;
    if (type) {
      vote(nextIsVoted, item.id, type);
    } else {
      vote(nextIsVoted, item.id);
    }
    this.setState({ isVoted: nextIsVoted, score: nextScore });
  }
  getAddMention() {
    const { addMention, username } = this.props;
    if (typeof addMention !== 'undefined') {
      return (
        <div
          className="addMention"
          onClick={() => addMention(`@${username}`)}
        >
          <p><i className="ion-reply" /></p>
        </div>
      );
    }
    return <div />;
  }
  togglePlusHover() {
    this.setState({ plusHover: !this.state.plusHover });
  }
  toggleMinusHover() {
    this.setState({ minusHover: !this.state.minusHover });
  }
  render() {
    const {
      type, item, onDelete, theme,
    } = this.props;
    const { favorited } = this.state;
    const disabled = this.props.isUser ? 'disabled' : '';
    const backgroundColor = type === ITEM.COMMENT.NAME ?
      theme.comment_card.backgroundColor : theme.item_card.backgroundColor;
    const color = type === ITEM.COMMENT.NAME ?
      theme.comment_card.color : theme.item_card.color;
    const voteColor = theme.plus_notif ? theme.plus_notif.backgroundColor : '#C14857';
    let plusColor = theme.id === 'dark_theme' ? '#ffffff' : theme.item_card.color;
    let minusColor = theme.id === 'dark_theme' ? '#ffffff' : theme.item_card.color;
    if (this.state.isVoted > 0) {
      plusColor = theme.id === 'dark_theme' ? '#ffffff' : theme.item_card.backgroundColor;
    } else if (this.state.isVoted < 0) {
      minusColor = theme.id === 'dark_theme' ? '#ffffff' : theme.item_card.backgroundColor;
    }
    return (
      <div
        className="bottom_bar_container"
        style={{ backgroundColor, color }}
      >
        <div className="left_items">
          <div
            className={`upvote ${disabled} ${this.state.isVoted > 0 ? 'upvoted' : ''}`}
            disabled={disabled}
            style={{
              backgroundColor: this.state.plusHover ? theme.backgroundColor : '',
              color: plusColor,
            }}
            onMouseEnter={() => { this.togglePlusHover(); }}
            onMouseLeave={() => { this.togglePlusHover(); }}
            onClick={() => this.vote(1)}
          >
            <div
              style={{ backgroundColor: voteColor }}
              className={`before ${this.state.isVoted > 0 ? 'votebefore' : ''}`}
            />
            <span className="ud_icon">+</span>
            <span className="ud_icon">+</span>
            <div
              style={{ borderColor: this.state.isVoted > 0 ? `${voteColor}` : 'rgba(0,0,0,0)' }}
              className={`${this.state.isVoted > 0 ? 'voteafter' : ''} after`}
            />
          </div>
          <div className="score" >
            <span>{ this.state.score }</span>
          </div>
          <div
            onClick={() => this.vote(-1)}
            disabled={disabled}
            className={`downvote ${disabled} ${this.state.isVoted < 0 ? 'downvoted' : ''}`}
            style={{
              backgroundColor: this.state.minusHover ? theme.backgroundColor : '',
              color: minusColor,
            }}
            onMouseEnter={() => { this.toggleMinusHover(); }}
            onMouseLeave={() => { this.toggleMinusHover(); }}
          >
            <div
              style={{ backgroundColor: voteColor }}
              className={`before ${this.state.isVoted < 0 ? 'votebefore' : ''}`}
            />
            <span className="ud_icon">-</span>
            <span className="ud_icon">-</span>
            <div
              style={{ borderColor: this.state.isVoted < 0 ? `${voteColor}` : 'rgba(0,0,0,0)' }}
              className={`${this.state.isVoted < 0 ? 'voteafter' : ''} after`}
            />
          </div>
        </div>
        <div
          className="right_items"
          onMouseLeave={() => this.setState({ triggerActive: false })}
        >
          <div className="togglable">
            <div
              className={`trigger ${this.state.triggerActive ? 'active' : ''}`}
              onClick={() => this.setState({ triggerActive: true })}
              onMouseEnter={() => this.setState({ triggerActive: true })}
            >
              <p><i className="ion-android-more-horizontal" /></p>
            </div>
            <div
              className={`toggle_items ${this.state.triggerActive ? 'active' : ''}`}
              onMouseLeave={() => this.setState({ triggerActive: false })}
            >
              { this.props.isUser ?
                <div
                  className="toggle_item delete"
                  onClick={() => onDelete()}
                >
                  <p><i className="ion-android-delete" /></p>
                </div>
                : null
              }
              {/* {
                !this.props.isUser ?
                  <div
                    className={`toggle_item subscribe ${subscribed ? 'active' : null}`}
                    onClick={() => this.onSubscribe()}
                  >
                    <p><i className="ion-social-rss-outline" /></p>
                  </div>
                  : null
              } */}
              { !item.rant_id && !item.c_type ?
                <div
                  className={`toggle_item favorite ${favorited ? 'active' : null}`}
                  onClick={() => this.onFavorite()}
                >
                  <p><i className="ion-android-favorite-outline" /></p>
                </div>
                : null
              }
              { !item.rant_id ?
                <div
                  className="toggle_item link"
                  onClick={() => this.props.copyToClip()}
                >
                  <p><i className="ion-link" /></p>
                </div>
                : null
              }
              { this.props.isUser && this.props.editable ?
                <div
                  className="toggle_item edit"
                  onClick={() => this.props.onEdit()}
                >
                  <p><i className="ion-android-create" /></p>
                </div>
                : null
              }
            </div>
          </div>
          {
            type === ITEM.COMMENT.NAME ?
              null :
              <div className="comments" onClick={() => this.props.onCommentsClick()} >
                <p><i className="ion-ios-chatboxes-outline" /></p>
                <span>{ item.num_comments }</span>
              </div>
          }
          {
            this.getAddMention()
          }
        </div>
      </div>
    );
  }
}


BottomBar.propTypes = {
  isUser: PropTypes.bool.isRequired,
  editable: PropTypes.bool.isRequired,
  vote: PropTypes.func.isRequired,
  onEdit: PropTypes.func.isRequired,
  onDelete: PropTypes.func.isRequired,
  type: PropTypes.string,
  addMention: PropTypes.func,
  username: PropTypes.string.isRequired,
  onCommentsClick: PropTypes.func,
  copyToClip: PropTypes.func.isRequired,
  item: PropTypes.object.isRequired,
  theme: PropTypes.object.isRequired,
  onFavorite: PropTypes.func.isRequired,
  onSubscribe: PropTypes.func.isRequired,
};

export default BottomBar;