diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index d8592bb5fc..cac2a9fb00 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -4,10 +4,10 @@ class Api::V1::ReactionDeckController < Api::BaseController include RoutingHelper before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index] - before_action -> { doorkeeper_authorize! :write, :'write:lists' }, only: [:create] + before_action -> { doorkeeper_authorize! :write, :'write:lists' }, only: [:create, :remove] before_action :require_user! - before_action :set_deck, only: [:index, :create] + before_action :set_deck, only: [:index, :create, :remove] rescue_from ArgumentError do |e| render json: { error: e.to_s }, status: 422 @@ -50,6 +50,14 @@ class Api::V1::ReactionDeckController < Api::BaseController render json: remove_metas(deck) end + def remove + deck = @deck.filter { |item| deck_params['emojis'].none? { |d| d['id'] == item['id'] } } + current_user.settings['reaction_deck'] = deck.to_json + current_user.save! + + render json: remove_metas(deck) + end + private def set_deck diff --git a/app/javascript/mastodon/actions/reaction_deck.js b/app/javascript/mastodon/actions/reaction_deck.js index 2914e8ceef..5b8be5d62f 100644 --- a/app/javascript/mastodon/actions/reaction_deck.js +++ b/app/javascript/mastodon/actions/reaction_deck.js @@ -8,6 +8,10 @@ export const REACTION_DECK_UPDATE_REQUEST = 'REACTION_DECK_UPDATE_REQUEST'; export const REACTION_DECK_UPDATE_SUCCESS = 'REACTION_DECK_UPDATE_SUCCESS'; export const REACTION_DECK_UPDATE_FAIL = 'REACTION_DECK_UPDATE_FAIL'; +export const REACTION_DECK_REMOVE_REQUEST = 'REACTION_DECK_REMOVE_REQUEST'; +export const REACTION_DECK_REMOVE_SUCCESS = 'REACTION_DECK_REMOVE_SUCCESS'; +export const REACTION_DECK_REMOVE_FAIL = 'REACTION_DECK_REMOVE_FAIL'; + export function fetchReactionDeck() { return (dispatch, getState) => { dispatch(fetchReactionDeckRequest()); @@ -77,3 +81,38 @@ export function updateReactionDeckFail(error) { skipLoading: true, }; } + +export function removeReactionDeck(id) { + return (dispatch, getState) => { + dispatch(removeReactionDeckRequest()); + + api(getState).post('/api/v1/remove_reaction_deck', { emojis: [{ id }] }).then(response => { + dispatch(removeReactionDeckSuccess(response.data)); + }).catch(error => { + dispatch(removeReactionDeckFail(error)); + }); + }; +} + +export function removeReactionDeckRequest() { + return { + type: REACTION_DECK_REMOVE_REQUEST, + skipLoading: true, + }; +} + +export function removeReactionDeckSuccess(emojis) { + return { + type: REACTION_DECK_REMOVE_SUCCESS, + emojis, + skipLoading: true, + }; +} + +export function removeReactionDeckFail(error) { + return { + type: REACTION_DECK_REMOVE_FAIL, + error, + skipLoading: true, + }; +} diff --git a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx index ac17e56876..dadcb1982e 100644 --- a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx +++ b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx @@ -1,17 +1,22 @@ import PropTypes from 'prop-types'; -import { injectIntl } from 'react-intl'; +import { defineMessages, injectIntl } from 'react-intl'; import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { updateReactionDeck } from 'mastodon/actions/reaction_deck'; +import { updateReactionDeck, removeReactionDeck } from 'mastodon/actions/reaction_deck'; +import Button from 'mastodon/components/button'; import EmojiPickerDropdownContainer from 'mastodon/features/compose/containers/emoji_picker_dropdown_container'; import emojify from 'mastodon/features/emoji/emoji'; import { autoPlayGif } from 'mastodon/initial_state'; +const messages = defineMessages({ + remove: { id: 'reaction_deck.remove', defaultMessage: 'Remove' }, +}); + const MapStateToProps = (state, { emojiId, emojiMap }) => ({ emoji: (state.get('reaction_deck', ImmutableList()).toArray().find(em => em.get('id') === emojiId) || ImmutableMap({ emoji: { shortcode: '' } })).get('name'), emojiMap, @@ -19,6 +24,7 @@ const MapStateToProps = (state, { emojiId, emojiMap }) => ({ const mapDispatchToProps = (dispatch, { emojiId }) => ({ onChange: (emoji) => dispatch(updateReactionDeck(emojiId, emoji)), + onRemove: () => dispatch(removeReactionDeck(emojiId)), }); class ReactionEmoji extends ImmutablePureComponent { @@ -27,6 +33,7 @@ class ReactionEmoji extends ImmutablePureComponent { emoji: PropTypes.string, emojiMap: ImmutablePropTypes.map.isRequired, onChange: PropTypes.func.isRequired, + onRemove: PropTypes.func.isRequired, }; static defaultProps = { @@ -34,7 +41,7 @@ class ReactionEmoji extends ImmutablePureComponent { }; render () { - const { emojiMap, emoji, onChange } = this.props; + const { intl, emojiMap, emoji, onChange, onRemove } = this.props; let content = null; @@ -61,9 +68,14 @@ class ReactionEmoji extends ImmutablePureComponent { return (