diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js index 40a5744379..381276d9dc 100644 --- a/app/javascript/flavours/glitch/containers/status_container.js +++ b/app/javascript/flavours/glitch/containers/status_container.js @@ -45,10 +45,7 @@ import { showAlertForError } from '../actions/alerts'; import AccountContainer from 'flavours/glitch/containers/account_container'; import Spoilers from '../components/spoilers'; import Icon from 'flavours/glitch/components/icon'; -import { createSelector } from 'reselect'; -import { Map as ImmutableMap } from 'immutable'; - -const customEmojiMap = createSelector([state => state.get('custom_emojis')], items => items.reduce((map, emoji) => map.set(emoji.get('shortcode'), emoji), ImmutableMap())); +import buildCustomEmojiMap from '../utils/emoji_map'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -88,7 +85,7 @@ const makeMapStateToProps = () => { account: account || props.account, settings: state.get('local_settings'), prepend: prepend || props.prepend, - emojiMap: customEmojiMap(state), + emojiMap: buildCustomEmojiMap(state), pictureInPicture: { inUse: state.getIn(['meta', 'layout']) !== 'mobile' && state.get('picture_in_picture').statusId === props.id, diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index 7d2c2aace3..b2f38ff1ff 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -20,6 +20,7 @@ import Icon from 'flavours/glitch/components/icon'; import AnimatedNumber from 'flavours/glitch/components/animated_number'; import PictureInPicturePlaceholder from 'flavours/glitch/components/picture_in_picture_placeholder'; import EditedTimestamp from 'flavours/glitch/components/edited_timestamp'; +import StatusReactionsBar from '../../../components/status_reactions_bar'; export default @injectIntl class DetailedStatus extends ImmutablePureComponent { @@ -43,6 +44,9 @@ class DetailedStatus extends ImmutablePureComponent { showMedia: PropTypes.bool, usingPiP: PropTypes.bool, onToggleMediaVisibility: PropTypes.func, + onReactionAdd: PropTypes.func.isRequired, + onReactionRemove: PropTypes.func.isRequired, + emojiMap: ImmutablePropTypes.map.isRequired, intl: PropTypes.object.isRequired, }; @@ -319,6 +323,14 @@ class DetailedStatus extends ImmutablePureComponent { disabled /> + +
diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index c716e4f0f5..e94a47f0ee 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -20,6 +20,8 @@ import { unreblog, pin, unpin, + statusAddReaction, + statusRemoveReaction, } from 'flavours/glitch/actions/interactions'; import { replyCompose, @@ -56,6 +58,7 @@ import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning'; import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status'; import Icon from 'flavours/glitch/components/icon'; import { Helmet } from 'react-helmet'; +import buildCustomEmojiMap from '../../utils/emoji_map'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -146,6 +149,7 @@ const makeMapStateToProps = () => { askReplyConfirmation: state.getIn(['local_settings', 'confirm_before_clearing_draft']) && state.getIn(['compose', 'text']).trim().length !== 0, domain: state.getIn(['meta', 'domain']), usingPiP: state.get('picture_in_picture').statusId === props.params.statusId, + emojiMap: buildCustomEmojiMap(state), }; }; @@ -291,6 +295,30 @@ class Status extends ImmutablePureComponent { } } + handleReactionAdd = (statusId, name) => { + const { dispatch } = this.props; + const { signedIn } = this.context.identity; + + if (signedIn) { + dispatch(statusAddReaction(statusId, name)); + } else { + dispatch(openModal('INTERACTION', { + type: 'reaction_add', + accountId: status.getIn(['account', 'id']), + url: status.get('url'), + })); + } + } + + handleReactionRemove = (statusId, name) => { + const { dispatch } = this.props; + const { signedIn } = this.context.identity; + + if (signedIn) { + dispatch(statusRemoveReaction(statusId, name)); + } + } + handlePin = (status) => { if (status.get('pinned')) { this.props.dispatch(unpin(status)); @@ -676,6 +704,8 @@ class Status extends ImmutablePureComponent { settings={settings} onOpenVideo={this.handleOpenVideo} onOpenMedia={this.handleOpenMedia} + onReactionAdd={this.handleReactionAdd} + onReactionRemove={this.handleReactionRemove} expanded={isExpanded} onToggleHidden={this.handleToggleHidden} onTranslate={this.handleTranslate} @@ -683,6 +713,7 @@ class Status extends ImmutablePureComponent { showMedia={this.state.showMedia} onToggleMediaVisibility={this.handleToggleMediaVisibility} usingPiP={usingPiP} + emojiMap={this.props.emojiMap} /> state.get('custom_emojis')], + items => items.reduce( + (map, emoji) => map.set(emoji.get('shortcode'), emoji), + ImmutableMap(), + ), +); +export default buildCustomEmojiMap;