Advertisement
Guest User

Untitled

a guest
Nov 24th, 2017
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.81 KB | None | 0 0
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import styled, { css } from 'styled-components';
  4.  
  5. import isEqual from 'lodash/isEqual';
  6. import pick from 'lodash/pick';
  7.  
  8. import Star from 'ui/atoms/star/Star';
  9. import RatesInfos from 'ui/atoms/rates-infos/RatesInfos';
  10. import Tick from 'ui/atoms/tick/Tick';
  11.  
  12. const clickable = css`
  13. &:hover {
  14. .average { display: none; }
  15. .user { display: block; }
  16. }
  17. `;
  18. const StarsWrapper = styled.div`
  19. display: flex;
  20. `;
  21.  
  22. const UserVotedTick = styled(Tick)`
  23. transition: opacity .5s;
  24. position: absolute;
  25. top: 9px;
  26. left: 2px;
  27. will-change: opacity;
  28. opacity: ${({ show }) => Number(show)};
  29. img{
  30. width: 18px;
  31. }
  32. `;
  33.  
  34. const RateInfo = styled(RatesInfos)`
  35. transition: opacity .5s;
  36. will-change: opacity;
  37. margin-top: 8px;
  38. opacity: ${({ show }) => Number(show)};
  39. `;
  40.  
  41. const RightBloc = styled.div`
  42. margin-left: 10px;
  43. position: relative;
  44. `;
  45.  
  46. const LeftBloc = styled.div`
  47. &.user {
  48. display: none;
  49. }
  50. `;
  51.  
  52. const RatingWrapper = styled.div`
  53. display: flex;
  54. padding: 10px;
  55. `;
  56.  
  57. const P = styled.p`
  58. text-align: center;
  59. font-size: 0.9em;
  60. margin: 0px;
  61. color: ${({ hasVoted }) => hasVoted ? '#3498db' : '#707070'};
  62.  
  63. span{
  64. color: #3498db;
  65. font-size: 0.8em;
  66. }
  67. `;
  68.  
  69. const Div = styled.div`
  70. display: inline-flex;
  71. color: #b2b2b2;
  72. font-size: 0.9em;
  73.  
  74. ${({ onVoted }) => onVoted ? clickable : ''}
  75. `;
  76.  
  77. class RatingStars extends React.Component {
  78. static displayName = 'Rating Stars';
  79. static propTypes = {
  80. note: PropTypes.number.isRequired,
  81. average: PropTypes.number.isRequired,
  82. votesCount: PropTypes.number.isRequired,
  83. onVoted: PropTypes.func,
  84. starClass: PropTypes.string,
  85.  
  86. // Translations
  87. myNoteIs: PropTypes.string.isRequired,
  88. firstToVote: PropTypes.string.isRequired,
  89. evaluateTheStartup: PropTypes.string.isRequired
  90. }
  91.  
  92. constructor(props) {
  93. super(props);
  94. this.state = {
  95. userRate: props.note || 0,
  96. hasvoted: false,
  97. finalUserRate: props.note || 0
  98. };
  99. }
  100.  
  101. componentWillReceiveProps(nextProps) {
  102. this.setUserRate(nextProps.note);
  103. }
  104.  
  105. componentDidUpdate() {
  106. if(this.state.hasvoted && !this.tickTimer) {
  107. this.tickTimer = setTimeout(() => {
  108. this.state.hasvoted && this.setState({ hasvoted: false });
  109. this.tickTimer = null;
  110. }, 900);
  111. }
  112. }
  113.  
  114. setUserRate(userRate) {
  115. this.state.userRate !== userRate && this.setState({ userRate });
  116. }
  117.  
  118. handleMouseLeave = () => {
  119. this.setState({userRate: this.state.finalUserRate});
  120. this.calcUserStars(this.props.note);
  121. }
  122.  
  123. handleMouseEnterStar = (userRate) => {
  124. this.setUserRate(userRate);
  125. this.calcUserStars(this.props.note);
  126. }
  127.  
  128. handleClickStar = (e, userRate) => {
  129. const { onVoted } = this.props;
  130.  
  131. e.stopPropagation();
  132.  
  133. onVoted && onVoted(userRate);
  134.  
  135. const newState = {
  136. hasvoted: true,
  137. userRate,
  138. finalUserRate: userRate,
  139. note: userRate
  140. };
  141.  
  142. const oldState = pick(this.state, ['hasvoted', 'userRate', 'finalUserRate', 'note']);
  143.  
  144. if(!isEqual(newState, oldState)) {
  145. this.setState(newState);
  146. }
  147. }
  148.  
  149. calcStars = (average) => {
  150. const fullStars = Math.trunc(average);
  151. const hasHalfStar = (average - fullStars) >= 0.5;
  152.  
  153. return Array.from(Array(5), (val, i) => {
  154. const value = i + 1;
  155. let color;
  156.  
  157. if(value <= fullStars) {
  158. color = 'yellow';
  159. } else if(hasHalfStar && value === (fullStars + 1)) {
  160. color = 'half';
  161. } else {
  162. color = 'grey';
  163. }
  164.  
  165. return { value, color };
  166. });
  167. }
  168.  
  169. calcUserStars = (rate) => {
  170. return Array.from(Array(5), (val, i) => {
  171. const value = i + 1;
  172. const color = value <= rate ? 'blue' : 'greyOmbre';
  173.  
  174. return {
  175. value,
  176. color,
  177. onMouseEnter: () => this.handleMouseEnterStar(value),
  178. onMouseLeave: () => this.handleMouseLeave(value),
  179. onClick: (e) => this.handleClickStar(e, value)
  180. };
  181. });
  182. }
  183.  
  184. render() {
  185. const { userRate, hasvoted } = this.state;
  186. const { average, onVoted, starClass } = this.props;
  187.  
  188. const hasVotes = this.props.votesCount !== 0;
  189.  
  190. const Stars = this.calcStars(average).map((props) => <Star className={starClass} key={props.value} {...props} />);
  191.  
  192. let Info;
  193.  
  194. if(hasVotes) {
  195. Info = userRate >= 0 && this.props.note
  196. ? (<P hasVoted>{this.props.myNoteIs} {this.props.note}/5</P>)
  197. : <P>{this.props.evaluateTheStartup}</P>;
  198. } else {
  199. Info = (<P className='ratingInfos'>{this.props.firstToVote}</P>);
  200. }
  201.  
  202. const UserStars = this.calcUserStars(userRate).map((props) => <Star className={starClass} key={props.value} {...props} />);
  203.  
  204. return (
  205. <Div onVoted={onVoted}>
  206. <RatingWrapper>
  207. <LeftBloc className='average'>
  208. <StarsWrapper>
  209. {Stars}
  210. </StarsWrapper>
  211. {Info}
  212. </LeftBloc>
  213. <LeftBloc className='user'>
  214. <StarsWrapper>
  215. {UserStars}
  216. </StarsWrapper>
  217. <P hasVoted>{this.props.myNoteIs} {userRate}/5</P>
  218. </LeftBloc>
  219. <RightBloc>
  220. <RateInfo
  221. average={this.props.average}
  222. votesCount={this.props.votesCount}
  223. show={!hasvoted}
  224. />
  225.  
  226. <UserVotedTick show={hasvoted} />
  227. </RightBloc>
  228. </RatingWrapper>
  229. </Div>
  230. );
  231. }
  232. }
  233.  
  234. export default RatingStars;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement