diff --git a/app/assets/javascripts/components/actions/accounts.jsx b/app/assets/javascripts/components/actions/accounts.jsx
index 803911c6c7..2245621996 100644
--- a/app/assets/javascripts/components/actions/accounts.jsx
+++ b/app/assets/javascripts/components/actions/accounts.jsx
@@ -40,6 +40,10 @@ export const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST';
export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS';
export const FOLLOWING_FETCH_FAIL = 'FOLLOWING_FETCH_FAIL';
+export const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST';
+export const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS';
+export const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL';
+
export function setAccountSelf(account) {
return {
type: ACCOUNT_SET_SELF,
@@ -304,6 +308,7 @@ export function fetchFollowers(id) {
api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => {
dispatch(fetchFollowersSuccess(id, response.data));
+ dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => {
dispatch(fetchFollowersFail(id, error));
});
@@ -339,6 +344,7 @@ export function fetchFollowing(id) {
api(getState).get(`/api/v1/accounts/${id}/following`).then(response => {
dispatch(fetchFollowingSuccess(id, response.data));
+ dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => {
dispatch(fetchFollowingFail(id, error));
});
@@ -367,3 +373,36 @@ export function fetchFollowingFail(id, error) {
error: error
};
};
+
+export function fetchRelationships(account_ids) {
+ return (dispatch, getState) => {
+ dispatch(fetchRelationshipsRequest(account_ids));
+
+ api(getState).get(`/api/v1/accounts/relationships?${account_ids.map(id => `id[]=${id}`).join('&')}`).then(response => {
+ dispatch(fetchRelationshipsSuccess(response.data));
+ }).catch(error => {
+ dispatch(fetchRelationshipsFail(error));
+ });
+ };
+};
+
+export function fetchRelationshipsRequest(ids) {
+ return {
+ type: RELATIONSHIPS_FETCH_REQUEST,
+ ids: ids
+ };
+};
+
+export function fetchRelationshipsSuccess(relationships) {
+ return {
+ type: RELATIONSHIPS_FETCH_SUCCESS,
+ relationships: relationships
+ };
+};
+
+export function fetchRelationshipsFail(error) {
+ return {
+ type: RELATIONSHIPS_FETCH_FAIL,
+ error: error
+ };
+};
diff --git a/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx b/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx
index aebe362306..c46b825347 100644
--- a/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx
+++ b/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx
@@ -109,7 +109,7 @@ const SuggestionsBox = React.createClass({
{displayName}
- {account.get('acct')}
+ @{account.get('acct')}
)
})}
diff --git a/app/assets/javascripts/components/features/followers/components/account.jsx b/app/assets/javascripts/components/features/followers/components/account.jsx
index 1aa3ce511b..27f34c4773 100644
--- a/app/assets/javascripts/components/features/followers/components/account.jsx
+++ b/app/assets/javascripts/components/features/followers/components/account.jsx
@@ -1,62 +1,82 @@
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar';
+import DisplayName from '../../../components/display_name';
import { Link } from 'react-router';
+import IconButton from '../../../components/icon_button';
const outerStyle = {
- padding: '10px'
+ padding: '10px',
+ borderBottom: '1px solid #363c4b'
};
-const displayNameStyle = {
+const itemStyle = {
+ flex: '1 1 auto',
display: 'block',
- fontWeight: '500',
+ color: '#9baec8',
overflow: 'hidden',
- textOverflow: 'ellipsis',
- color: '#fff'
+ textDecoration: 'none',
+ fontSize: '14px'
};
-const acctStyle = {
- display: 'block',
- overflow: 'hidden',
- textOverflow: 'ellipsis'
+const noteStyle = {
+ paddingTop: '5px',
+ fontSize: '12px',
+ color: '#616b86'
};
-const itemStyle = {
- display: 'block',
- color: '#9baec8',
- overflow: 'hidden',
- textDecoration: 'none'
+const buttonsStyle = {
+ padding: '10px'
};
const Account = React.createClass({
propTypes: {
account: ImmutablePropTypes.map.isRequired,
- me: React.PropTypes.number.isRequired
+ me: React.PropTypes.number.isRequired,
+ onFollow: React.PropTypes.func.isRequired,
+ withNote: React.PropTypes.bool
},
mixins: [PureRenderMixin],
+ handleFollow () {
+ this.props.onFollow(this.props.account);
+ },
+
render () {
- const { account } = this.props;
+ const { account, me } = this.props;
if (!account) {
return ;
}
- let displayName = account.get('display_name');
+ let note, buttons;
- if (displayName.length === 0) {
- displayName = account.get('username');
+ if (account.get('note').length > 0) {
+ note = {account.get('note')}
;
+ }
+
+ if (account.get('id') !== me) {
+ buttons = (
+
+
+
+ );
}
return (
-
-
-
{displayName}
-
{account.get('acct')}
-
+
+
+ {note}
);
}
diff --git a/app/assets/javascripts/components/features/followers/containers/account_container.jsx b/app/assets/javascripts/components/features/followers/containers/account_container.jsx
index ee6b6dcfdf..988d60adbb 100644
--- a/app/assets/javascripts/components/features/followers/containers/account_container.jsx
+++ b/app/assets/javascripts/components/features/followers/containers/account_container.jsx
@@ -1,6 +1,10 @@
import { connect } from 'react-redux';
import { makeGetAccount } from '../../../selectors';
import Account from '../components/account';
+import {
+ followAccount,
+ unfollowAccount
+} from '../../../actions/accounts';
const makeMapStateToProps = () => {
const getAccount = makeGetAccount();
@@ -14,7 +18,13 @@ const makeMapStateToProps = () => {
};
const mapDispatchToProps = (dispatch) => ({
- //
+ onFollow (account) {
+ if (account.getIn(['relationship', 'following'])) {
+ dispatch(unfollowAccount(account.get('id')));
+ } else {
+ dispatch(followAccount(account.get('id')));
+ }
+ }
});
export default connect(makeMapStateToProps, mapDispatchToProps)(Account);
diff --git a/app/assets/javascripts/components/reducers/timelines.jsx b/app/assets/javascripts/components/reducers/timelines.jsx
index 59a1fbaa7b..4bf97c18d3 100644
--- a/app/assets/javascripts/components/reducers/timelines.jsx
+++ b/app/assets/javascripts/components/reducers/timelines.jsx
@@ -20,7 +20,8 @@ import {
ACCOUNT_TIMELINE_FETCH_SUCCESS,
ACCOUNT_TIMELINE_EXPAND_SUCCESS,
FOLLOWERS_FETCH_SUCCESS,
- FOLLOWING_FETCH_SUCCESS
+ FOLLOWING_FETCH_SUCCESS,
+ RELATIONSHIPS_FETCH_SUCCESS
} from '../actions/accounts';
import {
STATUS_FETCH_SUCCESS,
@@ -184,6 +185,14 @@ function normalizeRelationship(state, relationship) {
return state.setIn(['relationships', relationship.get('id')], relationship);
};
+function normalizeRelationships(state, relationships) {
+ relationships.forEach(relationship => {
+ state = normalizeRelationship(state, relationship);
+ });
+
+ return state;
+};
+
function setSelf(state, account) {
state = normalizeAccount(state, account);
return state.set('me', account.get('id'));
@@ -252,6 +261,8 @@ export default function timelines(state = initialState, action) {
case FOLLOWERS_FETCH_SUCCESS:
case FOLLOWING_FETCH_SUCCESS:
return normalizeAccounts(state, Immutable.fromJS(action.accounts));
+ case RELATIONSHIPS_FETCH_SUCCESS:
+ return normalizeRelationships(state, Immutable.fromJS(action.relationships));
default:
return state;
}
diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss
index 0fd026fee0..2b1c1194d9 100644
--- a/app/assets/stylesheets/components.scss
+++ b/app/assets/stylesheets/components.scss
@@ -117,17 +117,17 @@
}
}
-.status__display-name, .status__relative-time, .detailed-status__display-name, .detailed-status__datetime {
+.status__display-name, .status__relative-time, .detailed-status__display-name, .detailed-status__datetime, .account__display-name {
text-decoration: none;
}
-.status__display-name {
+.status__display-name, .account__display-name {
strong {
color: #fff;
}
}
-.status__display-name, .reply-indicator__display-name, .detailed-status__display-name {
+.status__display-name, .reply-indicator__display-name, .detailed-status__display-name, .account__display-name {
&:hover {
strong {
text-decoration: underline;
@@ -135,6 +135,12 @@
}
}
+.account__display-name {
+ strong {
+ display: block;
+ }
+}
+
.detailed-status__display-name {
color: #d9e1e8;
line-height: 24px;