diff --git a/app/controllers/api/v1/groups/removed_accounts_controller.rb b/app/controllers/api/v1/groups/removed_accounts_controller.rb
index e0b5b428..d6cba234 100644
--- a/app/controllers/api/v1/groups/removed_accounts_controller.rb
+++ b/app/controllers/api/v1/groups/removed_accounts_controller.rb
@@ -56,7 +56,7 @@ class Api::V1::Groups::RemovedAccountsController < Api::BaseController
return if unlimited?
if records_continue?
- api_v1_group_accounts_url pagination_params(max_id: pagination_max_id)
+ api_v1_group_removed_accounts_url pagination_params(max_id: pagination_max_id)
end
end
@@ -64,7 +64,7 @@ class Api::V1::Groups::RemovedAccountsController < Api::BaseController
return if unlimited?
unless @accounts.empty?
- api_v1_group_accounts_url pagination_params(since_id: pagination_since_id)
+ api_v1_group_removed_accounts_url pagination_params(since_id: pagination_since_id)
end
end
diff --git a/app/javascript/gabsocial/actions/groups.js b/app/javascript/gabsocial/actions/groups.js
index b67a3116..110bf25a 100644
--- a/app/javascript/gabsocial/actions/groups.js
+++ b/app/javascript/gabsocial/actions/groups.js
@@ -31,6 +31,14 @@ export const GROUP_MEMBERS_EXPAND_REQUEST = 'GROUP_MEMBERS_EXPAND_REQUEST';
export const GROUP_MEMBERS_EXPAND_SUCCESS = 'GROUP_MEMBERS_EXPAND_SUCCESS';
export const GROUP_MEMBERS_EXPAND_FAIL = 'GROUP_MEMBERS_EXPAND_FAIL';
+export const GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST = 'GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST';
+export const GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS';
+export const GROUP_REMOVED_ACCOUNTS_FETCH_FAIL = 'GROUP_REMOVED_ACCOUNTS_FETCH_FAIL';
+
+export const GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST = 'GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST';
+export const GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS';
+export const GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL = 'GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL';
+
export const fetchGroup = id => (dispatch, getState) => {
if (!me) return;
@@ -294,4 +302,94 @@ export function expandMembersFail(id, error) {
id,
error,
};
+};
+
+export function fetchRemovedAccounts(id) {
+ return (dispatch, getState) => {
+ if (!me) return;
+
+ dispatch(fetchRemovedAccountsRequest(id));
+
+ api(getState).get(`/api/v1/groups/${id}/removed_accounts`).then(response => {
+ const next = getLinks(response).refs.find(link => link.rel === 'next');
+
+ dispatch(importFetchedAccounts(response.data));
+ dispatch(fetchRemovedAccountsSuccess(id, response.data, next ? next.uri : null));
+ dispatch(fetchRelationships(response.data.map(item => item.id)));
+ }).catch(error => {
+ dispatch(fetchRemovedAccountsFail(id, error));
+ });
+ };
+};
+
+export function fetchRemovedAccountsRequest(id) {
+ return {
+ type: GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST,
+ id,
+ };
+};
+
+export function fetchRemovedAccountsSuccess(id, accounts, next) {
+ return {
+ type: GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
+ id,
+ accounts,
+ next,
+ };
+};
+
+export function fetchRemovedAccountsFail(id, error) {
+ return {
+ type: GROUP_REMOVED_ACCOUNTS_FETCH_FAIL,
+ id,
+ error,
+ };
+};
+
+export function expandRemovedAccounts(id) {
+ return (dispatch, getState) => {
+ if (!me) return;
+
+ const url = getState().getIn(['user_lists', 'groups_removed_accounts', id, 'next']);
+
+ if (url === null) {
+ return;
+ }
+
+ dispatch(expandRemovedAccountsRequest(id));
+
+ api(getState).get(url).then(response => {
+ const next = getLinks(response).refs.find(link => link.rel === 'next');
+
+ dispatch(importFetchedAccounts(response.data));
+ dispatch(expandRemovedAccountsSuccess(id, response.data, next ? next.uri : null));
+ dispatch(fetchRelationships(response.data.map(item => item.id)));
+ }).catch(error => {
+ dispatch(expandRemovedAccountsFail(id, error));
+ });
+ };
+};
+
+export function expandRemovedAccountsRequest(id) {
+ return {
+ type: GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST,
+ id,
+ };
+};
+
+export function expandRemovedAccountsSuccess(id, accounts, next) {
+ return {
+ type: GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
+ id,
+ accounts,
+ next,
+ };
+};
+
+export function expandRemovedAccountsFail(id, error) {
+ return {
+ type: GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL,
+ id,
+ error,
+ };
};
\ No newline at end of file
diff --git a/app/javascript/gabsocial/features/groups/removed_accounts/index.js b/app/javascript/gabsocial/features/groups/removed_accounts/index.js
new file mode 100644
index 00000000..b91c77fa
--- /dev/null
+++ b/app/javascript/gabsocial/features/groups/removed_accounts/index.js
@@ -0,0 +1,73 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import PropTypes from 'prop-types';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import { debounce } from 'lodash';
+import LoadingIndicator from '../../../components/loading_indicator';
+import {
+ fetchRemovedAccounts,
+ expandRemovedAccounts,
+} from '../../../actions/groups';
+import { FormattedMessage } from 'react-intl';
+import AccountContainer from '../../../containers/account_container';
+import Column from '../../ui/components/column';
+import ScrollableList from '../../../components/scrollable_list';
+
+const mapStateToProps = (state, { params: { id } }) => ({
+ group: state.getIn(['groups', id]),
+ accountIds: state.getIn(['user_lists', 'groups_removed_accounts', id, 'items']),
+ hasMore: !!state.getIn(['user_lists', 'groups_removed_accounts', id, 'next']),
+});
+
+export default @connect(mapStateToProps)
+class GroupRemovedAccounts extends ImmutablePureComponent {
+
+ static propTypes = {
+ params: PropTypes.object.isRequired,
+ dispatch: PropTypes.func.isRequired,
+ accountIds: ImmutablePropTypes.list,
+ hasMore: PropTypes.bool,
+ };
+
+ componentWillMount () {
+ const { params: { id } } = this.props;
+
+ this.props.dispatch(fetchRemovedAccounts(id));
+ }
+
+ componentWillReceiveProps (nextProps) {
+ if (nextProps.params.id !== this.props.params.id) {
+ this.props.dispatch(fetchRemovedAccounts(nextProps.params.id));
+ }
+ }
+
+ handleLoadMore = debounce(() => {
+ this.props.dispatch(expandRemovedAccounts(this.props.params.id));
+ }, 300, { leading: true });
+
+ render () {
+ const { accountIds, hasMore, group } = this.props;
+
+ if (!group || !accountIds) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ }
+ >
+ {accountIds.map(id => )}
+
+
+ );
+ }
+}
diff --git a/app/javascript/gabsocial/features/groups/timeline/components/header.js b/app/javascript/gabsocial/features/groups/timeline/components/header.js
index 9944cb87..58d2cf2f 100644
--- a/app/javascript/gabsocial/features/groups/timeline/components/header.js
+++ b/app/javascript/gabsocial/features/groups/timeline/components/header.js
@@ -5,10 +5,12 @@ import Button from 'gabsocial/components/button';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl } from 'react-intl';
import { NavLink } from 'react-router-dom';
+import DropdownMenuContainer from '../../../../containers/dropdown_menu_container';
const messages = defineMessages({
join: { id: 'groups.join', defaultMessage: 'Join group' },
leave: { id: 'groups.leave', defaultMessage: 'Leave group' },
+ removed_accounts: { id: 'groups.removed_accounts', defaultMessage: 'Removed Accounts' }
});
export default @injectIntl
@@ -36,6 +38,16 @@ class Header extends ImmutablePureComponent {
}
}
+ getAdminMenu() {
+ const { group, intl } = this.props;
+
+ const menu = [
+ { text: intl.formatMessage(messages.removed_accounts), to: `/groups/${group.get('id')}/removed_accounts` },
+ ];
+
+ return ;
+ }
+
render () {
const { group, relationships } = this.props;
@@ -54,6 +66,7 @@ class Header extends ImmutablePureComponent {
Posts
Members
{this.getActionButton()}
+ {relationships.get('admin') && this.getAdminMenu()}
diff --git a/app/javascript/gabsocial/features/ui/index.js b/app/javascript/gabsocial/features/ui/index.js
index 952ba43e..afb0d5d0 100644
--- a/app/javascript/gabsocial/features/ui/index.js
+++ b/app/javascript/gabsocial/features/ui/index.js
@@ -56,6 +56,7 @@ import {
Groups,
GroupTimeline,
GroupMembers,
+ GroupRemovedAccounts,
} from './util/async-components';
import { me, meUsername } from '../../initial_state';
import { previewState as previewMediaState } from './components/media_modal';
@@ -176,6 +177,7 @@ class SwitchingColumnsArea extends React.PureComponent {
+
diff --git a/app/javascript/gabsocial/features/ui/util/async-components.js b/app/javascript/gabsocial/features/ui/util/async-components.js
index 9eb368c0..fbc0cc07 100644
--- a/app/javascript/gabsocial/features/ui/util/async-components.js
+++ b/app/javascript/gabsocial/features/ui/util/async-components.js
@@ -38,6 +38,10 @@ export function GroupMembers () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/members');
}
+export function GroupRemovedAccounts () {
+ return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/removed_accounts');
+}
+
export function Groups () {
return import(/* webpackChunkName: "features/groups/index" */'../../groups/index');
}
diff --git a/app/javascript/gabsocial/reducers/user_lists.js b/app/javascript/gabsocial/reducers/user_lists.js
index 97b7f5e9..609dc473 100644
--- a/app/javascript/gabsocial/reducers/user_lists.js
+++ b/app/javascript/gabsocial/reducers/user_lists.js
@@ -24,6 +24,8 @@ import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import {
GROUP_MEMBERS_FETCH_SUCCESS,
GROUP_MEMBERS_EXPAND_SUCCESS,
+ GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
+ GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
} from '../actions/groups';
const initialState = ImmutableMap({
@@ -35,6 +37,7 @@ const initialState = ImmutableMap({
blocks: ImmutableMap(),
mutes: ImmutableMap(),
groups: ImmutableMap(),
+ groups_removed_accounts: ImmutableMap(),
});
const normalizeList = (state, type, id, accounts, next) => {
@@ -83,6 +86,10 @@ export default function userLists(state = initialState, action) {
return normalizeList(state, 'groups', action.id, action.accounts, action.next);
case GROUP_MEMBERS_EXPAND_SUCCESS:
return appendToList(state, 'groups', action.id, action.accounts, action.next);
+ case GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS:
+ return normalizeList(state, 'groups_removed_accounts', action.id, action.accounts, action.next);
+ case GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS:
+ return appendToList(state, 'groups_removed_accounts', action.id, action.accounts, action.next);
default:
return state;
}
diff --git a/app/javascript/styles/gabsocial/components/group-detail.scss b/app/javascript/styles/gabsocial/components/group-detail.scss
index ea5ca94d..05e115a4 100644
--- a/app/javascript/styles/gabsocial/components/group-detail.scss
+++ b/app/javascript/styles/gabsocial/components/group-detail.scss
@@ -44,6 +44,11 @@
float: right;
margin: 7px;
}
+
+ div {
+ float: right;
+ margin: 4px;
+ }
}
}