Add unread indicator to conversations (#9009)
This commit is contained in:
parent
bebe8ec887
commit
a38a452481
13 changed files with 98 additions and 11 deletions
|
@ -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());
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue