// @flow import * as React from "react"; import { observer, inject } from "mobx-react"; import { sortBy, keyBy } from "lodash"; import { MAX_AVATAR_DISPLAY } from "shared/constants"; import { AvatarWithPresence } from "components/Avatar"; import Facepile from "components/Facepile"; import Document from "models/Document"; import ViewsStore from "stores/ViewsStore"; import DocumentPresenceStore from "stores/DocumentPresenceStore"; type Props = { views: ViewsStore, presence: DocumentPresenceStore, document: Document, currentUserId: string, }; @observer class Collaborators extends React.Component { componentDidMount() { this.props.views.fetchPage({ documentId: this.props.document.id }); } render() { const { document, presence, views, currentUserId } = this.props; let documentPresence = presence.get(document.id); documentPresence = documentPresence ? Array.from(documentPresence.values()) : []; const documentViews = views.inDocument(document.id); const presentIds = documentPresence.map((p) => p.userId); const editingIds = documentPresence .filter((p) => p.isEditing) .map((p) => p.userId); // ensure currently present via websocket are always ordered first const mostRecentViewers = sortBy( documentViews.slice(0, MAX_AVATAR_DISPLAY), (view) => { return presentIds.includes(view.user.id); } ); const viewersKeyedByUserId = keyBy(mostRecentViewers, (v) => v.user.id); const overflow = documentViews.length - mostRecentViewers.length; return ( v.user)} overflow={overflow} renderAvatar={(user) => { const isPresent = presentIds.includes(user.id); const isEditing = editingIds.includes(user.id); const { lastViewedAt } = viewersKeyedByUserId[user.id]; return ( ); }} /> ); } } export default inject("views", "presence")(Collaborators);