0
0
Fork 0

Add unread indicator to conversations (#9009)

This commit is contained in:
Eugen Rochko 2018-10-19 01:47:29 +02:00 committed by GitHub
parent bebe8ec887
commit a38a452481
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 98 additions and 11 deletions

View file

@ -13,6 +13,8 @@ export const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS';
export const CONVERSATIONS_FETCH_FAIL = 'CONVERSATIONS_FETCH_FAIL';
export const CONVERSATIONS_UPDATE = 'CONVERSATIONS_UPDATE';
export const CONVERSATIONS_READ = 'CONVERSATIONS_READ';
export const mountConversations = () => ({
type: CONVERSATIONS_MOUNT,
});
@ -21,6 +23,15 @@ export const unmountConversations = () => ({
type: CONVERSATIONS_UNMOUNT,
});
export const markConversationRead = conversationId => (dispatch, getState) => {
dispatch({
type: CONVERSATIONS_READ,
id: conversationId,
});
api(getState).post(`/api/v1/conversations/${conversationId}/read`);
};
export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => {
dispatch(expandConversationsRequest());

View file

@ -8,6 +8,7 @@ import DisplayName from '../../../components/display_name';
import Avatar from '../../../components/avatar';
import AttachmentList from '../../../components/attachment_list';
import { HotKeys } from 'react-hotkeys';
import classNames from 'classnames';
export default class Conversation extends ImmutablePureComponent {
@ -19,8 +20,10 @@ export default class Conversation extends ImmutablePureComponent {
conversationId: PropTypes.string.isRequired,
accounts: ImmutablePropTypes.list.isRequired,
lastStatus: ImmutablePropTypes.map.isRequired,
unread:PropTypes.bool.isRequired,
onMoveUp: PropTypes.func,
onMoveDown: PropTypes.func,
markRead: PropTypes.func.isRequired,
};
handleClick = () => {
@ -28,7 +31,12 @@ export default class Conversation extends ImmutablePureComponent {
return;
}
const { lastStatus } = this.props;
const { lastStatus, unread, markRead } = this.props;
if (unread) {
markRead();
}
this.context.router.history.push(`/statuses/${lastStatus.get('id')}`);
}
@ -41,7 +49,7 @@ export default class Conversation extends ImmutablePureComponent {
}
render () {
const { accounts, lastStatus, lastAccount } = this.props;
const { accounts, lastStatus, lastAccount, unread } = this.props;
if (lastStatus === null) {
return null;
@ -61,7 +69,7 @@ export default class Conversation extends ImmutablePureComponent {
return (
<HotKeys handlers={handlers}>
<div className='conversation focusable' tabIndex='0' onClick={this.handleClick} role='button'>
<div className={classNames('conversation', 'focusable', { 'conversation--unread': unread })} tabIndex='0' onClick={this.handleClick} role='button'>
<div className='conversation__header'>
<div className='conversation__avatars'>
<div>{accounts.map(account => <Avatar key={account.get('id')} size={36} account={account} />)}</div>

View file

@ -1,5 +1,6 @@
import { connect } from 'react-redux';
import Conversation from '../components/conversation';
import { markConversationRead } from '../../../actions/conversations';
const mapStateToProps = (state, { conversationId }) => {
const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);
@ -7,9 +8,14 @@ const mapStateToProps = (state, { conversationId }) => {
return {
accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),
unread: conversation.get('unread'),
lastStatus,
lastAccount: lastStatus === null ? null : state.getIn(['accounts', lastStatus.get('account')], null),
};
};
export default connect(mapStateToProps)(Conversation);
const mapDispatchToProps = (dispatch, { conversationId }) => ({
markRead: () => dispatch(markConversationRead(conversationId)),
});
export default connect(mapStateToProps, mapDispatchToProps)(Conversation);

View file

@ -6,6 +6,7 @@ import {
CONVERSATIONS_FETCH_SUCCESS,
CONVERSATIONS_FETCH_FAIL,
CONVERSATIONS_UPDATE,
CONVERSATIONS_READ,
} from '../actions/conversations';
import compareId from '../compare_id';
@ -18,6 +19,7 @@ const initialState = ImmutableMap({
const conversationToMap = item => ImmutableMap({
id: item.id,
unread: item.unread,
accounts: ImmutableList(item.accounts.map(a => a.id)),
last_status: item.last_status.id,
});
@ -80,6 +82,14 @@ export default function conversations(state = initialState, action) {
return state.update('mounted', count => count + 1);
case CONVERSATIONS_UNMOUNT:
return state.update('mounted', count => count - 1);
case CONVERSATIONS_READ:
return state.update('items', list => list.map(item => {
if (item.get('id') === action.id) {
return item.set('unread', false);
}
return item;
}));
default:
return state;
}

View file

@ -5503,6 +5503,11 @@ noscript {
border-bottom: 1px solid lighten($ui-base-color, 8%);
cursor: pointer;
&--unread {
background: lighten($ui-base-color, 8%);
border-bottom-color: lighten($ui-base-color, 12%);
}
&__header {
display: flex;
margin-bottom: 15px;