@@ -15,6 +15,14 @@ export const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST'; | |||
export const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS'; | |||
export const ACCOUNT_UNFOLLOW_FAIL = 'ACCOUNT_UNFOLLOW_FAIL'; | |||
export const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST'; | |||
export const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS'; | |||
export const ACCOUNT_BLOCK_FAIL = 'ACCOUNT_BLOCK_FAIL'; | |||
export const ACCOUNT_UNBLOCK_REQUEST = 'ACCOUNT_UNBLOCK_REQUEST'; | |||
export const ACCOUNT_UNBLOCK_SUCCESS = 'ACCOUNT_UNBLOCK_SUCCESS'; | |||
export const ACCOUNT_UNBLOCK_FAIL = 'ACCOUNT_UNBLOCK_FAIL'; | |||
export const ACCOUNT_TIMELINE_FETCH_REQUEST = 'ACCOUNT_TIMELINE_FETCH_REQUEST'; | |||
export const ACCOUNT_TIMELINE_FETCH_SUCCESS = 'ACCOUNT_TIMELINE_FETCH_SUCCESS'; | |||
export const ACCOUNT_TIMELINE_FETCH_FAIL = 'ACCOUNT_TIMELINE_FETCH_FAIL'; | |||
@@ -204,3 +212,69 @@ export function expandAccountTimelineFail(id, error) { | |||
error: error | |||
}; | |||
}; | |||
export function blockAccount(id) { | |||
return (dispatch, getState) => { | |||
dispatch(blockAccountRequest(id)); | |||
api(getState).post(`/api/v1/accounts/${id}/block`).then(response => { | |||
dispatch(blockAccountSuccess(response.data)); | |||
}).catch(error => { | |||
dispatch(blockAccountFail(id, error)); | |||
}); | |||
}; | |||
}; | |||
export function unblockAccount(id) { | |||
return (dispatch, getState) => { | |||
dispatch(unblockAccountRequest(id)); | |||
api(getState).post(`/api/v1/accounts/${id}/unblock`).then(response => { | |||
dispatch(unblockAccountSuccess(response.data)); | |||
}).catch(error => { | |||
dispatch(unblockAccountFail(id, error)); | |||
}); | |||
}; | |||
}; | |||
export function blockAccountRequest(id) { | |||
return { | |||
type: ACCOUNT_BLOCK_REQUEST, | |||
id: id | |||
}; | |||
}; | |||
export function blockAccountSuccess(relationship) { | |||
return { | |||
type: ACCOUNT_BLOCK_SUCCESS, | |||
relationship: relationship | |||
}; | |||
}; | |||
export function blockAccountFail(error) { | |||
return { | |||
type: ACCOUNT_BLOCK_FAIL, | |||
error: error | |||
}; | |||
}; | |||
export function unblockAccountRequest(id) { | |||
return { | |||
type: ACCOUNT_UNBLOCK_REQUEST, | |||
id: id | |||
}; | |||
}; | |||
export function unblockAccountSuccess(relationship) { | |||
return { | |||
type: ACCOUNT_UNBLOCK_SUCCESS, | |||
relationship: relationship | |||
}; | |||
}; | |||
export function unblockAccountFail(error) { | |||
return { | |||
type: ACCOUNT_UNBLOCK_FAIL, | |||
error: error | |||
}; | |||
}; |
@@ -41,6 +41,8 @@ const StatusActionBar = React.createClass({ | |||
<li><a href='#' onClick={this.handleDeleteClick}>Delete</a></li> | |||
</ul> | |||
); | |||
} else { | |||
menu = <ul />; | |||
} | |||
return ( | |||
@@ -7,7 +7,8 @@ const ActionBar = React.createClass({ | |||
propTypes: { | |||
account: ImmutablePropTypes.map.isRequired, | |||
me: React.PropTypes.number.isRequired, | |||
onFollow: React.PropTypes.func.isRequired | |||
onFollow: React.PropTypes.func.isRequired, | |||
onBlock: React.PropTypes.func.isRequired | |||
}, | |||
mixins: [PureRenderMixin], | |||
@@ -16,25 +17,46 @@ const ActionBar = React.createClass({ | |||
const { account, me } = this.props; | |||
let infoText = ''; | |||
let follow = ''; | |||
let buttonText = ''; | |||
let block = ''; | |||
let disabled = false; | |||
if (account.get('id') === me) { | |||
buttonText = 'This is you!'; | |||
disabled = true; | |||
} else { | |||
if (account.getIn(['relationship', 'following'])) { | |||
buttonText = 'Unfollow'; | |||
let blockText = ''; | |||
if (account.getIn(['relationship', 'blocking'])) { | |||
buttonText = 'Blocked'; | |||
disabled = true; | |||
blockText = 'Unblock'; | |||
} else { | |||
buttonText = 'Follow'; | |||
} | |||
if (account.getIn(['relationship', 'following'])) { | |||
buttonText = 'Unfollow'; | |||
} else { | |||
buttonText = 'Follow'; | |||
} | |||
if (account.getIn(['relationship', 'followed_by'])) { | |||
infoText = 'Follows you!'; | |||
} | |||
if (account.getIn(['relationship', 'followed_by'])) { | |||
infoText = 'Follows you!'; | |||
blockText = 'Block'; | |||
} | |||
block = <Button text={blockText} onClick={this.props.onBlock} />; | |||
} | |||
if (!account.getIn(['relationship', 'blocking'])) { | |||
follow = <Button text={buttonText} onClick={this.props.onFollow} disabled={disabled} />; | |||
} | |||
return ( | |||
<div style={{ borderTop: '1px solid #363c4b', borderBottom: '1px solid #363c4b', padding: '10px', lineHeight: '36px', overflow: 'hidden', flex: '0 0 auto' }}> | |||
<Button text={buttonText} onClick={this.props.onFollow} disabled={account.get('id') === me} /> <span style={{ color: '#616b86', fontWeight: '500', textTransform: 'uppercase', float: 'right', display: 'block' }}>{infoText}</span> | |||
{follow} {block} | |||
<span style={{ color: '#616b86', fontWeight: '500', textTransform: 'uppercase', float: 'right', display: 'block' }}>{infoText}</span> | |||
</div> | |||
); | |||
}, | |||
@@ -5,6 +5,8 @@ import { | |||
fetchAccount, | |||
followAccount, | |||
unfollowAccount, | |||
blockAccount, | |||
unblockAccount, | |||
fetchAccountTimeline, | |||
expandAccountTimeline | |||
} from '../../actions/accounts'; | |||
@@ -66,6 +68,14 @@ const Account = React.createClass({ | |||
} | |||
}, | |||
handleBlock () { | |||
if (this.props.account.getIn(['relationship', 'blocking'])) { | |||
this.props.dispatch(unblockAccount(this.props.account.get('id'))); | |||
} else { | |||
this.props.dispatch(blockAccount(this.props.account.get('id'))); | |||
} | |||
}, | |||
handleReply (status) { | |||
this.props.dispatch(replyCompose(status)); | |||
}, | |||
@@ -104,7 +114,7 @@ const Account = React.createClass({ | |||
return ( | |||
<div style={{ display: 'flex', flexDirection: 'column', 'flex': '0 0 auto', height: '100%' }}> | |||
<Header account={account} /> | |||
<ActionBar account={account} me={me} onFollow={this.handleFollow} onUnfollow={this.handleUnfollow} /> | |||
<ActionBar account={account} me={me} onFollow={this.handleFollow} onBlock={this.handleBlock} /> | |||
<StatusList statuses={statuses} me={me} onScrollToBottom={this.handleScrollToBottom} onReply={this.handleReply} onReblog={this.handleReblog} onFavourite={this.handleFavourite} /> | |||
</div> | |||
); | |||
@@ -15,6 +15,8 @@ import { | |||
ACCOUNT_FETCH_SUCCESS, | |||
ACCOUNT_FOLLOW_SUCCESS, | |||
ACCOUNT_UNFOLLOW_SUCCESS, | |||
ACCOUNT_BLOCK_SUCCESS, | |||
ACCOUNT_UNBLOCK_SUCCESS, | |||
ACCOUNT_TIMELINE_FETCH_SUCCESS, | |||
ACCOUNT_TIMELINE_EXPAND_SUCCESS | |||
} from '../actions/accounts'; | |||
@@ -231,6 +233,8 @@ export default function timelines(state = initialState, action) { | |||
return normalizeAccount(state, Immutable.fromJS(action.account), Immutable.fromJS(action.relationship)); | |||
case ACCOUNT_FOLLOW_SUCCESS: | |||
case ACCOUNT_UNFOLLOW_SUCCESS: | |||
case ACCOUNT_UNBLOCK_SUCCESS: | |||
case ACCOUNT_BLOCK_SUCCESS: | |||
return normalizeRelationship(state, Immutable.fromJS(action.relationship)); | |||
case STATUS_FETCH_SUCCESS: | |||
return normalizeContext(state, Immutable.fromJS(action.status), Immutable.fromJS(action.context.ancestors), Immutable.fromJS(action.context.descendants)); | |||
@@ -170,7 +170,6 @@ | |||
.dropdown--active .dropdown__content { | |||
display: block; | |||
z-index: 9999; | |||
box-shadow: 0 0 15px rgba(0, 0, 0, 0.4); | |||
&:before { | |||
content: ""; | |||
@@ -187,20 +186,11 @@ | |||
ul { | |||
list-style: none; | |||
} | |||
li { | |||
&:first-child a { | |||
border-radius: 4px 4px 0 0; | |||
} | |||
&:last-child a { | |||
border-radius: 0 0 4px 4px; | |||
} | |||
&:first-child:last-child a { | |||
border-radius: 4px; | |||
} | |||
background: #d9e1e8; | |||
padding: 4px 0; | |||
border-radius: 4px; | |||
box-shadow: 0 0 15px rgba(0, 0, 0, 0.4); | |||
min-width: 100px; | |||
} | |||
a { | |||
@@ -8,7 +8,7 @@ class FavouriteService < BaseService | |||
account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url]) | |||
if status.local? | |||
NotificationMailer.favourite(status, account).deliver_later | |||
NotificationMailer.favourite(status, account).deliver_later unless status.account.blocking?(account) | |||
else | |||
NotificationWorker.perform_async(favourite.stream_entry.id, status.account_id) | |||
end | |||
@@ -10,7 +10,7 @@ class FollowService < BaseService | |||
follow = source_account.follow!(target_account) | |||
if target_account.local? | |||
NotificationMailer.follow(target_account, source_account).deliver_later | |||
NotificationMailer.follow(target_account, source_account).deliver_later unless target_account.blocking?(source_account) | |||
else | |||
subscribe_service.call(target_account) | |||
NotificationWorker.perform_async(follow.stream_entry.id, target_account.id) | |||
@@ -69,7 +69,7 @@ class ProcessFeedService < BaseService | |||
unless mentioned_account.nil? | |||
mentioned_account.mentions.where(status: status).first_or_create(status: status) | |||
NotificationMailer.mention(mentioned_account, status).deliver_later | |||
NotificationMailer.mention(mentioned_account, status).deliver_later unless mentioned_account.blocking?(status.account) | |||
end | |||
else | |||
# What to do about remote user? | |||
@@ -114,7 +114,7 @@ class ProcessFeedService < BaseService | |||
if !status.reblog.nil? | |||
status.save! | |||
NotificationMailer.reblog(status.reblog, status.account).deliver_later if status.reblog.local? | |||
NotificationMailer.reblog(status.reblog, status.account).deliver_later if status.reblog.local? && !status.reblog.account.blocking?(status.account) | |||
end | |||
end | |||
@@ -58,7 +58,7 @@ class ProcessInteractionService < BaseService | |||
def follow!(account, target_account) | |||
account.follow!(target_account) | |||
NotificationMailer.follow(target_account, account).deliver_later | |||
NotificationMailer.follow(target_account, account).deliver_later unless target_account.blocking?(account) | |||
end | |||
def unfollow!(account, target_account) | |||
@@ -78,7 +78,7 @@ class ProcessInteractionService < BaseService | |||
def favourite!(xml, from_account) | |||
current_status = status(xml) | |||
current_status.favourites.where(account: from_account).first_or_create!(account: from_account) | |||
NotificationMailer.favourite(current_status, from_account).deliver_later | |||
NotificationMailer.favourite(current_status, from_account).deliver_later unless current_status.account.blocking?(from_account) | |||
end | |||
def add_post!(body, account) | |||
@@ -27,7 +27,7 @@ class ProcessMentionsService < BaseService | |||
mentioned_account = mention.account | |||
if mentioned_account.local? | |||
NotificationMailer.mention(mentioned_account, status).deliver_later | |||
NotificationMailer.mention(mentioned_account, status).deliver_later unless mentioned_account.blocking?(status.account) | |||
else | |||
NotificationWorker.perform_async(status.stream_entry.id, mentioned_account.id) | |||
end | |||
@@ -9,7 +9,7 @@ class ReblogService < BaseService | |||
account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url]) | |||
if reblogged_status.local? | |||
NotificationMailer.reblog(reblogged_status, account).deliver_later | |||
NotificationMailer.reblog(reblogged_status, account).deliver_later unless reblogged_status.account.blocking?(account) | |||
else | |||
NotificationWorker.perform_async(reblog.stream_entry.id, reblogged_status.account_id) | |||
end | |||