commit: 904a2479dd2085dfc94f33746ad6f7a755e72609
parent e057c0e525692a7dcca188f254f043e3c77e1a8a
Author: Emelia Smith <ThisIsMissEm@users.noreply.github.com>
Date: Mon, 9 Apr 2018 17:09:11 +0200
Feature: Direct message from Statuses (#7089)
* Fix: Switching between composing direct message and mention from menus
Previously clicking "direct message" followed by "mention" resulted in the composed status staying as "direct", along with weird spacing of items in the text area. This attempts to fix that.
* Fix: Add missing proptype check for onMention in Status component
* Add the ability to send a direct message to a user from the menu on Statuses
* Add space between "Embed" and "Mention" on expanded statuses menu
Diffstat:
8 files changed, 48 insertions(+), 9 deletions(-)
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
@@ -31,6 +31,8 @@ export default class Status extends ImmutablePureComponent {
onFavourite: PropTypes.func,
onReblog: PropTypes.func,
onDelete: PropTypes.func,
+ onDirect: PropTypes.func,
+ onMention: PropTypes.func,
onPin: PropTypes.func,
onOpenMedia: PropTypes.func,
onOpenVideo: PropTypes.func,
diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js
@@ -9,6 +9,7 @@ import { me } from '../initial_state';
const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
+ direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
@@ -41,6 +42,7 @@ export default class StatusActionBar extends ImmutablePureComponent {
onFavourite: PropTypes.func,
onReblog: PropTypes.func,
onDelete: PropTypes.func,
+ onDirect: PropTypes.func,
onMention: PropTypes.func,
onMute: PropTypes.func,
onBlock: PropTypes.func,
@@ -92,6 +94,10 @@ export default class StatusActionBar extends ImmutablePureComponent {
this.props.onMention(this.props.status.get('account'), this.context.router.history);
}
+ handleDirectClick = () => {
+ this.props.onDirect(this.props.status.get('account'), this.context.router.history);
+ }
+
handleMuteClick = () => {
this.props.onMute(this.props.status.get('account'));
}
@@ -149,6 +155,7 @@ export default class StatusActionBar extends ImmutablePureComponent {
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
} else {
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
+ menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick });
menu.push(null);
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js
@@ -5,6 +5,7 @@ import { makeGetStatus } from '../selectors';
import {
replyCompose,
mentionCompose,
+ directCompose,
} from '../actions/compose';
import {
reblog,
@@ -102,6 +103,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
}
},
+ onDirect (account, router) {
+ dispatch(directCompose(account, router));
+ },
+
onMention (account, router) {
dispatch(mentionCompose(account, router));
},
diff --git a/app/javascript/mastodon/features/status/components/action_bar.js b/app/javascript/mastodon/features/status/components/action_bar.js
@@ -8,6 +8,7 @@ import { me } from '../../../initial_state';
const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
+ direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
reply: { id: 'status.reply', defaultMessage: 'Reply' },
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
@@ -37,6 +38,7 @@ export default class ActionBar extends React.PureComponent {
onReblog: PropTypes.func.isRequired,
onFavourite: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
+ onDirect: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired,
onMute: PropTypes.func,
onMuteConversation: PropTypes.func,
@@ -63,6 +65,10 @@ export default class ActionBar extends React.PureComponent {
this.props.onDelete(this.props.status);
}
+ handleDirectClick = () => {
+ this.props.onDirect(this.props.status.get('account'), this.context.router.history);
+ }
+
handleMentionClick = () => {
this.props.onMention(this.props.status.get('account'), this.context.router.history);
}
@@ -108,6 +114,7 @@ export default class ActionBar extends React.PureComponent {
if (publicStatus) {
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
+ menu.push(null);
}
if (me === status.getIn(['account', 'id'])) {
@@ -121,6 +128,7 @@ export default class ActionBar extends React.PureComponent {
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
} else {
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
+ menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick });
menu.push(null);
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js
@@ -19,6 +19,7 @@ import {
import {
replyCompose,
mentionCompose,
+ directCompose,
} from '../../actions/compose';
import { blockAccount } from '../../actions/accounts';
import {
@@ -148,6 +149,10 @@ export default class Status extends ImmutablePureComponent {
}
}
+ handleDirectClick = (account, router) => {
+ this.props.dispatch(directCompose(account, router));
+ }
+
handleMentionClick = (account, router) => {
this.props.dispatch(mentionCompose(account, router));
}
@@ -379,6 +384,7 @@ export default class Status extends ImmutablePureComponent {
onFavourite={this.handleFavouriteClick}
onReblog={this.handleReblogClick}
onDelete={this.handleDeleteClick}
+ onDirect={this.handleDirectClick}
onMention={this.handleMentionClick}
onMute={this.handleMuteClick}
onMuteConversation={this.handleConversationMuteClick}
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
@@ -198,6 +198,10 @@
"id": "status.delete"
},
{
+ "defaultMessage": "Direct message @{name}",
+ "id": "status.direct"
+ },
+ {
"defaultMessage": "Mention @{name}",
"id": "status.mention"
},
@@ -1371,6 +1375,10 @@
"id": "status.delete"
},
{
+ "defaultMessage": "Direct message @{name}",
+ "id": "status.direct"
+ },
+ {
"defaultMessage": "Mention @{name}",
"id": "status.mention"
},
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
@@ -240,6 +240,7 @@
"status.block": "Block @{name}",
"status.cannot_reblog": "This post cannot be boosted",
"status.delete": "Delete",
+ "status.direct": "Direct message @{name}",
"status.embed": "Embed",
"status.favourite": "Favourite",
"status.load_more": "Load more",
diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js
@@ -259,16 +259,18 @@ export default function compose(state = initialState, action) {
case COMPOSE_UPLOAD_PROGRESS:
return state.set('progress', Math.round((action.loaded / action.total) * 100));
case COMPOSE_MENTION:
- return state
- .update('text', text => `${text}@${action.account.get('acct')} `)
- .set('focusDate', new Date())
- .set('idempotencyKey', uuid());
+ return state.withMutations(map => {
+ map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));
+ map.set('focusDate', new Date());
+ map.set('idempotencyKey', uuid());
+ });
case COMPOSE_DIRECT:
- return state
- .update('text', text => `@${action.account.get('acct')} `)
- .set('privacy', 'direct')
- .set('focusDate', new Date())
- .set('idempotencyKey', uuid());
+ return state.withMutations(map => {
+ map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));
+ map.set('privacy', 'direct');
+ map.set('focusDate', new Date());
+ map.set('idempotencyKey', uuid());
+ });
case COMPOSE_SUGGESTIONS_CLEAR:
return state.update('suggestions', ImmutableList(), list => list.clear()).set('suggestion_token', null);
case COMPOSE_SUGGESTIONS_READY: