Skip to content
Snippets Groups Projects
Commit fe8dd58b authored by Patrick Figel's avatar Patrick Figel Committed by Eugen
Browse files

Add list of muted user to UI and Getting Started (#1799)

Add the same UI that already exists for blocked users for muted
ones and add it to the "Getting Started" menu.
parent 92cd207c
No related branches found
No related tags found
No related merge requests found
import api, { getLinks } from '../api'
import { fetchRelationships } from './accounts';
export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
export const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL';
export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST';
export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';
export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
export function fetchMutes() {
return (dispatch, getState) => {
dispatch(fetchMutesRequest());
api(getState).get('/api/v1/mutes').then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(fetchMutesSuccess(response.data, next ? next.uri : null));
dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => dispatch(fetchMutesFail(error)));
};
};
export function fetchMutesRequest() {
return {
type: MUTES_FETCH_REQUEST
};
};
export function fetchMutesSuccess(accounts, next) {
return {
type: MUTES_FETCH_SUCCESS,
accounts,
next
};
};
export function fetchMutesFail(error) {
return {
type: MUTES_FETCH_FAIL,
error
};
};
export function expandMutes() {
return (dispatch, getState) => {
const url = getState().getIn(['user_lists', 'mutes', 'next']);
if (url === null) {
return;
}
dispatch(expandMutesRequest());
api(getState).get(url).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(expandMutesSuccess(response.data, next ? next.uri : null));
dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => dispatch(expandMutesFail(error)));
};
};
export function expandMutesRequest() {
return {
type: MUTES_EXPAND_REQUEST
};
};
export function expandMutesSuccess(accounts, next) {
return {
type: MUTES_EXPAND_SUCCESS,
accounts,
next
};
};
export function expandMutesFail(error) {
return {
type: MUTES_EXPAND_FAIL,
error
};
};
......@@ -10,7 +10,8 @@ const messages = defineMessages({
follow: { id: 'account.follow', defaultMessage: 'Follow' },
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' },
unblock: { id: 'account.unblock', defaultMessage: 'Unblock' }
unblock: { id: 'account.unblock', defaultMessage: 'Unblock' },
unmute: { id: 'account.unmute', defaultMessage: 'Unmute' }
});
const buttonsStyle = {
......@@ -25,6 +26,7 @@ const Account = React.createClass({
me: React.PropTypes.number.isRequired,
onFollow: React.PropTypes.func.isRequired,
onBlock: React.PropTypes.func.isRequired,
onMute: React.PropTypes.func.isRequired,
intl: React.PropTypes.object.isRequired
},
......@@ -38,6 +40,10 @@ const Account = React.createClass({
this.props.onBlock(this.props.account);
},
handleMute () {
this.props.onMute(this.props.account);
},
render () {
const { account, me, intl } = this.props;
......@@ -51,11 +57,14 @@ const Account = React.createClass({
const following = account.getIn(['relationship', 'following']);
const requested = account.getIn(['relationship', 'requested']);
const blocking = account.getIn(['relationship', 'blocking']);
const muting = account.getIn(['relationship', 'muting']);
if (requested) {
buttons = <IconButton disabled={true} icon='hourglass' title={intl.formatMessage(messages.requested)} />
} else if (blocking) {
buttons = <IconButton active={true} icon='unlock-alt' title={intl.formatMessage(messages.unblock)} onClick={this.handleBlock} />;
buttons = <IconButton active={true} icon='unlock-alt' title={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.handleBlock} />;
} else if (muting) {
buttons = <IconButton active={true} icon='volume-up' title={intl.formatMessage(messages.unmute, { name: account.get('username') })} onClick={this.handleMute} />;
} else {
buttons = <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} active={following} />;
}
......
......@@ -37,6 +37,7 @@ import FollowRequests from '../features/follow_requests';
import GenericNotFound from '../features/generic_not_found';
import FavouritedStatuses from '../features/favourited_statuses';
import Blocks from '../features/blocks';
import Mutes from '../features/mutes';
import Report from '../features/report';
import { IntlProvider, addLocaleData } from 'react-intl';
import en from 'react-intl/locale-data/en';
......@@ -171,6 +172,7 @@ const Mastodon = React.createClass({
<Route path='follow_requests' component={FollowRequests} />
<Route path='blocks' component={Blocks} />
<Route path='mutes' component={Mutes} />
<Route path='report' component={Report} />
<Route path='*' component={GenericNotFound} />
......
......@@ -14,6 +14,7 @@ const messages = defineMessages({
sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' }
});
......@@ -37,6 +38,7 @@ const GettingStarted = ({ intl, me }) => {
<ColumnLink icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />
{followRequests}
<ColumnLink icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
<ColumnLink icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />
<ColumnLink icon='book' text={intl.formatMessage(messages.info)} href='/about/more' />
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
</div>
......
import { connect } from 'react-redux';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes';
import LoadingIndicator from '../../components/loading_indicator';
import { ScrollContainer } from 'react-router-scroll';
import Column from '../ui/components/column';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import AccountContainer from '../../containers/account_container';
import { fetchMutes, expandMutes } from '../../actions/mutes';
import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({
heading: { id: 'column.mutes', defaultMessage: 'Muted users' }
});
const mapStateToProps = state => ({
accountIds: state.getIn(['user_lists', 'mutes', 'items'])
});
const Mutes = React.createClass({
propTypes: {
params: React.PropTypes.object.isRequired,
dispatch: React.PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list,
intl: React.PropTypes.object.isRequired
},
mixins: [PureRenderMixin],
componentWillMount () {
this.props.dispatch(fetchMutes());
},
handleScroll (e) {
const { scrollTop, scrollHeight, clientHeight } = e.target;
if (scrollTop === scrollHeight - clientHeight) {
this.props.dispatch(expandMutes());
}
},
render () {
const { intl, accountIds } = this.props;
if (!accountIds) {
return (
<Column>
<LoadingIndicator />
</Column>
);
}
return (
<Column icon='users' heading={intl.formatMessage(messages.heading)}>
<ColumnBackButtonSlim />
<ScrollContainer scrollKey='mutes'>
<div className='scrollable' onScroll={this.handleScroll}>
{accountIds.map(id =>
<AccountContainer key={id} id={id} />
)}
</div>
</ScrollContainer>
</Column>
);
}
});
export default connect(mapStateToProps)(injectIntl(Mutes));
......@@ -31,6 +31,7 @@ const en = {
"column.favourites": "Favourites",
"column.follow_requests": "Follow requests",
"column.home": "Home",
"column.mutes": "Muted users",
"column.notifications": "Notifications",
"column.public": "Federated timeline",
"compose_form.placeholder": "What is on your mind?",
......@@ -68,6 +69,7 @@ const en = {
"navigation_bar.follow_requests": "Follow requests",
"navigation_bar.info": "Extended information",
"navigation_bar.logout": "Logout",
"navigation_bar.mutes": "Muted users",
"navigation_bar.preferences": "Preferences",
"navigation_bar.public_timeline": "Federated timeline",
"notification.favourite": "{name} favourited your status",
......
......@@ -15,6 +15,10 @@ import {
BLOCKS_FETCH_SUCCESS,
BLOCKS_EXPAND_SUCCESS
} from '../actions/blocks';
import {
MUTES_FETCH_SUCCESS,
MUTES_EXPAND_SUCCESS
} from '../actions/mutes';
import { COMPOSE_SUGGESTIONS_READY } from '../actions/compose';
import {
REBLOG_SUCCESS,
......@@ -94,6 +98,8 @@ export default function accounts(state = initialState, action) {
case FOLLOW_REQUESTS_EXPAND_SUCCESS:
case BLOCKS_FETCH_SUCCESS:
case BLOCKS_EXPAND_SUCCESS:
case MUTES_FETCH_SUCCESS:
case MUTES_EXPAND_SUCCESS:
return normalizeAccounts(state, action.accounts);
case NOTIFICATIONS_REFRESH_SUCCESS:
case NOTIFICATIONS_EXPAND_SUCCESS:
......
......@@ -16,6 +16,10 @@ import {
BLOCKS_FETCH_SUCCESS,
BLOCKS_EXPAND_SUCCESS
} from '../actions/blocks';
import {
MUTES_FETCH_SUCCESS,
MUTES_EXPAND_SUCCESS
} from '../actions/mutes';
import Immutable from 'immutable';
const initialState = Immutable.Map({
......@@ -24,7 +28,8 @@ const initialState = Immutable.Map({
reblogged_by: Immutable.Map(),
favourited_by: Immutable.Map(),
follow_requests: Immutable.Map(),
blocks: Immutable.Map()
blocks: Immutable.Map(),
mutes: Immutable.Map()
});
const normalizeList = (state, type, id, accounts, next) => {
......@@ -65,6 +70,10 @@ export default function userLists(state = initialState, action) {
return state.setIn(['blocks', 'items'], Immutable.List(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);
case BLOCKS_EXPAND_SUCCESS:
return state.updateIn(['blocks', 'items'], list => list.push(...action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);
case MUTES_FETCH_SUCCESS:
return state.setIn(['mutes', 'items'], Immutable.List(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);
case MUTES_EXPAND_SUCCESS:
return state.updateIn(['mutes', 'items'], list => list.push(...action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);
default:
return state;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment