167 lines
5.7 KiB
JavaScript
167 lines
5.7 KiB
JavaScript
|
|
import React, { Component } from 'react';
|
|
import { inject, observer } from 'mobx-react';
|
|
import { remote } from 'electron';
|
|
import clazz from 'classname';
|
|
import moment from 'moment';
|
|
|
|
import classes from './style.css';
|
|
import helper from 'utils/helper';
|
|
|
|
moment.updateLocale('en', {
|
|
relativeTime: {
|
|
past: '%s',
|
|
m: '1 min',
|
|
mm: '%d mins',
|
|
h: 'an hour',
|
|
hh: '%d h',
|
|
s: 'now',
|
|
ss: '%d s',
|
|
},
|
|
});
|
|
|
|
@inject(stores => ({
|
|
chats: stores.chat.sessions,
|
|
chatTo: stores.chat.chatTo,
|
|
selected: stores.chat.user,
|
|
messages: stores.chat.messages,
|
|
markedRead: stores.chat.markedRead,
|
|
sticky: stores.chat.sticky,
|
|
removeChat: stores.chat.removeChat,
|
|
loading: stores.session.loading,
|
|
searching: stores.search.searching,
|
|
}))
|
|
@observer
|
|
export default class Chats extends Component {
|
|
getTheLastestMessage(userid) {
|
|
var list = this.props.messages.get(userid);
|
|
var res;
|
|
|
|
if (list) {
|
|
// Make sure all chatset has be loaded
|
|
res = list.data.slice(-1)[0];
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
hasUnreadMessage(userid) {
|
|
var list = this.props.messages.get(userid);
|
|
|
|
if (list) {
|
|
return list.data.length !== (list.unread || 0);
|
|
}
|
|
}
|
|
|
|
showContextMenu(user) {
|
|
var menu = new remote.Menu.buildFromTemplate([
|
|
{
|
|
label: '发送消息',
|
|
click: () => {
|
|
this.props.chatTo(user);
|
|
}
|
|
},
|
|
{
|
|
type: 'separator'
|
|
},
|
|
{
|
|
label: helper.isTop(user) ? '取消置顶' : '聊天置顶',
|
|
click: () => {
|
|
this.props.sticky(user);
|
|
}
|
|
},
|
|
{
|
|
label: '删除',
|
|
click: () => {
|
|
this.props.removeChat(user);
|
|
}
|
|
},
|
|
{
|
|
label: '标为已读',
|
|
click: () => {
|
|
this.props.markedRead(user.UserName);
|
|
}
|
|
},
|
|
]);
|
|
|
|
menu.popup(remote.getCurrentWindow());
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
var container = this.refs.container;
|
|
var active = container.querySelector(`.${classes.chat}.${classes.active}`);
|
|
|
|
if (active) {
|
|
let rect4active = active.getBoundingClientRect();
|
|
let rect4viewport = container.getBoundingClientRect();
|
|
|
|
// Keep the conversation always in the viewport
|
|
if (!(rect4active.top >= rect4viewport.top
|
|
&& rect4active.bottom <= rect4viewport.bottom)) {
|
|
active.scrollIntoViewIfNeeded();
|
|
}
|
|
}
|
|
}
|
|
|
|
render() {
|
|
var { loading, chats, selected, chatTo, searching } = this.props;
|
|
|
|
if (loading) return false;
|
|
|
|
return (
|
|
<div className={classes.container}>
|
|
<div
|
|
className={classes.chats}
|
|
ref="container">
|
|
{
|
|
!searching && chats.map((e, index) => {
|
|
var message = this.getTheLastestMessage(e.UserName) || {};
|
|
var muted = helper.isMuted(e);
|
|
var isTop = helper.isTop(e);
|
|
return (
|
|
<div
|
|
className={clazz(classes.chat, {
|
|
[classes.sticky]: isTop,
|
|
[classes.active]: selected && selected.UserName === e.UserName
|
|
})}
|
|
key={index}
|
|
onContextMenu={ev => this.showContextMenu(e)}
|
|
onClick={ev => chatTo(e)}>
|
|
<div className={classes.inner}>
|
|
<div className={clazz(classes.dot, {
|
|
[classes.green]: !muted && this.hasUnreadMessage(e.UserName),
|
|
[classes.red]: muted && this.hasUnreadMessage(e.UserName)
|
|
})}>
|
|
<img
|
|
className="disabledDrag"
|
|
src={e.HeadImgUrl}
|
|
onError={e => (e.target.src = 'assets/images/user-fallback.png')}
|
|
/>
|
|
</div>
|
|
|
|
<div className={classes.info}>
|
|
<p
|
|
className={classes.username}
|
|
dangerouslySetInnerHTML={{__html: e.RemarkName || e.NickName}} />
|
|
|
|
<span
|
|
className={classes.message}
|
|
dangerouslySetInnerHTML={{__html: helper.getMessageContent(message) || '未收到消息'}} />
|
|
</div>
|
|
</div>
|
|
|
|
<span className={classes.times}>
|
|
{
|
|
message.CreateTime ? moment(message.CreateTime * 1000).fromNow() : ''
|
|
}
|
|
</span>
|
|
</div>
|
|
);
|
|
})
|
|
}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|