about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2018-03-29 21:13:47 +0200
committerThibaut Girka <thib@sitedethib.com>2018-05-16 19:45:30 +0200
commita5fac975f3951e954f8a1685150e716250a16a78 (patch)
tree2bc233c46141736b6e722dbd80c8aaee2ca1e03a
parent939ea456d28072592e44809636919fb03e967001 (diff)
[Glitch] Feature: Direct message from menu
Port d1f34151aee564bb1e60ee48107797681c869a81 to glitch-soc
-rw-r--r--app/javascript/flavours/glitch/actions/compose.js14
-rw-r--r--app/javascript/flavours/glitch/features/account/components/action_bar.js3
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/components/header.js6
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js13
-rw-r--r--app/javascript/flavours/glitch/features/composer/direct_warning/index.js49
-rw-r--r--app/javascript/flavours/glitch/features/composer/index.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/compose.js7
7 files changed, 93 insertions, 1 deletions
diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js
index 8a6ca3699..39381faa8 100644
--- a/app/javascript/flavours/glitch/actions/compose.js
+++ b/app/javascript/flavours/glitch/actions/compose.js
@@ -21,6 +21,7 @@ export const COMPOSE_SUBMIT_SUCCESS  = 'COMPOSE_SUBMIT_SUCCESS';
 export const COMPOSE_SUBMIT_FAIL     = 'COMPOSE_SUBMIT_FAIL';
 export const COMPOSE_REPLY           = 'COMPOSE_REPLY';
 export const COMPOSE_REPLY_CANCEL    = 'COMPOSE_REPLY_CANCEL';
+export const COMPOSE_DIRECT          = 'COMPOSE_DIRECT';
 export const COMPOSE_MENTION         = 'COMPOSE_MENTION';
 export const COMPOSE_RESET           = 'COMPOSE_RESET';
 export const COMPOSE_UPLOAD_REQUEST  = 'COMPOSE_UPLOAD_REQUEST';
@@ -102,6 +103,19 @@ export function mentionCompose(account, router) {
   };
 };
 
