diff --git a/app/javascript/mastodon/actions/interactions.js b/app/javascript/mastodon/actions/interactions.js index 920094d5e..ed0a74985 100644 --- a/app/javascript/mastodon/actions/interactions.js +++ b/app/javascript/mastodon/actions/interactions.js @@ -1,5 +1,6 @@ import api from '../api'; import { importFetchedAccounts, importFetchedStatus } from './importer'; +import { me } from '../initial_state'; export const REBLOG_REQUEST = 'REBLOG_REQUEST'; export const REBLOG_SUCCESS = 'REBLOG_SUCCESS'; @@ -552,7 +553,7 @@ export function emojiReactionFail(status, name, domain, url, static_url, error) }; const findMyEmojiReaction = (status) => { - return status.get('emoji_reactions').find(emoji_reaction => emoji_reaction.get('me') === true); + return status.get('emoji_reactioned') && status.get('emoji_reactions').find(emoji_reaction => emoji_reaction.get('account_ids').includes(me)); }; export function removeEmojiReaction(status) { diff --git a/app/javascript/mastodon/components/emoji_reactions_bar.js b/app/javascript/mastodon/components/emoji_reactions_bar.js index 7267d178c..c1280fabe 100644 --- a/app/javascript/mastodon/components/emoji_reactions_bar.js +++ b/app/javascript/mastodon/components/emoji_reactions_bar.js @@ -7,7 +7,7 @@ import Emoji from './emoji'; import unicodeMapping from 'mastodon/features/emoji/emoji_unicode_mapping_light'; import TransitionMotion from 'react-motion/lib/TransitionMotion'; import AnimatedNumber from 'mastodon/components/animated_number'; -import { reduceMotion } from 'mastodon/initial_state'; +import { reduceMotion, me } from 'mastodon/initial_state'; import spring from 'react-motion/lib/spring'; class EmojiReaction extends ImmutablePureComponent { @@ -15,6 +15,7 @@ class EmojiReaction extends ImmutablePureComponent { static propTypes = { status: ImmutablePropTypes.map.isRequired, emojiReaction: ImmutablePropTypes.map.isRequired, + myReaction: PropTypes.bool.isRequired, addEmojiReaction: PropTypes.func.isRequired, removeEmojiReaction: PropTypes.func.isRequired, emojiMap: ImmutablePropTypes.map.isRequired, @@ -26,9 +27,9 @@ class EmojiReaction extends ImmutablePureComponent { }; handleClick = () => { - const { emojiReaction, status, addEmojiReaction, removeEmojiReaction } = this.props; + const { emojiReaction, status, addEmojiReaction, removeEmojiReaction, myReaction } = this.props; - if (emojiReaction.get('me')) { + if (myReaction) { removeEmojiReaction(status); } else { addEmojiReaction(status, emojiReaction.get('name'), emojiReaction.get('domain', null), emojiReaction.get('url', null), emojiReaction.get('static_url', null)); @@ -40,7 +41,7 @@ class EmojiReaction extends ImmutablePureComponent { handleMouseLeave = () => this.setState({ hovered: false }) render () { - const { emojiReaction, status } = this.props; + const { emojiReaction, status, myReaction } = this.props; let shortCode = emojiReaction.get('name'); @@ -49,7 +50,7 @@ class EmojiReaction extends ImmutablePureComponent { } return ( - @@ -80,16 +81,23 @@ export default class EmojiReactionsBar extends ImmutablePureComponent { const emoji_reactions = status.get("emoji_reactions") const visibleReactions = emoji_reactions.filter(x => x.get('count') > 0); - const styles = visibleReactions.map(emoji_reaction => ({ - key: `${emoji_reaction.get('name')}@${emoji_reaction.get('domain', '')}`, - data: emoji_reaction, - style: { scale: reduceMotion ? 1 : spring(1, { stiffness: 150, damping: 13 }) }, - })).toArray(); - if (visibleReactions.isEmpty() ) { return ; } + const styles = visibleReactions.map(emoji_reaction => { + const domain = emoji_reaction.get('domain', ''); + + return { + key: `${emoji_reaction.get('name')}${domain ? `@${domain}` : ''}`, + data: { + emojiReaction: emoji_reaction, + myReaction: emoji_reaction.get('account_ids', []).includes(me), + }, + style: { scale: reduceMotion ? 1 : spring(1, { stiffness: 150, damping: 13 }) }, + }; + }).toArray(); + return ( {items => ( @@ -97,7 +105,8 @@ export default class EmojiReactionsBar extends ImmutablePureComponent { {items.map(({ key, data, style }) => ( ))} - {visibleReactions.size < 8} )} diff --git a/app/javascript/mastodon/reducers/statuses.js b/app/javascript/mastodon/reducers/statuses.js index fe842f2ea..032b0feb2 100644 --- a/app/javascript/mastodon/reducers/statuses.js +++ b/app/javascript/mastodon/reducers/statuses.js @@ -23,6 +23,7 @@ import { } from '../actions/statuses'; import { TIMELINE_DELETE } from '../actions/timelines'; import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer'; +import { me } from '../initial_state'; import { Map as ImmutableMap, fromJS } from 'immutable'; const importStatus = (state, status) => { @@ -55,15 +56,15 @@ const updateEmojiReaction = (state, id, name, domain, url, static_url, updater) return emojiReactions.update(idx, emojiReactions => updater(emojiReactions)); } - return emojiReactions.push(updater(fromJS({ name, domain, url, static_url, count: 0 }))); + return emojiReactions.push(updater(fromJS({ name, domain, url, static_url, count: 0, account_ids: [] }))); }); }); const updateEmojiReactionCount = (state, emojiReaction) => updateEmojiReaction(state, emojiReaction.status_id, emojiReaction.name, emojiReaction.domain, emojiReaction.url, emojiReaction.static_url, x => x.set('count', emojiReaction.count)); -const addEmojiReaction = (state, id, name, domain, url, static_url) => updateEmojiReaction(state, id, name, domain, url, static_url, x => x.set('me', true).update('count', y => y + 1)); +const addEmojiReaction = (state, id, name, domain, url, static_url) => updateEmojiReaction(state, id, name, domain, url, static_url, x => x.update('count', y => y + 1).update('account_ids', z => z.push(me))); -const removeEmojiReaction = (state, id, name, domain, url, static_url) => updateEmojiReaction(state, id, name, domain, url, static_url, x => x.set('me', false).update('count', y => y - 1)); +const removeEmojiReaction = (state, id, name, domain, url, static_url) => updateEmojiReaction(state, id, name, domain, url, static_url, x => x.update('count', y => y - 1).update('account_ids', z => z.deleteIn([me]))); const initialState = ImmutableMap(); diff --git a/app/models/status.rb b/app/models/status.rb index 375fc5f54..60bdc3b44 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -311,7 +311,7 @@ class Status < ApplicationRecord def generate_grouped_emoji_reactions records = emoji_reactions.group(:status_id, :name, :custom_emoji_id).order(Arel.sql('MIN(created_at) ASC')).select('name, custom_emoji_id, count(*) as count, array_agg(account_id::text order by created_at) as account_ids') - ActiveModelSerializers::SerializableResource.new(records, each_serializer: REST::EmojiReactionSerializer, scope: nil, scope_name: :current_user).to_json + Oj.dump(ActiveModelSerializers::SerializableResource.new(records, each_serializer: REST::EmojiReactionSerializer, scope: nil, scope_name: :current_user)) end def refresh_grouped_emoji_reactions!