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