* 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
		
			
				
	
	
		
			163 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import React from 'react';
 | |
| import PropTypes from 'prop-types';
 | |
| import IconButton from '../../../components/icon_button';
 | |
| import ImmutablePropTypes from 'react-immutable-proptypes';
 | |
| import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
 | |
| import { defineMessages, injectIntl } from 'react-intl';
 | |
| 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' },
 | |
|   cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
 | |
|   favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
 | |
|   mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },
 | |
|   muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
 | |
|   unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
 | |
|   block: { id: 'status.block', defaultMessage: 'Block @{name}' },
 | |
|   report: { id: 'status.report', defaultMessage: 'Report @{name}' },
 | |
|   share: { id: 'status.share', defaultMessage: 'Share' },
 | |
|   pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
 | |
|   unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
 | |
|   embed: { id: 'status.embed', defaultMessage: 'Embed' },
 | |
| });
 | |
| 
 | |
| @injectIntl
 | |
| export default class ActionBar extends React.PureComponent {
 | |
| 
 | |
|   static contextTypes = {
 | |
|     router: PropTypes.object,
 | |
|   };
 | |
| 
 | |
|   static propTypes = {
 | |
|     status: ImmutablePropTypes.map.isRequired,
 | |
|     onReply: PropTypes.func.isRequired,
 | |
|     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,
 | |
|     onBlock: PropTypes.func,
 | |
|     onReport: PropTypes.func,
 | |
|     onPin: PropTypes.func,
 | |
|     onEmbed: PropTypes.func,
 | |
|     intl: PropTypes.object.isRequired,
 | |
|   };
 | |
| 
 | |
|   handleReplyClick = () => {
 | |
|     this.props.onReply(this.props.status);
 | |
|   }
 | |
| 
 | |
|   handleReblogClick = (e) => {
 | |
|     this.props.onReblog(this.props.status, e);
 | |
|   }
 | |
| 
 | |
|   handleFavouriteClick = () => {
 | |
|     this.props.onFavourite(this.props.status);
 | |
|   }
 | |
| 
 | |
|   handleDeleteClick = () => {
 | |
|     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);
 | |
|   }
 | |
| 
 | |
|   handleMuteClick = () => {
 | |
|     this.props.onMute(this.props.status.get('account'));
 | |
|   }
 | |
| 
 | |
|   handleConversationMuteClick = () => {
 | |
|     this.props.onMuteConversation(this.props.status);
 | |
|   }
 | |
| 
 | |
|   handleBlockClick = () => {
 | |
|     this.props.onBlock(this.props.status.get('account'));
 | |
|   }
 | |
| 
 | |
|   handleReport = () => {
 | |
|     this.props.onReport(this.props.status);
 | |
|   }
 | |
| 
 | |
|   handlePinClick = () => {
 | |
|     this.props.onPin(this.props.status);
 | |
|   }
 | |
| 
 | |
|   handleShare = () => {
 | |
|     navigator.share({
 | |
|       text: this.props.status.get('search_index'),
 | |
|       url: this.props.status.get('url'),
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   handleEmbed = () => {
 | |
|     this.props.onEmbed(this.props.status);
 | |
|   }
 | |
| 
 | |
|   render () {
 | |
|     const { status, intl } = this.props;
 | |
| 
 | |
|     const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
 | |
|     const mutingConversation = status.get('muted');
 | |
| 
 | |
|     let menu = [];
 | |
| 
 | |
|     if (publicStatus) {
 | |
|       menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
 | |
|       menu.push(null);
 | |
|     }
 | |
| 
 | |
|     if (me === status.getIn(['account', 'id'])) {
 | |
|       if (publicStatus) {
 | |
|         menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
 | |
|       }
 | |
| 
 | |
|       menu.push(null);
 | |
|       menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
 | |
|       menu.push(null);
 | |
|       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 });
 | |
|       menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
 | |
|     }
 | |
| 
 | |
|     const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && (
 | |
|       <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShare} /></div>
 | |
|     );
 | |
| 
 | |
|     let reblogIcon = 'retweet';
 | |
|     if (status.get('visibility') === 'direct') reblogIcon = 'envelope';
 | |
|     else if (status.get('visibility') === 'private') reblogIcon = 'lock';
 | |
| 
 | |
|     let reblog_disabled = (status.get('visibility') === 'direct' || status.get('visibility') === 'private');
 | |
| 
 | |
|     return (
 | |
|       <div className='detailed-status__action-bar'>
 | |
|         <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_id', null) === null ? 'reply' : 'reply-all'} onClick={this.handleReplyClick} /></div>
 | |
|         <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>
 | |
|         <div className='detailed-status__button'><IconButton animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div>
 | |
|         {shareButton}
 | |
| 
 | |
|         <div className='detailed-status__action-bar-dropdown'>
 | |
|           <DropdownMenuContainer size={18} icon='ellipsis-h' items={menu} direction='left' title='More' />
 | |
|         </div>
 | |
|       </div>
 | |
|     );
 | |
|   }
 | |
| 
 | |
| }
 |