wip chat pagination
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
f52b69ebbb
commit
12e4c6c083
21 changed files with 170 additions and 61 deletions
|
@ -1,4 +1,4 @@
|
|||
import api from '../api';
|
||||
import api, { getLinks } from '../api';
|
||||
import { getSettings, changeSetting } from 'soapbox/actions/settings';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
@ -7,6 +7,10 @@ export const CHATS_FETCH_REQUEST = 'CHATS_FETCH_REQUEST';
|
|||
export const CHATS_FETCH_SUCCESS = 'CHATS_FETCH_SUCCESS';
|
||||
export const CHATS_FETCH_FAIL = 'CHATS_FETCH_FAIL';
|
||||
|
||||
export const CHATS_EXPAND_REQUEST = 'CHATS_EXPAND_REQUEST';
|
||||
export const CHATS_EXPAND_SUCCESS = 'CHATS_EXPAND_SUCCESS';
|
||||
export const CHATS_EXPAND_FAIL = 'CHATS_EXPAND_FAIL';
|
||||
|
||||
export const CHAT_MESSAGES_FETCH_REQUEST = 'CHAT_MESSAGES_FETCH_REQUEST';
|
||||
export const CHAT_MESSAGES_FETCH_SUCCESS = 'CHAT_MESSAGES_FETCH_SUCCESS';
|
||||
export const CHAT_MESSAGES_FETCH_FAIL = 'CHAT_MESSAGES_FETCH_FAIL';
|
||||
|
@ -30,14 +34,35 @@ export const CHAT_MESSAGE_DELETE_FAIL = 'CHAT_MESSAGE_DELETE_FAIL';
|
|||
export function fetchChats() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: CHATS_FETCH_REQUEST });
|
||||
return api(getState).get('/api/v1/pleroma/chats').then(({ data }) => {
|
||||
dispatch({ type: CHATS_FETCH_SUCCESS, chats: data });
|
||||
api(getState).get('/api/v2/pleroma/chats').then((response) => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch({ type: CHATS_FETCH_SUCCESS, chats: response.data, next: next ? next.uri : null });
|
||||
}).catch(error => {
|
||||
dispatch({ type: CHATS_FETCH_FAIL, error });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function expandChats() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['chats', 'next']);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: CHATS_EXPAND_REQUEST });
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch({ type: CHATS_EXPAND_SUCCESS, chats: response.data, next: next ? next.uri : null });
|
||||
}).catch(error => {
|
||||
dispatch({ type: CHATS_EXPAND_FAIL, error });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchChatMessages(chatId, maxId = null) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: CHAT_MESSAGES_FETCH_REQUEST, chatId, maxId });
|
||||
|
@ -140,7 +165,7 @@ export function startChat(accountId) {
|
|||
|
||||
export function markChatRead(chatId, lastReadId) {
|
||||
return (dispatch, getState) => {
|
||||
const chat = getState().getIn(['chats', chatId]);
|
||||
const chat = getState().getIn(['chats', 'items', chatId]);
|
||||
if (!lastReadId) lastReadId = chat.get('last_message');
|
||||
|
||||
if (chat.get('unread') < 1) return;
|
||||
|
|
|
@ -11,7 +11,7 @@ FaviconService.initFaviconService();
|
|||
|
||||
const getNotifTotals = state => {
|
||||
const notifications = state.getIn(['notifications', 'unread'], 0);
|
||||
const chats = state.get('chats').reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0);
|
||||
const chats = state.getIn(['chats', 'items']).reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0);
|
||||
const reports = state.getIn(['admin', 'openReports']).count();
|
||||
const approvals = state.getIn(['admin', 'awaitingApproval']).count();
|
||||
return notifications + chats + reports + approvals;
|
||||
|
|
|
@ -25,7 +25,7 @@ const mapStateToProps = state => {
|
|||
account,
|
||||
logo: getSoapboxConfig(state).get('logo'),
|
||||
notificationCount: state.getIn(['notifications', 'unread']),
|
||||
chatsCount: state.get('chats').reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0),
|
||||
chatsCount: state.getIn(['chats', 'items']).reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0),
|
||||
dashboardCount: reportsCount + approvalCount,
|
||||
baseURL: getBaseURL(account),
|
||||
settings: getSettings(state),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
import IntersectionObserverArticleContainer from '../containers/intersection_observer_article_container';
|
||||
import LoadMore from './load_more';
|
||||
import MoreFollows from './more_follows';
|
||||
|
@ -45,6 +46,7 @@ class ScrollableList extends PureComponent {
|
|||
placeholderCount: PropTypes.number,
|
||||
autoload: PropTypes.bool,
|
||||
onRefresh: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -240,16 +242,22 @@ class ScrollableList extends PureComponent {
|
|||
}
|
||||
|
||||
renderLoading = () => {
|
||||
const { prepend, placeholderComponent: Placeholder, placeholderCount } = this.props;
|
||||
const { className, prepend, placeholderComponent: Placeholder, placeholderCount } = this.props;
|
||||
|
||||
if (Placeholder && placeholderCount > 0) {
|
||||
return Array(placeholderCount).fill().map((_, i) => (
|
||||
<Placeholder key={i} />
|
||||
));
|
||||
return (
|
||||
<div className={classNames('slist slist--flex', className)}>
|
||||
<div role='feed' className='item-list'>
|
||||
{Array(placeholderCount).fill().map((_, i) => (
|
||||
<Placeholder key={i} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='slist slist--flex'>
|
||||
<div className={classNames('slist slist--flex', className)}>
|
||||
<div role='feed' className='item-list'>
|
||||
{prepend}
|
||||
</div>
|
||||
|
@ -262,10 +270,10 @@ class ScrollableList extends PureComponent {
|
|||
}
|
||||
|
||||
renderEmptyMessage = () => {
|
||||
const { prepend, alwaysPrepend, emptyMessage } = this.props;
|
||||
const { className, prepend, alwaysPrepend, emptyMessage } = this.props;
|
||||
|
||||
return (
|
||||
<div className='slist slist--flex' ref={this.setRef}>
|
||||
<div className={classNames('slist slist--flex', className)} ref={this.setRef}>
|
||||
{alwaysPrepend && prepend}
|
||||
|
||||
<div className='empty-column-indicator'>
|
||||
|
@ -276,13 +284,13 @@ class ScrollableList extends PureComponent {
|
|||
}
|
||||
|
||||
renderFeed = () => {
|
||||
const { children, scrollKey, isLoading, hasMore, prepend, onLoadMore, onRefresh, placeholderComponent: Placeholder } = this.props;
|
||||
const { className, children, scrollKey, isLoading, hasMore, prepend, onLoadMore, onRefresh, placeholderComponent: Placeholder } = this.props;
|
||||
const childrenCount = React.Children.count(children);
|
||||
const trackScroll = true; //placeholder
|
||||
const loadMore = (hasMore && onLoadMore) ? <LoadMore visible={!isLoading} onClick={this.handleLoadMore} /> : null;
|
||||
|
||||
const feed = (
|
||||
<div className='slist' ref={this.setRef} onMouseMove={this.handleMouseMove}>
|
||||
<div className={classNames('slist', className)} ref={this.setRef} onMouseMove={this.handleMouseMove}>
|
||||
<div role='feed' className='item-list'>
|
||||
{prepend}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ const mapStateToProps = state => {
|
|||
account: state.getIn(['accounts', me]),
|
||||
logo: getSoapboxConfig(state).get('logo'),
|
||||
notificationCount: state.getIn(['notifications', 'unread']),
|
||||
chatsCount: state.get('chats').reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0),
|
||||
chatsCount: state.getIn(['chats', 'items']).reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0),
|
||||
dashboardCount: reportsCount + approvalCount,
|
||||
features: getFeatures(instance),
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ import { displayFqn } from 'soapbox/utils/state';
|
|||
|
||||
const mapStateToProps = (state, { params }) => {
|
||||
const getChat = makeGetChat();
|
||||
const chat = state.getIn(['chats', params.chatId], ImmutableMap()).toJS();
|
||||
const chat = state.getIn(['chats', 'items', params.chatId], ImmutableMap()).toJS();
|
||||
|
||||
return {
|
||||
me: state.get('me'),
|
||||
|
|
|
@ -15,7 +15,7 @@ const makeMapStateToProps = () => {
|
|||
const getChat = makeGetChat();
|
||||
|
||||
const mapStateToProps = (state, { chatId }) => {
|
||||
const chat = state.getIn(['chats', chatId]);
|
||||
const chat = state.getIn(['chats', 'items', chatId]);
|
||||
|
||||
return {
|
||||
chat: chat ? getChat(state, chat.toJS()) : undefined,
|
||||
|
|
|
@ -23,7 +23,7 @@ const messages = defineMessages({
|
|||
|
||||
const mapStateToProps = (state, { chatId }) => ({
|
||||
me: state.get('me'),
|
||||
chat: state.getIn(['chats', chatId]),
|
||||
chat: state.getIn(['chats', 'items', chatId]),
|
||||
chatMessageIds: state.getIn(['chat_message_lists', chatId], ImmutableOrderedSet()),
|
||||
});
|
||||
|
||||
|
|
|
@ -2,11 +2,19 @@ import React from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { debounce } from 'lodash';
|
||||
import { expandChats } from 'soapbox/actions/chats';
|
||||
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||
import PlaceholderChat from 'soapbox/features/placeholder/components/placeholder_chat';
|
||||
import Chat from './chat';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
const messages = defineMessages({
|
||||
emptyMessage: { id: 'chat_panels.main_window.empty', defaultMessage: 'No chats found. To start a chat, visit a user\'s profile' },
|
||||
});
|
||||
|
||||
const getSortedChatIds = chats => (
|
||||
chats
|
||||
.toList()
|
||||
|
@ -32,7 +40,9 @@ const makeMapStateToProps = () => {
|
|||
);
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
chatIds: sortedChatIdsSelector(state.get('chats')),
|
||||
chatIds: sortedChatIdsSelector(state.getIn(['chats', 'items'])),
|
||||
hasMore: !!state.getIn(['chats', 'next']),
|
||||
isLoading: state.getIn(['chats', 'loading']),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
|
@ -47,28 +57,40 @@ class ChatList extends ImmutablePureComponent {
|
|||
intl: PropTypes.object.isRequired,
|
||||
chatIds: ImmutablePropTypes.list,
|
||||
onClickChat: PropTypes.func,
|
||||
emptyMessage: PropTypes.node,
|
||||
onRefresh: PropTypes.func,
|
||||
hasMore: PropTypes.func,
|
||||
isLoading: PropTypes.bool,
|
||||
};
|
||||
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.dispatch(expandChats());
|
||||
}, 300, { leading: true });
|
||||
|
||||
render() {
|
||||
const { chatIds, emptyMessage } = this.props;
|
||||
const { intl, chatIds, hasMore, isLoading } = this.props;
|
||||
|
||||
return (
|
||||
<div className='chat-list'>
|
||||
<div className='chat-list__content'>
|
||||
{chatIds.count() === 0 &&
|
||||
<div className='empty-column-indicator'>{emptyMessage}</div>
|
||||
}
|
||||
{chatIds.map(chatId => (
|
||||
<div key={chatId} className='chat-list-item'>
|
||||
<Chat
|
||||
chatId={chatId}
|
||||
onClick={this.props.onClickChat}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<ScrollableList
|
||||
className='chat-list'
|
||||
scrollKey='awaiting-approval'
|
||||
emptyMessage={intl.formatMessage(messages.emptyMessage)}
|
||||
hasMore={hasMore}
|
||||
isLoading={isLoading}
|
||||
showLoading={isLoading && chatIds.size === 0}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
onRefresh={this.props.onRefresh}
|
||||
placeholderComponent={PlaceholderChat}
|
||||
placeholderCount={20}
|
||||
>
|
||||
{chatIds.map(chatId => (
|
||||
<div key={chatId} className='chat-list-item'>
|
||||
<Chat
|
||||
chatId={chatId}
|
||||
onClick={this.props.onClickChat}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</ScrollableList>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
const getChatsUnreadCount = state => {
|
||||
const chats = state.get('chats');
|
||||
const chats = state.getIn(['chats', 'items']);
|
||||
return chats.reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0);
|
||||
};
|
||||
|
||||
|
@ -30,7 +30,7 @@ const normalizePanes = (chats, panes = ImmutableList()) => (
|
|||
);
|
||||
|
||||
const makeNormalizeChatPanes = () => createSelector([
|
||||
state => state.get('chats'),
|
||||
state => state.getIn(['chats', 'items']),
|
||||
state => getSettings(state).getIn(['chats', 'panes']),
|
||||
], normalizePanes);
|
||||
|
||||
|
@ -93,7 +93,6 @@ class ChatPanes extends ImmutablePureComponent {
|
|||
<>
|
||||
<ChatList
|
||||
onClickChat={this.handleClickChat}
|
||||
emptyMessage={<FormattedMessage id='chat_panels.main_window.empty' defaultMessage="No chats found. To start a chat, visit a user's profile." />}
|
||||
/>
|
||||
<AccountSearch
|
||||
placeholder={intl.formatMessage(messages.searchPlaceholder)}
|
||||
|
|
|
@ -22,7 +22,7 @@ const makeMapStateToProps = () => {
|
|||
const getChat = makeGetChat();
|
||||
|
||||
const mapStateToProps = (state, { chatId }) => {
|
||||
const chat = state.getIn(['chats', chatId]);
|
||||
const chat = state.getIn(['chats', 'items', chatId]);
|
||||
|
||||
return {
|
||||
me: state.get('me'),
|
||||
|
|
|
@ -4,11 +4,10 @@ import { connect } from 'react-redux';
|
|||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { fetchChats, launchChat } from 'soapbox/actions/chats';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ChatList from './components/chat_list';
|
||||
import AudioToggle from 'soapbox/features/chats/components/audio_toggle';
|
||||
import AccountSearch from 'soapbox/components/account_search';
|
||||
import PullToRefresh from 'soapbox/components/pull_to_refresh';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.chats', defaultMessage: 'Chats' },
|
||||
|
@ -60,12 +59,10 @@ class ChatIndex extends React.PureComponent {
|
|||
onSelected={this.handleSuggestion}
|
||||
/>
|
||||
|
||||
<PullToRefresh onRefresh={this.handleRefresh}>
|
||||
<ChatList
|
||||
onClickChat={this.handleClickChat}
|
||||
emptyMessage={<FormattedMessage id='chat_panels.main_window.empty' defaultMessage="No chats found. To start a chat, visit a user's profile." />}
|
||||
/>
|
||||
</PullToRefresh>
|
||||
<ChatList
|
||||
onClickChat={this.handleClickChat}
|
||||
onRefresh={this.handleRefresh}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import PlaceholderAvatar from './placeholder_avatar';
|
||||
import PlaceholderDisplayName from './placeholder_display_name';
|
||||
import { randomIntFromInterval, generateText } from '../utils';
|
||||
|
||||
export default class PlaceholderAccount extends React.Component {
|
||||
|
||||
render() {
|
||||
const messageLength = randomIntFromInterval(5, 75);
|
||||
|
||||
return (
|
||||
<div className='chat-list-item chat-list-item--placeholder'>
|
||||
<div className='account'>
|
||||
<div className='account__wrapper'>
|
||||
<div className='account__display-name'>
|
||||
<div className='account__avatar-wrapper'>
|
||||
<PlaceholderAvatar size={36} />
|
||||
</div>
|
||||
<PlaceholderDisplayName minLength={3} maxLength={25} />
|
||||
<span className='chat__last-message'>
|
||||
{generateText(messageLength)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -171,7 +171,7 @@ const mapStateToProps = state => {
|
|||
logo: getSoapboxConfig(state).get('logo'),
|
||||
features: getFeatures(instance),
|
||||
notificationCount: state.getIn(['notifications', 'unread']),
|
||||
chatsCount: state.get('chats').reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0),
|
||||
chatsCount: state.getIn(['chats', 'items']).reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0),
|
||||
dashboardCount: reportsCount + approvalCount,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
ACCOUNTS_IMPORT,
|
||||
ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP,
|
||||
} from '../actions/importer';
|
||||
import { CHATS_FETCH_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
|
||||
import { CHATS_FETCH_SUCCESS, CHATS_EXPAND_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
|
||||
import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { normalizeAccount as normalizeAccount2 } from 'soapbox/actions/importer/normalizer';
|
||||
import {
|
||||
|
@ -208,6 +208,7 @@ export default function accounts(state = initialState, action) {
|
|||
username: action.username,
|
||||
}));
|
||||
case CHATS_FETCH_SUCCESS:
|
||||
case CHATS_EXPAND_SUCCESS:
|
||||
return importAccountsFromChats(state, action.chats);
|
||||
case CHAT_FETCH_SUCCESS:
|
||||
case STREAMING_CHAT_UPDATE:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
CHATS_FETCH_SUCCESS,
|
||||
CHATS_EXPAND_SUCCESS,
|
||||
CHAT_MESSAGES_FETCH_SUCCESS,
|
||||
CHAT_MESSAGE_SEND_REQUEST,
|
||||
CHAT_MESSAGE_SEND_SUCCESS,
|
||||
|
@ -47,6 +48,7 @@ export default function chatMessageLists(state = initialState, action) {
|
|||
case CHAT_MESSAGE_SEND_REQUEST:
|
||||
return updateList(state, action.chatId, [action.uuid]);
|
||||
case CHATS_FETCH_SUCCESS:
|
||||
case CHATS_EXPAND_SUCCESS:
|
||||
return importLastMessages(state, action.chats);
|
||||
case STREAMING_CHAT_UPDATE:
|
||||
if (action.chat.last_message &&
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
CHATS_FETCH_SUCCESS,
|
||||
CHATS_EXPAND_SUCCESS,
|
||||
CHAT_MESSAGES_FETCH_SUCCESS,
|
||||
CHAT_MESSAGE_SEND_REQUEST,
|
||||
CHAT_MESSAGE_SEND_SUCCESS,
|
||||
|
@ -38,6 +39,7 @@ export default function chatMessages(state = initialState, action) {
|
|||
pending: true,
|
||||
}));
|
||||
case CHATS_FETCH_SUCCESS:
|
||||
case CHATS_EXPAND_SUCCESS:
|
||||
return importLastMessages(state, fromJS(action.chats));
|
||||
case CHAT_MESSAGES_FETCH_SUCCESS:
|
||||
return importMessages(state, fromJS(action.chatMessages));
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import {
|
||||
CHATS_FETCH_SUCCESS,
|
||||
CHATS_FETCH_REQUEST,
|
||||
CHATS_EXPAND_SUCCESS,
|
||||
CHATS_EXPAND_REQUEST,
|
||||
CHAT_FETCH_SUCCESS,
|
||||
CHAT_READ_SUCCESS,
|
||||
CHAT_READ_REQUEST,
|
||||
|
@ -8,17 +11,29 @@ import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
|
|||
import { normalizeChat } from 'soapbox/actions/importer/normalizer';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
const importChat = (state, chat) => state.set(chat.id, fromJS(normalizeChat(chat)));
|
||||
const importChat = (state, chat) => state.setIn(['items', chat.id], fromJS(normalizeChat(chat)));
|
||||
|
||||
const importChats = (state, chats) =>
|
||||
state.withMutations(mutable => chats.forEach(chat => importChat(mutable, chat)));
|
||||
const importChats = (state, chats, next) =>
|
||||
state.withMutations(mutable => {
|
||||
if (next !== undefined) mutable.set('next', next);
|
||||
chats.forEach(chat => importChat(mutable, chat));
|
||||
mutable.set('loading', false);
|
||||
});
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
const initialState = ImmutableMap({
|
||||
next: null,
|
||||
isLoading: false,
|
||||
items: ImmutableMap({}),
|
||||
});
|
||||
|
||||
export default function chats(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case CHATS_FETCH_REQUEST:
|
||||
case CHATS_EXPAND_REQUEST:
|
||||
return state.set('loading', true);
|
||||
case CHATS_FETCH_SUCCESS:
|
||||
return importChats(state, action.chats);
|
||||
case CHATS_EXPAND_SUCCESS:
|
||||
return importChats(state, action.chats, action.next);
|
||||
case STREAMING_CHAT_UPDATE:
|
||||
return importChats(state, [action.chat]);
|
||||
case CHAT_FETCH_SUCCESS:
|
||||
|
|
|
@ -209,8 +209,8 @@ export const getAccountGallery = createSelector([
|
|||
export const makeGetChat = () => {
|
||||
return createSelector(
|
||||
[
|
||||
(state, { id }) => state.getIn(['chats', id]),
|
||||
(state, { id }) => state.getIn(['accounts', state.getIn(['chats', id, 'account'])]),
|
||||
(state, { id }) => state.getIn(['chats', 'items', id]),
|
||||
(state, { id }) => state.getIn(['accounts', state.getIn(['chats', 'items', id, 'account'])]),
|
||||
(state, { last_message }) => state.getIn(['chat_messages', last_message]),
|
||||
],
|
||||
|
||||
|
|
|
@ -116,6 +116,10 @@
|
|||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-toggle .react-toggle-thumb {
|
||||
|
@ -219,7 +223,6 @@
|
|||
}
|
||||
|
||||
.chat-list {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
|
||||
&__content {
|
||||
|
@ -233,6 +236,10 @@
|
|||
align-items: start;
|
||||
}
|
||||
|
||||
.account {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.account__display-name {
|
||||
position: relative;
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
}
|
||||
|
||||
.status__content--placeholder,
|
||||
.display-name--placeholder {
|
||||
.display-name--placeholder,
|
||||
.chat-list-item--placeholder .chat__last-message {
|
||||
letter-spacing: -1px;
|
||||
color: var(--brand-color) !important;
|
||||
opacity: 0.1;
|
||||
|
|
Loading…
Reference in a new issue