1 import React
from 'react';
2 import PropTypes
from 'prop-types';
3 import IconButton
from '../../../components/icon_button';
4 import ImmutablePropTypes
from 'react-immutable-proptypes';
5 import DropdownMenuContainer
from '../../../containers/dropdown_menu_container';
6 import { defineMessages
, injectIntl
} from 'react-intl';
7 import { me
, isStaff
} from '../../../initial_state';
9 const messages
= defineMessages({
10 delete: { id: 'status.delete', defaultMessage: 'Delete' },
11 redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
12 direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
13 mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
14 reply: { id: 'status.reply', defaultMessage: 'Reply' },
15 reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
16 reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost to original audience' },
17 cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
18 cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
19 favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
20 mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },
21 muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
22 unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
23 block: { id: 'status.block', defaultMessage: 'Block @{name}' },
24 report: { id: 'status.report', defaultMessage: 'Report @{name}' },
25 share: { id: 'status.share', defaultMessage: 'Share' },
26 pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
27 unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
28 embed: { id: 'status.embed', defaultMessage: 'Embed' },
29 admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
30 admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
33 export default @injectIntl
34 class ActionBar
extends React
.PureComponent
{
36 static contextTypes
= {
37 router: PropTypes
.object
,
41 status: ImmutablePropTypes
.map
.isRequired
,
42 onReply: PropTypes
.func
.isRequired
,
43 onReblog: PropTypes
.func
.isRequired
,
44 onFavourite: PropTypes
.func
.isRequired
,
45 onDelete: PropTypes
.func
.isRequired
,
46 onDirect: PropTypes
.func
.isRequired
,
47 onMention: PropTypes
.func
.isRequired
,
48 onMute: PropTypes
.func
,
49 onMuteConversation: PropTypes
.func
,
50 onBlock: PropTypes
.func
,
51 onReport: PropTypes
.func
,
52 onPin: PropTypes
.func
,
53 onEmbed: PropTypes
.func
,
54 intl: PropTypes
.object
.isRequired
,
57 handleReplyClick
= () => {
58 this.props
.onReply(this.props
.status
);
61 handleReblogClick
= (e
) => {
62 this.props
.onReblog(this.props
.status
, e
);
65 handleFavouriteClick
= () => {
66 this.props
.onFavourite(this.props
.status
);
69 handleDeleteClick
= () => {
70 this.props
.onDelete(this.props
.status
, this.context
.router
.history
);
73 handleRedraftClick
= () => {
74 this.props
.onDelete(this.props
.status
, this.context
.router
.history
, true);
77 handleDirectClick
= () => {
78 this.props
.onDirect(this.props
.status
.get('account'), this.context
.router
.history
);
81 handleMentionClick
= () => {
82 this.props
.onMention(this.props
.status
.get('account'), this.context
.router
.history
);
85 handleMuteClick
= () => {
86 this.props
.onMute(this.props
.status
.get('account'));
89 handleConversationMuteClick
= () => {
90 this.props
.onMuteConversation(this.props
.status
);
93 handleBlockClick
= () => {
94 this.props
.onBlock(this.props
.status
.get('account'));
97 handleReport
= () => {
98 this.props
.onReport(this.props
.status
);
101 handlePinClick
= () => {
102 this.props
.onPin(this.props
.status
);
105 handleShare
= () => {
107 text: this.props
.status
.get('search_index'),
108 url: this.props
.status
.get('url'),
112 handleEmbed
= () => {
113 this.props
.onEmbed(this.props
.status
);
117 const { status
, intl
} = this.props
;
119 const publicStatus
= ['public', 'unlisted'].includes(status
.get('visibility'));
120 const mutingConversation
= status
.get('muted');
125 menu
.push({ text: intl
.formatMessage(messages
.embed
), action: this.handleEmbed
});
129 if (me
=== status
.getIn(['account', 'id'])) {
131 menu
.push({ text: intl
.formatMessage(status
.get('pinned') ? messages
.unpin : messages
.pin
), action: this.handlePinClick
});
133 if (status
.get('visibility') === 'private') {
134 menu
.push({ text: intl
.formatMessage(status
.get('reblogged') ? messages
.cancel_reblog_private : messages
.reblog_private
), action: this.handleReblogClick
});
139 menu
.push({ text: intl
.formatMessage(mutingConversation
? messages
.unmuteConversation : messages
.muteConversation
), action: this.handleConversationMuteClick
});
141 menu
.push({ text: intl
.formatMessage(messages
.delete), action: this.handleDeleteClick
});
142 menu
.push({ text: intl
.formatMessage(messages
.redraft
), action: this.handleRedraftClick
});
144 menu
.push({ text: intl
.formatMessage(messages
.mention
, { name: status
.getIn(['account', 'username']) }), action: this.handleMentionClick
});
145 menu
.push({ text: intl
.formatMessage(messages
.direct
, { name: status
.getIn(['account', 'username']) }), action: this.handleDirectClick
});
147 menu
.push({ text: intl
.formatMessage(messages
.mute
, { name: status
.getIn(['account', 'username']) }), action: this.handleMuteClick
});
148 menu
.push({ text: intl
.formatMessage(messages
.block
, { name: status
.getIn(['account', 'username']) }), action: this.handleBlockClick
});
149 menu
.push({ text: intl
.formatMessage(messages
.report
, { name: status
.getIn(['account', 'username']) }), action: this.handleReport
});
152 menu
.push({ text: intl
.formatMessage(messages
.admin_account
, { name: status
.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
153 menu
.push({ text: intl
.formatMessage(messages
.admin_status
), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
157 const shareButton
= ('share' in navigator
) && status
.get('visibility') === 'public' && (
158 <div className
='detailed-status__button'><IconButton title
={intl
.formatMessage(messages
.share
)} icon
='share-alt' onClick
={this.handleShare
} /></div>
162 if (status
.get('in_reply_to_id', null) === null) {
165 replyIcon
= 'reply-all';
168 let reblogIcon
= 'retweet';
169 if (status
.get('visibility') === 'direct') reblogIcon
= 'envelope';
170 else if (status
.get('visibility') === 'private') reblogIcon
= 'lock';
172 let reblog_disabled
= (status
.get('visibility') === 'direct' || status
.get('visibility') === 'private');
175 <div className
='detailed-status__action-bar'>
176 <div className
='detailed-status__button'><IconButton title
={intl
.formatMessage(messages
.reply
)} icon
={status
.get('in_reply_to_account_id') === status
.getIn(['account', 'id']) ? 'reply' : replyIcon
} onClick
={this.handleReplyClick
} /></div>
177 <div className
='detailed-status__button'><IconButton disabled
={reblog_disabled
} active
={status
.get('reblogged')} title
={reblog_disabled
? intl
.formatMessage(messages
.cannot_reblog
) : intl
.formatMessage(messages
.reblog
)} icon
={reblogIcon
} onClick
={this.handleReblogClick
} /></div>
178 <div className
='detailed-status__button'><IconButton className
='star-icon' animate active
={status
.get('favourited')} title
={intl
.formatMessage(messages
.favourite
)} icon
='star' onClick
={this.handleFavouriteClick
} /></div>
181 <div className
='detailed-status__action-bar-dropdown'>
182 <DropdownMenuContainer size
={18} icon
='ellipsis-h' items
={menu
} direction
='left' title
='More' />