diff --git a/app/soapbox/actions/chats.js b/app/soapbox/actions/chats.js
index 5fa6811ee..2ca996cfe 100644
--- a/app/soapbox/actions/chats.js
+++ b/app/soapbox/actions/chats.js
@@ -1,5 +1,6 @@
-import api from '../api';
+import api, { getLinks } from '../api';
import { getSettings, changeSetting } from 'soapbox/actions/settings';
+import { getFeatures } from 'soapbox/utils/features';
import { v4 as uuidv4 } from 'uuid';
import { Map as ImmutableMap } from 'immutable';
@@ -7,6 +8,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';
@@ -27,14 +32,61 @@ export const CHAT_MESSAGE_DELETE_REQUEST = 'CHAT_MESSAGE_DELETE_REQUEST';
export const CHAT_MESSAGE_DELETE_SUCCESS = 'CHAT_MESSAGE_DELETE_SUCCESS';
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 });
+export function fetchChatsV1() {
+ return (dispatch, getState) =>
+ api(getState).get('/api/v1/pleroma/chats').then((response) => {
+ dispatch({ type: CHATS_FETCH_SUCCESS, chats: response.data });
}).catch(error => {
dispatch({ type: CHATS_FETCH_FAIL, error });
});
+}
+
+export function fetchChatsV2() {
+ return (dispatch, getState) =>
+ api(getState).get('/api/v2/pleroma/chats').then((response) => {
+ let next = getLinks(response).refs.find(link => link.rel === 'next');
+
+ if (!next && response.data.length) {
+ next = { uri: `/api/v2/pleroma/chats?max_id=${response.data[response.data.length - 1].id}&offset=0` };
+ }
+
+ dispatch({ type: CHATS_FETCH_SUCCESS, chats: response.data, next: next ? next.uri : null });
+ }).catch(error => {
+ dispatch({ type: CHATS_FETCH_FAIL, error });
+ });
+}
+
+export function fetchChats() {
+ return (dispatch, getState) => {
+ const state = getState();
+ const instance = state.get('instance');
+ const features = getFeatures(instance);
+
+ dispatch({ type: CHATS_FETCH_REQUEST });
+ if (features.chatsV2) {
+ dispatch(fetchChatsV2());
+ } else {
+ dispatch(fetchChatsV1());
+ }
+ };
+}
+
+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 });
+ });
};
}
@@ -140,7 +192,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;
diff --git a/app/soapbox/components/helmet.js b/app/soapbox/components/helmet.js
index 4b1454ffa..3b96b8c10 100644
--- a/app/soapbox/components/helmet.js
+++ b/app/soapbox/components/helmet.js
@@ -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;
diff --git a/app/soapbox/components/primary_navigation.js b/app/soapbox/components/primary_navigation.js
index 9a11e5969..5bac11d33 100644
--- a/app/soapbox/components/primary_navigation.js
+++ b/app/soapbox/components/primary_navigation.js
@@ -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),
diff --git a/app/soapbox/components/scrollable_list.js b/app/soapbox/components/scrollable_list.js
index ceb554c53..9617d1c68 100644
--- a/app/soapbox/components/scrollable_list.js
+++ b/app/soapbox/components/scrollable_list.js
@@ -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) => (
-