diff --git a/app/soapbox/actions/chats.js b/app/soapbox/actions/chats.js
index e69de29bb..1f864ef80 100644
--- a/app/soapbox/actions/chats.js
+++ b/app/soapbox/actions/chats.js
@@ -0,0 +1,16 @@
+import api from '../api';
+
+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 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, data });
+ }).catch(error => {
+ dispatch({ type: CHATS_FETCH_FAIL, error });
+ });
+ };
+}
diff --git a/app/soapbox/features/chats/components/chat_list.js b/app/soapbox/features/chats/components/chat_list.js
new file mode 100644
index 000000000..e2446e07f
--- /dev/null
+++ b/app/soapbox/features/chats/components/chat_list.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { injectIntl, FormattedMessage } from 'react-intl';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import { fetchChats } from 'soapbox/actions/chats';
+
+const mapStateToProps = state => ({
+ chats: state.get('chats'),
+});
+
+export default @connect(mapStateToProps)
+@injectIntl
+class ChatList extends ImmutablePureComponent {
+
+ static propTypes = {
+ dispatch: PropTypes.func.isRequired,
+ intl: PropTypes.object.isRequired,
+ };
+
+ componentDidMount() {
+ this.props.dispatch(fetchChats());
+ }
+
+ render() {
+ const { chats } = this.props;
+
+ return (
+
+
+
+
+
+ {chats.toList().map(chat => (
+
+ {chat.getIn(['account', 'acct'])}
+
+ ))}
+
+
+ );
+ }
+
+}
diff --git a/app/soapbox/features/ui/index.js b/app/soapbox/features/ui/index.js
index cdac3a3d8..15b9ced5f 100644
--- a/app/soapbox/features/ui/index.js
+++ b/app/soapbox/features/ui/index.js
@@ -36,6 +36,7 @@ import { connectUserStream } from '../../actions/streaming';
import { Redirect } from 'react-router-dom';
import Icon from 'soapbox/components/icon';
import { isStaff } from 'soapbox/utils/accounts';
+import ChatList from 'soapbox/features/chats/components/chat_list';
import {
Status,
@@ -604,6 +605,7 @@ class UI extends React.PureComponent {
{me && }
+ {me && }
);
diff --git a/app/soapbox/reducers/chats.js b/app/soapbox/reducers/chats.js
new file mode 100644
index 000000000..feb44c97a
--- /dev/null
+++ b/app/soapbox/reducers/chats.js
@@ -0,0 +1,15 @@
+import { CHATS_FETCH_SUCCESS } from '../actions/chats';
+import { Map as ImmutableMap, fromJS } from 'immutable';
+
+const initialState = ImmutableMap();
+
+export default function admin(state = initialState, action) {
+ switch(action.type) {
+ case CHATS_FETCH_SUCCESS:
+ return state.merge(fromJS(action.data).reduce((acc, curr) => (
+ acc.set(curr.get('id'), curr)
+ ), ImmutableMap()));
+ default:
+ return state;
+ }
+};
diff --git a/app/soapbox/reducers/index.js b/app/soapbox/reducers/index.js
index 7a8219522..90cd6af62 100644
--- a/app/soapbox/reducers/index.js
+++ b/app/soapbox/reducers/index.js
@@ -43,6 +43,7 @@ import instance from './instance';
import me from './me';
import auth from './auth';
import admin from './admin';
+import chats from './chats';
const reducers = {
dropdown_menu,
@@ -89,6 +90,7 @@ const reducers = {
me,
auth,
admin,
+ chats,
};
export default combineReducers(reducers);
diff --git a/app/styles/application.scss b/app/styles/application.scss
index 2b4c52a83..96eb4dcf4 100644
--- a/app/styles/application.scss
+++ b/app/styles/application.scss
@@ -28,6 +28,7 @@
@import 'demetricator';
@import 'pro';
@import 'overflow_hacks';
+@import 'chats';
// COMPONENTS
@import 'components/buttons';
diff --git a/app/styles/chats.scss b/app/styles/chats.scss
new file mode 100644
index 000000000..60d1355e2
--- /dev/null
+++ b/app/styles/chats.scss
@@ -0,0 +1,24 @@
+.chat-list {
+ position: fixed;
+ bottom: 0;
+ right: 20px;
+ width: 265px;
+
+ &__header {
+ background: var(--brand-color);
+ color: #fff;
+ padding: 6px 10px;
+ font-size: 18px;
+ font-weight: bold;
+ border-radius: 6px 6px 0 0;
+ }
+
+ &__content {
+ background: var(--foreground-color);
+ padding: 10px;
+ }
+
+ &__actions {
+ background: var(--foreground-color);
+ }
+}