+export function directCompose(account, router) {
+  return (dispatch, getState) => {
+    dispatch({
+      type: COMPOSE_DIRECT,
+      account: account,
+    });
+
+    if (!getState().getIn(['compose', 'mounted'])) {
+      router.push('/statuses/new');
+    }
+  };
+};
+
 export function submitCompose() {
   return function (dispatch, getState) {
     let status = getState().getIn(['compose', 'text'], '');
diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js
index fb90722f3..8b95c08f2 100644
--- a/app/javascript/flavours/glitch/features/account/components/action_bar.js
+++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js
@@ -8,6 +8,7 @@ import { me } from 'flavours/glitch/util/initial_state';
 
 const messages = defineMessages({
   mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
+  direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' },
   edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
   unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
   unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
@@ -32,6 +33,7 @@ export default class ActionBar extends React.PureComponent {
     onFollow: PropTypes.func,
     onBlock: PropTypes.func.isRequired,
     onMention: PropTypes.func.isRequired,
+    onDirect: PropTypes.func.isRequired,
     onReblogToggle: PropTypes.func.isRequired,
     onReport: PropTypes.func.isRequired,
     onMute: PropTypes.func.isRequired,
@@ -53,6 +55,7 @@ export default class ActionBar extends React.PureComponent {
     let extraInfo = '';
 
     menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
+    menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.props.onDirect });
 
     if ('share' in navigator) {
       menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare });
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/header.js b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
index 39a1850d7..a1434b8dd 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/components/header.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
@@ -16,6 +16,7 @@ export default class Header extends ImmutablePureComponent {
     onFollow: PropTypes.func.isRequired,
     onBlock: PropTypes.func.isRequired,
     onMention: PropTypes.func.isRequired,
+    onDirect: PropTypes.func.isRequired,
     onReblogToggle: PropTypes.func.isRequired,
     onReport: PropTypes.func.isRequired,
     onMute: PropTypes.func.isRequired,
@@ -40,6 +41,10 @@ export default class Header extends ImmutablePureComponent {
     this.props.onMention(this.props.account, this.context.router.history);
   }
 
+  handleDirect = () => {
+    this.props.onDirect(this.props.account, this.context.router.history);
+  }
+
   handleReport = () => {
     this.props.onReport(this.props.account);
   }
@@ -89,6 +94,7 @@ export default class Header extends ImmutablePureComponent {
           account={account}
           onBlock={this.handleBlock}
           onMention={this.handleMention}
+          onDirect={this.handleDirect}
           onReblogToggle={this.handleReblogToggle}
           onReport={this.handleReport}
           onMute={this.handleMute}
diff --git a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
index 848119c63..fb0edfa88 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
@@ -9,7 +9,10 @@ import {
   unblockAccount,
   unmuteAccount,
 } from 'flavours/glitch/actions/accounts';
-import { mentionCompose } from 'flavours/glitch/actions/compose';
+import {
+  mentionCompose,
+  directCompose
+} from 'flavours/glitch/actions/compose';
 import { initMuteModal } from 'flavours/glitch/actions/mutes';
 import { initReport } from 'flavours/glitch/actions/reports';
 import { openModal } from 'flavours/glitch/actions/modal';
@@ -67,6 +70,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
     dispatch(mentionCompose(account, router));
   },
 
+  onDirect (account, router) {
+    dispatch(directCompose(account, router));
+  },
+
+  onDirect (account, router) {
+    dispatch(directCompose(account, router));
+  },
+
   onReblogToggle (account) {
     if (account.getIn(['relationship', 'showing_reblogs'])) {
       dispatch(followAccount(account.get('id'), false));
diff --git a/app/javascript/flavours/glitch/features/composer/direct_warning/index.js b/app/javascript/flavours/glitch/features/composer/direct_warning/index.js
new file mode 100644
index 000000000..947096aed
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/composer/direct_warning/index.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import Motion from 'flavours/glitch/util/optional_motion';
+import spring from 'react-motion/lib/spring';
+import { defineMessages, FormattedMessage } from 'react-intl';
+
+//  This is the spring used with our motion.
+const motionSpring = spring(1, { damping: 35, stiffness: 400 });
+
+//  Messages.
+const messages = defineMessages({
+  disclaimer: {
+    defaultMessage: 'This toot will only be visible to all the mentioned users.',
+    id: 'compose_form.direct_message_warning',
+  },
+});
+
+//  The component.
+export default function ComposerDirectWarning () {
+  return (
+    <Motion
+      defaultStyle={{
+        opacity: 0,
+        scaleX: 0.85,
+        scaleY: 0.75,
+      }}
+      style={{
+        opacity: motionSpring,
+        scaleX: motionSpring,
+        scaleY: motionSpring,
+      }}
+    >
+      {({ opacity, scaleX, scaleY }) => (
+        <div
+          className='composer--warning'
+          style={{
+            opacity: opacity,
+            transform: `scale(${scaleX}, ${scaleY})`,
+          }}
+        >
+          <FormattedMessage
+            {...messages.disclaimer}
+          />
+        </div>
+      )}
+    </Motion>
+  );
+}
+
+ComposerDirectWarning.propTypes = {};
diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js
index 3aa283628..de85340a3 100644
--- a/app/javascript/flavours/glitch/features/composer/index.js
+++ b/app/javascript/flavours/glitch/features/composer/index.js
@@ -39,6 +39,7 @@ import ComposerTextarea from './textarea';
 import ComposerUploadForm from './upload_form';
 import ComposerWarning from './warning';
 import ComposerHashtagWarning from './hashtag_warning';
+import ComposerDirectWarning from './direct_warning';
 
 //  Utils.
 import { countableText } from 'flavours/glitch/util/counter';
@@ -326,6 +327,7 @@ class Composer extends React.Component {
           onSubmit={handleSubmit}
           text={spoilerText}
         />
+        {privacy === 'direct' ? <ComposerDirectWarning /> : null}
         {privacy === 'private' && amUnlocked ? <ComposerWarning /> : null}
         {privacy !== 'public' && APPROX_HASHTAG_RE.test(text) ? <ComposerHashtagWarning /> : null}
         {replyContent ? (
diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js
index 8973c7713..68c7e11f1 100644
--- a/app/javascript/flavours/glitch/reducers/compose.js
+++ b/app/javascript/flavours/glitch/reducers/compose.js
@@ -5,6 +5,7 @@ import {
   COMPOSE_CYCLE_ELEFRIEND,
   COMPOSE_REPLY,
   COMPOSE_REPLY_CANCEL,
+  COMPOSE_DIRECT,
   COMPOSE_MENTION,
   COMPOSE_SUBMIT_REQUEST,
   COMPOSE_SUBMIT_SUCCESS,
@@ -325,6 +326,12 @@ export default function compose(state = initialState, action) {
       .update('text', text => `${text}@${action.account.get('acct')} `)
       .set('focusDate', new Date())
       .set('idempotencyKey', uuid());
+  case COMPOSE_DIRECT:
+    return state
+      .update('text', text => `${text}@${action.account.get('acct')} `)
+      .set('privacy', 'direct')
+      .set('focusDate', new Date())
+      .set('idempotencyKey', uuid());
   case COMPOSE_SUGGESTIONS_CLEAR:
     return state.update('suggestions', ImmutableList(), list => list.clear()).set('suggestion_token', null);
   case COMPOSE_SUGGESTIONS_READY: