about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/javascript/glitch/components/status/container.js11
-rw-r--r--app/javascript/mastodon/actions/accounts.js4
-rw-r--r--app/javascript/mastodon/actions/mutes.js21
-rw-r--r--app/javascript/mastodon/features/ui/components/modal_root.js2
-rw-r--r--app/javascript/mastodon/features/ui/components/mute_modal.js98
-rw-r--r--app/javascript/mastodon/features/ui/util/async-components.js4
-rw-r--r--app/javascript/mastodon/reducers/index.js2
-rw-r--r--app/javascript/mastodon/reducers/mutes.js29
-rw-r--r--app/javascript/styles/components.scss11
9 files changed, 168 insertions, 14 deletions
diff --git a/app/javascript/glitch/components/status/container.js b/app/javascript/glitch/components/status/container.js
index 1d572e0e7..6e49081b7 100644
--- a/app/javascript/glitch/components/status/container.js
+++ b/app/javascript/glitch/components/status/container.js
@@ -43,6 +43,7 @@ import {
   blockAccount,
   muteAccount,
 } from '../../../mastodon/actions/accounts';
+import { initMuteModal } from '../../../mastodon/actions/mutes';
 import {
   muteStatus,
   unmuteStatus,
@@ -80,10 +81,6 @@ const messages = defineMessages({
     id             : 'confirmations.block.confirm',
     defaultMessage : 'Block',
   },
-  muteConfirm : {
-    id             : 'confirmations.mute.confirm',
-    defaultMessage : 'Mute',
-  },
 });
 
                             /* * * * */
