This repository has been archived on 2022-08-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
outline/app/scenes/Document/components/SocketPresence.js
Tom Moor 146e4da73b feat: Document presence indicator (#1114)
* Update websockets to allow joining document-based rooms

* dynamic websocket joining

* emit user.join/leave events when entering and exiting document rooms

* presence storage

* feat: frontend presence store

* lint

* UI updates

* First pass editing state

* refactoring

* Timeout per user/doc
lint

* Document data loading refactor to keep Socket mounted

* restore: Mark as viewed functionality
Add display of 'you' to collaborators

* fix: Socket/document remount when document slug changes due to title change

* Revert unneccessary package update

* Move editing ping interval to a shared constant

* fix: Flash of sidebar when loading page directly on editing mode

* separate document and revision loading

* add comments for socket events

* fix: Socket events getting bound multiple times on reconnect

* fix: Clear client side presence state on disconnect

* fix: Don't ignore server side error
Improved documentation

* More comments / why comments

* rename Socket -> SocketPresence

* fix: Handle redis is down
remove unneccessary join

* fix: PR feedback
2020-01-02 21:17:59 -08:00

78 lines
1.7 KiB
JavaScript

// @flow
import * as React from 'react';
import { SocketContext } from 'components/SocketProvider';
import { USER_PRESENCE_INTERVAL } from 'shared/constants';
type Props = {
children?: React.Node,
documentId: string,
isEditing: boolean,
};
export default class SocketPresence extends React.Component<Props> {
static contextType = SocketContext;
previousContext: any;
editingInterval: IntervalID;
componentDidMount() {
this.editingInterval = setInterval(() => {
if (this.props.isEditing) {
this.emitPresence();
}
}, USER_PRESENCE_INTERVAL);
this.setupOnce();
}
componentDidUpdate(prevProps: Props) {
this.setupOnce();
if (prevProps.isEditing !== this.props.isEditing) {
this.emitPresence();
}
}
componentWillUnmount() {
if (this.context) {
this.context.emit('leave', { documentId: this.props.documentId });
this.context.off('authenticated', this.emitJoin);
}
clearInterval(this.editingInterval);
}
setupOnce = () => {
if (this.context && !this.previousContext) {
this.previousContext = this.context;
if (this.context.authenticated) {
this.emitJoin();
}
this.context.on('authenticated', () => {
this.emitJoin();
});
}
};
emitJoin = () => {
if (!this.context) return;
this.context.emit('join', {
documentId: this.props.documentId,
isEditing: this.props.isEditing,
});
};
emitPresence = () => {
if (!this.context) return;
this.context.emit('presence', {
documentId: this.props.documentId,
isEditing: this.props.isEditing,
});
};
render() {
return this.props.children || null;
}
}