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 ColorManager from '../../../ide/colors/ColorManager'
  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(${ColorManager.getHueForUserId(
  63. user.user_id
  64. )}, 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. <OverlayTrigger
  90. placement="left"
  91. overlay={
  92. <Tooltip id="tooltip-connected-users">{t('connected_users')}</Tooltip>
  93. }
  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" modifier="fw" />
  101. </button>
  102. </OverlayTrigger>
  103. )
  104. })
  105. DropDownToggleButton.propTypes = {
  106. onlineUserCount: PropTypes.number.isRequired,
  107. onClick: PropTypes.func
  108. }
  109. export default OnlineUsersWidget