@@ -230,11 +227,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
   },
 
   onMute (account) {
-    dispatch(openModal('CONFIRM', {
-      message: <FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-      confirm: intl.formatMessage(messages.muteConfirm),
-      onConfirm: () => dispatch(muteAccount(account.get('id'))),
-    }));
+    dispatch(initMuteModal(account));
   },
 
   onMuteConversation (status) {
diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js
index 03e3d3d9f..fc47110e3 100644
--- a/app/javascript/mastodon/actions/accounts.js
+++ b/app/javascript/mastodon/actions/accounts.js
@@ -240,11 +240,11 @@ export function unblockAccountFail(error) {
 };
 
 
-export function muteAccount(id) {
+export function muteAccount(id, notifications) {
   return (dispatch, getState) => {
     dispatch(muteAccountRequest(id));
 
-    api(getState).post(`/api/v1/accounts/${id}/mute`).then(response => {
+    api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications }).then(response => {
       // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
       dispatch(muteAccountSuccess(response.data, getState().get('statuses')));
     }).catch(error => {
diff --git a/app/javascript/mastodon/actions/mutes.js b/app/javascript/mastodon/actions/mutes.js
index febda7219..3474250fe 100644
--- a/app/javascript/mastodon/actions/mutes.js
+++ b/app/javascript/mastodon/actions/mutes.js
@@ -1,5 +1,6 @@
 import api, { getLinks } from '../api';
 import { fetchRelationships } from './accounts';
+import { openModal } from '../../mastodon/actions/modal';
 
 export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
 export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
@@ -9,6 +10,9 @@ export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST';
 export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';
 export const MUTES_EXPAND_FAIL    = 'MUTES_EXPAND_FAIL';
 
+export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';
+export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';
+
 export function fetchMutes() {
   return (dispatch, getState) => {
     dispatch(fetchMutesRequest());
@@ -80,3 +84,20 @@ export function expandMutesFail(error) {
     error,
   };
 };
+
+export function initMuteModal(account) {
+  return dispatch => {
+    dispatch({
+      type: MUTES_INIT_MODAL,
+      account,
+    });
+
+    dispatch(openModal('MUTE'));
+  };
+}
+
+export function toggleHideNotifications() {
+  return dispatch => {
+    dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS });
+  };
+}
\ No newline at end of file
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js
index 4588cd5fd..6347c4b22 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.js
+++ b/app/javascript/mastodon/features/ui/components/modal_root.js
@@ -12,6 +12,7 @@ import BoostModal from './boost_modal';
 import ConfirmationModal from './confirmation_modal';
 import {
   OnboardingModal,
+  MuteModal,
   ReportModal,
   SettingsModal,
   EmbedModal,
@@ -23,6 +24,7 @@ const MODAL_COMPONENTS = {
   'VIDEO': () => Promise.resolve({ default: VideoModal }),
   'BOOST': () => Promise.resolve({ default: BoostModal }),
   'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
+  'MUTE': MuteModal,
   'REPORT': ReportModal,
   'SETTINGS': SettingsModal,
   'ACTIONS': () => Promise.resolve({ default: ActionsModal }),
diff --git a/app/javascript/mastodon/features/ui/components/mute_modal.js b/app/javascript/mastodon/features/ui/components/mute_modal.js
new file mode 100644
index 000000000..51a2d70e0
--- /dev/null
+++ b/app/javascript/mastodon/features/ui/components/mute_modal.js
@@ -0,0 +1,98 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { injectIntl, FormattedMessage } from 'react-intl';
+import Button from '../../../components/button';
+import { closeModal } from '../../../actions/modal';
+import { muteAccount } from '../../../actions/accounts';
+import { toggleHideNotifications } from '../../../actions/mutes';
+
+
+const mapStateToProps = state => {
+  return {
+    isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
+    account: state.getIn(['mutes', 'new', 'account']),
+    notifications: state.getIn(['mutes', 'new', 'notifications']),
+  };
+};
+
+const mapDispatchToProps = dispatch => {
+  return {
+    onConfirm(account, notifications) {
+      dispatch(muteAccount(account.get('id'), notifications))
+    },
+
+    onClose() {
+      dispatch(closeModal());
+    },
+
+    onToggleNotifications() {
+      dispatch(toggleHideNotifications());
+    },
+  };
+};
+
+@connect(mapStateToProps, mapDispatchToProps)
+@injectIntl
+export default class MuteModal extends React.PureComponent {
+  static propTypes = {
+    isSubmitting: PropTypes.bool.isRequired,
+    account: PropTypes.object.isRequired,
+    notifications: PropTypes.bool.isRequired,
+    onClose: PropTypes.func.isRequired,
+    onConfirm: PropTypes.func.isRequired,
+    onToggleNotifications: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
+  };
+
+  componentDidMount() {
+    this.button.focus();
+  }
+
+  handleClick = () => {
+    this.props.onClose();
+    this.props.onConfirm(this.props.account, this.props.notifications);
+  }
+
+  handleCancel = () => {
+    this.props.onClose();
+  }
+
+  setRef = (c) => {
+    this.button = c;
+  }
+
+  toggleNotifications = () => {
+    this.props.onToggleNotifications();
+  }
+
+  render () {
+    const { account, notifications } = this.props;
+
+    return (
+      <div className='modal-root__modal mute-modal'>
+        <div className='mute-modal__container'>
+          <p>
+            <FormattedMessage id='confirmations.mute.message'
+              defaultMessage='Are you sure you want to mute {name}?'
+              values={{ name: <strong>@{account.get('acct')}</strong> }}
+            />
+          </p>
+          <p>
+            <FormattedMessage id='mute_modal.hide_notifications' defaultMessage='Hide notifications from this user?' />
+            <input type="checkbox" checked={notifications} onChange={this.toggleNotifications} />
+          </p>
+        </div>
+
+        <div className='mute-modal__action-bar'>
+          <Button onClick={this.handleCancel} className='mute-modal__cancel-button'>
+            <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
+          </Button>
+          <Button onClick={this.handleClick} ref={this.setRef}>
+            <FormattedMessage id='confirmations.mute.confirm' defaultMessage='Mute' />
+          </Button>
+        </div>
+      </div>
+    );
+  }
+}
\ No newline at end of file
diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js
index 219b8192b..2f5c52e9e 100644
--- a/app/javascript/mastodon/features/ui/util/async-components.js
+++ b/app/javascript/mastodon/features/ui/util/async-components.js
@@ -86,6 +86,10 @@ export function OnboardingModal () {
   return import(/* webpackChunkName: "modals/onboarding_modal" */'../components/onboarding_modal');
 }
 
+export function MuteModal () {
+  return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
+}
+
 export function ReportModal () {
   return import(/* webpackChunkName: "modals/report_modal" */'../components/report_modal');
 }
diff --git a/app/javascript/mastodon/reducers/index.js b/app/javascript/mastodon/reducers/index.js
index 86cda2adc..a54fca530 100644
--- a/app/javascript/mastodon/reducers/index.js
+++ b/app/javascript/mastodon/reducers/index.js
@@ -14,6 +14,7 @@ import local_settings from '../../glitch/reducers/local_settings';
 import push_notifications from './push_notifications';
 import status_lists from './status_lists';
 import cards from './cards';
+import mutes from './mutes';
 import reports from './reports';
 import contexts from './contexts';
 import compose from './compose';
@@ -37,6 +38,7 @@ const reducers = {
   local_settings,
   push_notifications,
   cards,
+  mutes,
   reports,
   contexts,
   compose,
diff --git a/app/javascript/mastodon/reducers/mutes.js b/app/javascript/mastodon/reducers/mutes.js
new file mode 100644
index 000000000..6d6a9a3b8
--- /dev/null
+++ b/app/javascript/mastodon/reducers/mutes.js
@@ -0,0 +1,29 @@
+import Immutable from 'immutable';
+
+import {
+	MUTES_INIT_MODAL,
+	MUTES_TOGGLE_HIDE_NOTIFICATIONS,
+} from '../actions/mutes';
+
+const initialState = Immutable.Map({
+	new: Immutable.Map({
+		isSubmitting: false,
+		account: null,
+		notifications: true,
+	}),
+});
+
+export default function mutes(state = initialState, action) {
+	switch (action.type) {
+	case MUTES_INIT_MODAL:
+		return state.withMutations((state) => {
+			state.setIn(['new', 'isSubmitting'], false);
+			state.setIn(['new', 'account'], action.account);
+			state.setIn(['new', 'notifications'], true);
+		});
+	case MUTES_TOGGLE_HIDE_NOTIFICATIONS:
+		return state.setIn(['new', 'notifications'], !state.getIn(['new', 'notifications']));
+	default:
+		return state;
+	}
+}
\ No newline at end of file
diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss
index 16a87fcd8..6c29663f9 100644
--- a/app/javascript/styles/components.scss
+++ b/app/javascript/styles/components.scss
@@ -3879,7 +3879,8 @@ button.icon-button.active i.fa-retweet {
 .boost-modal,
 .confirmation-modal,
 .report-modal,
-.actions-modal {
+.actions-modal,
+.mute-modal {
   background: lighten($ui-secondary-color, 8%);
   color: $ui-base-color;
   border-radius: 8px;
@@ -3925,6 +3926,7 @@ button.icon-button.active i.fa-retweet {
 
 .boost-modal__action-bar,
 .confirmation-modal__action-bar,
+.mute-modal__action-bar,
 .report-modal__action-bar {
   display: flex;
   justify-content: space-between;
@@ -4020,8 +4022,10 @@ button.icon-button.active i.fa-retweet {
   }
 }
 
-.confirmation-modal__action-bar {
-  .confirmation-modal__cancel-button {
+.confirmation-modal__action-bar,
+.mute-modal__action-bar {
+  .confirmation-modal__cancel-button,
+  .mute-modal__cancel-button {
     background-color: transparent;
     color: darken($ui-secondary-color, 34%);
     font-size: 14px;
@@ -4036,6 +4040,7 @@ button.icon-button.active i.fa-retweet {
 }
 
 .confirmation-modal__container,
+.mute-modal__container,
 .report-modal__target {
   padding: 30px;
   font-size: 16px;