online-users-widget.js 3.3 KB

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