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 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import React, { useCallback } from 'react';
  2. import { FlatList, Text, TextStyle, View, ViewStyle } from 'react-native';
  3. import Button from '../../../base/ui/components/native/Button';
  4. import { BUTTON_TYPES } from '../../../base/ui/constants.native';
  5. import AbstractPollResults from '../AbstractPollResults';
  6. import type { AbstractProps, AnswerInfo } from '../AbstractPollResults';
  7. import { dialogStyles, pollsStyles, resultsStyles } from './styles';
  8. /**
  9. * Component that renders the poll results.
  10. *
  11. * @param {Props} props - The passed props.
  12. * @returns {React.Node}
  13. */
  14. const PollResults = (props: AbstractProps) => {
  15. const {
  16. answers,
  17. changeVote,
  18. creatorName,
  19. haveVoted,
  20. question,
  21. showDetails,
  22. t,
  23. toggleIsDetailed
  24. } = props;
  25. /**
  26. * Render a header summing up answer information.
  27. *
  28. * @param {string} answer - The name of the answer.
  29. * @param {number} percentage - The percentage of voters.
  30. * @param {number} nbVotes - The number of collected votes.
  31. * @returns {React.Node}
  32. */
  33. const renderHeader = (answer: string, percentage: number, nbVotes: number) => (
  34. <View style = { resultsStyles.answerHeader as ViewStyle }>
  35. <Text style = { resultsStyles.answer as TextStyle }>{ answer }</Text>
  36. <View>
  37. <Text style = { resultsStyles.answer as TextStyle }>({nbVotes}) {percentage}%</Text>
  38. </View>
  39. </View>
  40. );
  41. /**
  42. * Render voters of and answer.
  43. *
  44. * @param {AnswerInfo} answer - The answer info.
  45. * @returns {React.Node}
  46. */
  47. const renderRow = useCallback((answer: AnswerInfo) => {
  48. const { name, percentage, voters, voterCount } = answer;
  49. if (showDetails) {
  50. return (
  51. <View style = { resultsStyles.answerContainer as ViewStyle }>
  52. { renderHeader(name, percentage, voterCount) }
  53. <View style = { resultsStyles.barContainer as ViewStyle }>
  54. <View style = { [ resultsStyles.bar, { width: `${percentage}%` } ] as ViewStyle[] } />
  55. </View>
  56. { voters && voterCount > 0
  57. && <View style = { resultsStyles.voters as ViewStyle }>
  58. {/* @ts-ignore */}
  59. {voters.map(({ id, name: voterName }) =>
  60. (<Text
  61. key = { id }
  62. style = { resultsStyles.voter as TextStyle }>
  63. { voterName }
  64. </Text>)
  65. )}
  66. </View>}
  67. </View>
  68. );
  69. }
  70. // else, we display a simple list
  71. // We add a progress bar by creating an empty view of width equal to percentage.
  72. return (
  73. <View style = { resultsStyles.answerContainer as ViewStyle }>
  74. { renderHeader(answer.name, percentage, voterCount) }
  75. <View style = { resultsStyles.barContainer as ViewStyle }>
  76. <View style = { [ resultsStyles.bar, { width: `${percentage}%` } ] as ViewStyle[] } />
  77. </View>
  78. </View>
  79. );
  80. }, [ showDetails ]);
  81. /* eslint-disable react/jsx-no-bind */
  82. return (
  83. <View>
  84. <Text style = { dialogStyles.questionText as TextStyle } >{ question }</Text>
  85. <Text style = { dialogStyles.questionOwnerText as TextStyle } >
  86. { t('polls.by', { name: creatorName }) }
  87. </Text>
  88. <FlatList
  89. data = { answers }
  90. keyExtractor = { (item, index) => index.toString() }
  91. renderItem = { answer => renderRow(answer.item) } />
  92. <View style = { pollsStyles.bottomLinks as ViewStyle }>
  93. <Button
  94. labelKey = {
  95. showDetails
  96. ? 'polls.results.hideDetailedResults'
  97. : 'polls.results.showDetailedResults'
  98. }
  99. labelStyle = { pollsStyles.toggleText }
  100. onClick = { toggleIsDetailed }
  101. type = { BUTTON_TYPES.TERTIARY } />
  102. <Button
  103. labelKey = {
  104. haveVoted
  105. ? 'polls.results.changeVote'
  106. : 'polls.results.vote'
  107. }
  108. labelStyle = { pollsStyles.toggleText }
  109. onClick = { changeVote }
  110. type = { BUTTON_TYPES.TERTIARY } />
  111. </View>
  112. </View>
  113. );
  114. };
  115. /*
  116. * We apply AbstractPollResults to fill in the AbstractProps common
  117. * to both the web and native implementations.
  118. */
  119. // eslint-disable-next-line new-cap
  120. export default AbstractPollResults(PollResults);