online-users-widget.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import React from 'react'
  2. import PropTypes from 'prop-types'
  3. import { useTranslation } from 'react-i18next'
  4. import { Dropdown, MenuItem } from 'react-bootstrap'
  5. import Tooltip from '../../../shared/components/tooltip'
  6. import Icon from '../../../shared/components/icon'
  7. import { getHueForUserId } from '../../../shared/utils/colors'
  8. import ControlledDropdown from '../../../shared/components/controlled-dropdown'
  9. function OnlineUsersWidget({ onlineUsers, goToUser }) {
  10. const { t } = useTranslation()
  11. const shouldDisplayDropdown = onlineUsers.length >= 4
  12. if (shouldDisplayDropdown) {
  13. return (
  14. <ControlledDropdown id="online-users" className="online-users" pullRight>
  15. <DropDownToggleButton
  16. bsRole="toggle"
  17. onlineUserCount={onlineUsers.length}
  18. />
  19. <Dropdown.Menu>
  20. <MenuItem header>{t('connected_users')}</MenuItem>
  21. {onlineUsers.map((user, index) => (
  22. <MenuItem
  23. as="button"
  24. key={`${user.user_id}_${index}`}
  25. eventKey={user}
  26. onSelect={goToUser}
  27. >
  28. <UserIcon user={user} onClick={goToUser} showName />
  29. </MenuItem>
  30. ))}
  31. </Dropdown.Menu>
  32. </ControlledDropdown>
  33. )
  34. } else {
  35. return (
  36. <div className="online-users">
  37. {onlineUsers.map((user, index) => (
  38. <Tooltip
  39. key={`${user.user_id}_${index}`}
  40. id="online-user"
  41. description={user.name}
  42. overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }}
  43. >
  44. <span>
  45. {/* OverlayTrigger won't fire unless UserIcon is wrapped in a span */}
  46. <UserIcon user={user} onClick={goToUser} />
  47. </span>
  48. </Tooltip>
  49. ))}
  50. </div>
  51. )
  52. }
  53. }
  54. OnlineUsersWidget.propTypes = {
  55. onlineUsers: PropTypes.arrayOf(
  56. PropTypes.shape({
  57. user_id: PropTypes.string.isRequired,
  58. name: PropTypes.string.isRequired,
  59. })
  60. ).isRequired,
  61. goToUser: PropTypes.func.isRequired,
  62. }
  63. function UserIcon({ user, showName, onClick }) {
  64. const backgroundColor = `hsl(${getHueForUserId(user.user_id)}, 70%, 50%)`
  65. function handleOnClick() {
  66. onClick(user)
  67. }
  68. const [character] = [...user.name]
  69. return (
  70. // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
  71. <span onClick={handleOnClick}>
  72. <span className="online-user" style={{ backgroundColor }}>
  73. {character}
  74. </span>
  75. {showName && user.name}
  76. </span>
  77. )
  78. }
  79. UserIcon.propTypes = {
  80. user: PropTypes.shape({
  81. user_id: PropTypes.string.isRequired,
  82. name: PropTypes.string.isRequired,
  83. }),
  84. showName: PropTypes.bool,
  85. onClick: PropTypes.func.isRequired,
  86. }
  87. const DropDownToggleButton = React.forwardRef((props, ref) => {
  88. const { t } = useTranslation()
  89. return (
  90. <Tooltip
  91. id="connected-users"
  92. description={t('connected_users')}
  93. overlayProps={{ placement: 'left' }}
  94. >
  95. <button
  96. className="btn online-user online-user-multi"
  97. onClick={props.onClick} // required by Bootstrap Dropdown to trigger an opening
  98. >
  99. <strong>{props.onlineUserCount}</strong>
  100. <Icon type="users" fw />
  101. </button>
  102. </Tooltip>
  103. )
  104. })
  105. DropDownToggleButton.displayName = 'DropDownToggleButton'
  106. DropDownToggleButton.propTypes = {
  107. onlineUserCount: PropTypes.number.isRequired,
  108. onClick: PropTypes.func,
  109. }
  110. export default OnlineUsersWidget