mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-04 20:33:12 -05:00
121 lines
3.3 KiB
JavaScript
121 lines
3.3 KiB
JavaScript
|
import React from 'react'
|
||
|
import PropTypes from 'prop-types'
|
||
|
import { useTranslation } from 'react-i18next'
|
||
|
import { Dropdown, MenuItem, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||
|
import Icon from '../../../shared/components/icon'
|
||
|
import ColorManager from '../../../ide/colors/ColorManager'
|
||
|
|
||
|
function OnlineUsersWidget({ onlineUsers, goToUser }) {
|
||
|
const { t } = useTranslation()
|
||
|
|
||
|
const shouldDisplayDropdown = onlineUsers.length >= 4
|
||
|
|
||
|
if (shouldDisplayDropdown) {
|
||
|
return (
|
||
|
<Dropdown id="online-users" className="online-users" pullRight>
|
||
|
<DropDownToggleButton
|
||
|
bsRole="toggle"
|
||
|
onlineUserCount={onlineUsers.length}
|
||
|
/>
|
||
|
<Dropdown.Menu>
|
||
|
<MenuItem header>{t('connected_users')}</MenuItem>
|
||
|
{onlineUsers.map(user => (
|
||
|
<MenuItem
|
||
|
as="button"
|
||
|
key={user.user_id}
|
||
|
eventKey={user}
|
||
|
onSelect={goToUser}
|
||
|
>
|
||
|
<UserIcon user={user} onClick={goToUser} showName />
|
||
|
</MenuItem>
|
||
|
))}
|
||
|
</Dropdown.Menu>
|
||
|
</Dropdown>
|
||
|
)
|
||
|
} else {
|
||
|
return (
|
||
|
<div className="online-users">
|
||
|
{onlineUsers.map(user => (
|
||
|
<OverlayTrigger
|
||
|
key={user.user_id}
|
||
|
placement="bottom"
|
||
|
trigger={['hover', 'focus']}
|
||
|
overlay={<Tooltip id="tooltip-online-user">{user.name}</Tooltip>}
|
||
|
>
|
||
|
<span>
|
||
|
{/* OverlayTrigger won't fire unless UserIcon is wrapped in a span */}
|
||
|
<UserIcon user={user} onClick={goToUser} />
|
||
|
</span>
|
||
|
</OverlayTrigger>
|
||
|
))}
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OnlineUsersWidget.propTypes = {
|
||
|
onlineUsers: PropTypes.arrayOf(
|
||
|
PropTypes.shape({
|
||
|
user_id: PropTypes.string.isRequired,
|
||
|
name: PropTypes.string.isRequired
|
||
|
})
|
||
|
).isRequired,
|
||
|
goToUser: PropTypes.func.isRequired
|
||
|
}
|
||
|
|
||
|
function UserIcon({ user, showName, onClick }) {
|
||
|
const backgroundColor = `hsl(${ColorManager.getHueForUserId(
|
||
|
user.user_id
|
||
|
)}, 70%, 50%)`
|
||
|
|
||
|
function handleOnClick() {
|
||
|
onClick(user)
|
||
|
}
|
||
|
|
||
|
return (
|
||
|
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
||
|
<span onClick={handleOnClick}>
|
||
|
<span className="online-user" style={{ backgroundColor }}>
|
||
|
{user.name.slice(0, 1)}
|
||
|
</span>
|
||
|
{showName && user.name}
|
||
|
</span>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
UserIcon.propTypes = {
|
||
|
user: PropTypes.shape({
|
||
|
user_id: PropTypes.string.isRequired,
|
||
|
name: PropTypes.string.isRequired
|
||
|
}),
|
||
|
showName: PropTypes.bool,
|
||
|
onClick: PropTypes.func.isRequired
|
||
|
}
|
||
|
|
||
|
const DropDownToggleButton = React.forwardRef((props, ref) => {
|
||
|
const { t } = useTranslation()
|
||
|
return (
|
||
|
<OverlayTrigger
|
||
|
placement="left"
|
||
|
overlay={
|
||
|
<Tooltip id="tooltip-connected-users">{t('connected_users')}</Tooltip>
|
||
|
}
|
||
|
>
|
||
|
<button
|
||
|
className="btn online-user online-user-multi"
|
||
|
onClick={props.onClick} // required by Bootstrap Dropdown to trigger an opening
|
||
|
>
|
||
|
<strong>{props.onlineUserCount}</strong>
|
||
|
<Icon type="users" modifier="fw" />
|
||
|
</button>
|
||
|
</OverlayTrigger>
|
||
|
)
|
||
|
})
|
||
|
|
||
|
DropDownToggleButton.propTypes = {
|
||
|
onlineUserCount: PropTypes.number.isRequired,
|
||
|
onClick: PropTypes.func
|
||
|
}
|
||
|
|
||
|
export default OnlineUsersWidget
|