frontend > app
This commit is contained in:
41
app/components/DocumentViews/DocumentViewersStore.js
Normal file
41
app/components/DocumentViews/DocumentViewersStore.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// @flow
|
||||
import { observable, action } from 'mobx';
|
||||
import invariant from 'invariant';
|
||||
import { client } from 'utils/ApiClient';
|
||||
import type { User } from 'types';
|
||||
|
||||
type View = {
|
||||
user: User,
|
||||
count: number,
|
||||
};
|
||||
|
||||
class DocumentViewersStore {
|
||||
documentId: string;
|
||||
@observable viewers: Array<View>;
|
||||
@observable isFetching: boolean;
|
||||
|
||||
@action fetchViewers = async () => {
|
||||
this.isFetching = true;
|
||||
|
||||
try {
|
||||
const res = await client.post(
|
||||
'/views.list',
|
||||
{
|
||||
id: this.documentId,
|
||||
},
|
||||
{ cache: true }
|
||||
);
|
||||
invariant(res && res.data, 'Data should be available');
|
||||
this.viewers = res.data.users;
|
||||
} catch (e) {
|
||||
console.error('Something went wrong');
|
||||
}
|
||||
this.isFetching = false;
|
||||
};
|
||||
|
||||
constructor(documentId: string) {
|
||||
this.documentId = documentId;
|
||||
}
|
||||
}
|
||||
|
||||
export default DocumentViewersStore;
|
||||
76
app/components/DocumentViews/DocumentViews.js
Normal file
76
app/components/DocumentViews/DocumentViews.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import Popover from 'components/Popover';
|
||||
import styled from 'styled-components';
|
||||
import DocumentViewers from './components/DocumentViewers';
|
||||
import DocumentViewersStore from './DocumentViewersStore';
|
||||
import Flex from 'components/Flex';
|
||||
|
||||
const Container = styled(Flex)`
|
||||
font-size: 13px;
|
||||
user-select: none;
|
||||
|
||||
a {
|
||||
color: #ccc;
|
||||
|
||||
&:hover {
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
documentId: string,
|
||||
count: number,
|
||||
};
|
||||
|
||||
@observer class DocumentViews extends Component {
|
||||
anchor: HTMLElement;
|
||||
store: DocumentViewersStore;
|
||||
props: Props;
|
||||
state: {
|
||||
opened: boolean,
|
||||
};
|
||||
state = {};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.store = new DocumentViewersStore(props.documentId);
|
||||
}
|
||||
|
||||
openPopover = () => {
|
||||
this.setState({ opened: true });
|
||||
};
|
||||
|
||||
closePopover = () => {
|
||||
this.setState({ opened: false });
|
||||
};
|
||||
|
||||
setRef = (ref: HTMLElement) => {
|
||||
this.anchor = ref;
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Container align="center">
|
||||
<a ref={this.setRef} onClick={this.openPopover}>
|
||||
Viewed
|
||||
{' '}
|
||||
{this.props.count}
|
||||
{' '}
|
||||
{this.props.count === 1 ? 'time' : 'times'}
|
||||
</a>
|
||||
{this.state.opened &&
|
||||
<Popover anchor={this.anchor} onClose={this.closePopover}>
|
||||
<DocumentViewers
|
||||
onMount={this.store.fetchViewers}
|
||||
viewers={this.store.viewers}
|
||||
/>
|
||||
</Popover>}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DocumentViews;
|
||||
@@ -0,0 +1,55 @@
|
||||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import Flex from 'components/Flex';
|
||||
import styled from 'styled-components';
|
||||
import map from 'lodash/map';
|
||||
import Avatar from 'components/Avatar';
|
||||
import Scrollable from 'components/Scrollable';
|
||||
|
||||
type Props = {
|
||||
viewers: Array<Object>,
|
||||
onMount: Function,
|
||||
};
|
||||
|
||||
const List = styled.ul`
|
||||
list-style: none;
|
||||
font-size: 13px;
|
||||
margin: -4px 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
padding: 4px 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const UserName = styled.span`
|
||||
padding-left: 8px;
|
||||
`;
|
||||
|
||||
class DocumentViewers extends Component {
|
||||
props: Props;
|
||||
|
||||
componentDidMount() {
|
||||
this.props.onMount();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Scrollable>
|
||||
<List>
|
||||
{map(this.props.viewers, view => (
|
||||
<li key={view.user.id}>
|
||||
<Flex align="center">
|
||||
<Avatar src={view.user.avatarUrl} />
|
||||
{' '}
|
||||
<UserName>{view.user.name}</UserName>
|
||||
</Flex>
|
||||
</li>
|
||||
))}
|
||||
</List>
|
||||
</Scrollable>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DocumentViewers;
|
||||
@@ -0,0 +1,3 @@
|
||||
// @flow
|
||||
import DocumentViewers from './DocumentViewers';
|
||||
export default DocumentViewers;
|
||||
3
app/components/DocumentViews/index.js
Normal file
3
app/components/DocumentViews/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
// @flow
|
||||
import DocumentViews from './DocumentViews';
|
||||
export default DocumentViews;
|
||||
Reference in New Issue
Block a user