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

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