Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React from 'react';
- import PropTypes from 'prop-types';
- import styled, { css } from 'styled-components';
- import isEqual from 'lodash/isEqual';
- import pick from 'lodash/pick';
- import Star from 'ui/atoms/star/Star';
- import RatesInfos from 'ui/atoms/rates-infos/RatesInfos';
- import Tick from 'ui/atoms/tick/Tick';
- const clickable = css`
- &:hover {
- .average { display: none; }
- .user { display: block; }
- }
- `;
- const StarsWrapper = styled.div`
- display: flex;
- `;
- const UserVotedTick = styled(Tick)`
- transition: opacity .5s;
- position: absolute;
- top: 9px;
- left: 2px;
- will-change: opacity;
- opacity: ${({ show }) => Number(show)};
- img{
- width: 18px;
- }
- `;
- const RateInfo = styled(RatesInfos)`
- transition: opacity .5s;
- will-change: opacity;
- margin-top: 8px;
- opacity: ${({ show }) => Number(show)};
- `;
- const RightBloc = styled.div`
- margin-left: 10px;
- position: relative;
- `;
- const LeftBloc = styled.div`
- &.user {
- display: none;
- }
- `;
- const RatingWrapper = styled.div`
- display: flex;
- padding: 10px;
- `;
- const P = styled.p`
- text-align: center;
- font-size: 0.9em;
- margin: 0px;
- color: ${({ hasVoted }) => hasVoted ? '#3498db' : '#707070'};
- span{
- color: #3498db;
- font-size: 0.8em;
- }
- `;
- const Div = styled.div`
- display: inline-flex;
- color: #b2b2b2;
- font-size: 0.9em;
- ${({ onVoted }) => onVoted ? clickable : ''}
- `;
- class RatingStars extends React.Component {
- static displayName = 'Rating Stars';
- static propTypes = {
- note: PropTypes.number.isRequired,
- average: PropTypes.number.isRequired,
- votesCount: PropTypes.number.isRequired,
- onVoted: PropTypes.func,
- starClass: PropTypes.string,
- // Translations
- myNoteIs: PropTypes.string.isRequired,
- firstToVote: PropTypes.string.isRequired,
- evaluateTheStartup: PropTypes.string.isRequired
- }
- constructor(props) {
- super(props);
- this.state = {
- userRate: props.note || 0,
- hasvoted: false,
- finalUserRate: props.note || 0
- };
- }
- componentWillReceiveProps(nextProps) {
- this.setUserRate(nextProps.note);
- }
- componentDidUpdate() {
- if(this.state.hasvoted && !this.tickTimer) {
- this.tickTimer = setTimeout(() => {
- this.state.hasvoted && this.setState({ hasvoted: false });
- this.tickTimer = null;
- }, 900);
- }
- }
- setUserRate(userRate) {
- this.state.userRate !== userRate && this.setState({ userRate });
- }
- handleMouseLeave = () => {
- this.setState({userRate: this.state.finalUserRate});
- this.calcUserStars(this.props.note);
- }
- handleMouseEnterStar = (userRate) => {
- this.setUserRate(userRate);
- this.calcUserStars(this.props.note);
- }
- handleClickStar = (e, userRate) => {
- const { onVoted } = this.props;
- e.stopPropagation();
- onVoted && onVoted(userRate);
- const newState = {
- hasvoted: true,
- userRate,
- finalUserRate: userRate,
- note: userRate
- };
- const oldState = pick(this.state, ['hasvoted', 'userRate', 'finalUserRate', 'note']);
- if(!isEqual(newState, oldState)) {
- this.setState(newState);
- }
- }
- calcStars = (average) => {
- const fullStars = Math.trunc(average);
- const hasHalfStar = (average - fullStars) >= 0.5;
- return Array.from(Array(5), (val, i) => {
- const value = i + 1;
- let color;
- if(value <= fullStars) {
- color = 'yellow';
- } else if(hasHalfStar && value === (fullStars + 1)) {
- color = 'half';
- } else {
- color = 'grey';
- }
- return { value, color };
- });
- }
- calcUserStars = (rate) => {
- return Array.from(Array(5), (val, i) => {
- const value = i + 1;
- const color = value <= rate ? 'blue' : 'greyOmbre';
- return {
- value,
- color,
- onMouseEnter: () => this.handleMouseEnterStar(value),
- onMouseLeave: () => this.handleMouseLeave(value),
- onClick: (e) => this.handleClickStar(e, value)
- };
- });
- }
- render() {
- const { userRate, hasvoted } = this.state;
- const { average, onVoted, starClass } = this.props;
- const hasVotes = this.props.votesCount !== 0;
- const Stars = this.calcStars(average).map((props) => <Star className={starClass} key={props.value} {...props} />);
- let Info;
- if(hasVotes) {
- Info = userRate >= 0 && this.props.note
- ? (<P hasVoted>{this.props.myNoteIs} {this.props.note}/5</P>)
- : <P>{this.props.evaluateTheStartup}</P>;
- } else {
- Info = (<P className='ratingInfos'>{this.props.firstToVote}</P>);
- }
- const UserStars = this.calcUserStars(userRate).map((props) => <Star className={starClass} key={props.value} {...props} />);
- return (
- <Div onVoted={onVoted}>
- <RatingWrapper>
- <LeftBloc className='average'>
- <StarsWrapper>
- {Stars}
- </StarsWrapper>
- {Info}
- </LeftBloc>
- <LeftBloc className='user'>
- <StarsWrapper>
- {UserStars}
- </StarsWrapper>
- <P hasVoted>{this.props.myNoteIs} {userRate}/5</P>
- </LeftBloc>
- <RightBloc>
- <RateInfo
- average={this.props.average}
- votesCount={this.props.votesCount}
- show={!hasvoted}
- />
- <UserVotedTick show={hasvoted} />
- </RightBloc>
- </RatingWrapper>
- </Div>
- );
- }
- }
- export default RatingStars;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement