online-users-widget.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. return (
  69. // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
  70. <span onClick={handleOnClick}>
  71. <span className="online-user" style={{ backgroundColor }}>
  72. {user.name.slice(0, 1)}
  73. </span>
  74. {showName && user.name}
  75. </span>
  76. )
  77. }
  78. UserIcon.propTypes = {
  79. user: PropTypes.shape({
  80. user_id: PropTypes.string.isRequired,
  81. name: PropTypes.string.isRequired,
  82. }),
  83. showName: PropTypes.bool,
  84. onClick: PropTypes.func.isRequired,
  85. }
  86. const DropDownToggleButton = React.forwardRef((props, ref) => {
  87. const { t } = useTranslation()
  88. return (
  89. <Tooltip
  90. id="connected-users"
  91. description={t('connected_users')}
  92. overlayProps={{ placement: 'left' }}
  93. >
  94. <button
  95. className="btn online-user online-user-multi"
  96. onClick={props.onClick} // required by Bootstrap Dropdown to trigger an opening
  97. >
  98. <strong>{props.onlineUserCount}</strong>
  99. <Icon type="users" fw />
  100. </button>
  101. </Tooltip>
  102. )
  103. })
  104. DropDownToggleButton.displayName = 'DropDownToggleButton'
  105. DropDownToggleButton.propTypes = {
  106. onlineUserCount: PropTypes.number.isRequired,
  107. onClick: PropTypes.func,
  108. }
  109. export default OnlineUsersWidget