You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PollResults.tsx 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import React from 'react';
  2. import { makeStyles } from 'tss-react/mui';
  3. import { withPixelLineHeight } from '../../../base/styles/functions.web';
  4. import AbstractPollResults, { AbstractProps } from '../AbstractPollResults';
  5. const useStyles = makeStyles()(theme => {
  6. return {
  7. container: {
  8. margin: '24px',
  9. padding: '16px',
  10. backgroundColor: theme.palette.ui02,
  11. borderRadius: '8px'
  12. },
  13. header: {
  14. marginBottom: '16px'
  15. },
  16. question: {
  17. ...withPixelLineHeight(theme.typography.heading6),
  18. color: theme.palette.text01,
  19. marginBottom: '8px'
  20. },
  21. creator: {
  22. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  23. color: theme.palette.text02
  24. },
  25. resultList: {
  26. listStyleType: 'none',
  27. margin: 0,
  28. padding: 0,
  29. '& li': {
  30. marginBottom: '16px'
  31. }
  32. },
  33. answerName: {
  34. display: 'flex',
  35. flexShrink: 1,
  36. overflowWrap: 'anywhere',
  37. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  38. color: theme.palette.text01,
  39. marginBottom: '4px'
  40. },
  41. answerResultContainer: {
  42. display: 'flex',
  43. justifyContent: 'space-between',
  44. alignItems: 'center',
  45. minWidth: '10em'
  46. },
  47. barContainer: {
  48. backgroundColor: theme.palette.ui03,
  49. borderRadius: '4px',
  50. height: '6px',
  51. maxWidth: '160px',
  52. width: '158px',
  53. flexGrow: 1,
  54. marginTop: '2px'
  55. },
  56. bar: {
  57. height: '6px',
  58. borderRadius: '4px',
  59. backgroundColor: theme.palette.action01
  60. },
  61. voteCount: {
  62. flex: 1,
  63. textAlign: 'right',
  64. ...withPixelLineHeight(theme.typography.bodyShortBold),
  65. color: theme.palette.text01
  66. },
  67. voters: {
  68. margin: 0,
  69. marginTop: '4px',
  70. listStyleType: 'none',
  71. display: 'flex',
  72. flexDirection: 'column',
  73. backgroundColor: theme.palette.ui03,
  74. borderRadius: theme.shape.borderRadius,
  75. padding: '8px 16px',
  76. '& li': {
  77. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  78. color: theme.palette.text01,
  79. margin: 0,
  80. marginBottom: '2px',
  81. '&:last-of-type': {
  82. marginBottom: 0
  83. }
  84. }
  85. },
  86. buttonsContainer: {
  87. display: 'flex',
  88. justifyContent: 'space-between',
  89. '& button': {
  90. border: 0,
  91. backgroundColor: 'transparent',
  92. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  93. color: theme.palette.link01
  94. }
  95. }
  96. };
  97. });
  98. /**
  99. * Component that renders the poll results.
  100. *
  101. * @param {Props} props - The passed props.
  102. * @returns {React.Node}
  103. */
  104. const PollResults = ({
  105. answers,
  106. changeVote,
  107. creatorName,
  108. haveVoted,
  109. showDetails,
  110. question,
  111. t,
  112. toggleIsDetailed
  113. }: AbstractProps) => {
  114. const { classes } = useStyles();
  115. return (
  116. <div className = { classes.container }>
  117. <div className = { classes.header }>
  118. <div className = { classes.question }>
  119. {question}
  120. </div>
  121. <div className = { classes.creator }>
  122. {t('polls.by', { name: creatorName })}
  123. </div>
  124. </div>
  125. <ul className = { classes.resultList }>
  126. {answers.map(({ name, percentage, voters, voterCount }, index) =>
  127. (<li key = { index }>
  128. <div className = { classes.answerName }>
  129. {name}
  130. </div>
  131. <div className = { classes.answerResultContainer }>
  132. <span className = { classes.barContainer }>
  133. <div
  134. className = { classes.bar }
  135. style = {{ width: `${percentage}%` }} />
  136. </span>
  137. <div className = { classes.voteCount }>
  138. {voterCount}({percentage}%)
  139. </div>
  140. </div>
  141. {showDetails && voters && voterCount > 0
  142. && <ul className = { classes.voters }>
  143. {voters.map(voter =>
  144. <li key = { voter?.id }>{voter?.name}</li>
  145. )}
  146. </ul>}
  147. </li>)
  148. )}
  149. </ul>
  150. <div className = { classes.buttonsContainer }>
  151. <button
  152. onClick = { toggleIsDetailed }>
  153. {showDetails ? t('polls.results.hideDetailedResults') : t('polls.results.showDetailedResults')}
  154. </button>
  155. <button
  156. onClick = { changeVote }>
  157. {haveVoted ? t('polls.results.changeVote') : t('polls.results.vote')}
  158. </button>
  159. </div>
  160. </div>
  161. );
  162. };
  163. /*
  164. * We apply AbstractPollResults to fill in the AbstractProps common
  165. * to both the web and native implementations.
  166. */
  167. // eslint-disable-next-line new-cap
  168. export default AbstractPollResults(PollResults);