From e3d96073d70bc6be5cdaf3fe90cf6d3264c99509 Mon Sep 17 00:00:00 2001
From: Alexandru Munteanu <alexandru.munt@gmail.com>
Date: Tue, 17 Jul 2018 08:51:04 +0300
Subject: [PATCH] feat(email-subscriptions): subscribe and unsubscribe from
 emails

---
 packages/component-user-manager/src/Users.js  | 33 +++++++++++++++
 .../src/routes/users/subscriptions.js         | 22 ++++++++++
 .../components/UserProfile/AccountDetails.js  |  2 +-
 .../UserProfile/AccountDetailsCard.js         |  6 +--
 .../UserProfile/AccountDetailsEdit.js         |  2 +-
 .../UserProfile/EmailNotifications.js         | 41 +++++++++++++++++--
 .../components/UserProfile/UserProfilePage.js | 19 ++++++---
 .../components-faraday/src/redux/users.js     |  9 +++-
 packages/xpub-faraday/config/default.js       |  2 +-
 packages/xpub-faraday/config/validations.js   |  1 +
 10 files changed, 120 insertions(+), 17 deletions(-)
 create mode 100644 packages/component-user-manager/src/routes/users/subscriptions.js

diff --git a/packages/component-user-manager/src/Users.js b/packages/component-user-manager/src/Users.js
index 95d064990..8b95b8c82 100644
--- a/packages/component-user-manager/src/Users.js
+++ b/packages/component-user-manager/src/Users.js
@@ -125,6 +125,39 @@ const Users = app => {
     require('./routes/users/changePassword')(app.locals.models),
   )
 
+  /**
+   * @api {patch} /api/users/subscriptions Change user's email subscription flag
+   * @apiGroup Users
+   * @apiParamExample {json} Body
+   *    {
+   *      "isUnsubscribed": true,
+   *    }
+   * @apiSuccessExample {json} Success
+   *    HTTP/1.1 200 OK
+   *    {
+   *      "id": "a6184463-b17a-42f8-b02b-ae1d755cdc6b",
+   *      "type": "user",
+   *      "admin": false,
+   *      "email": "email@example.com",
+   *      "teams": [],
+   *      "username": "email@example.com",
+   *      "fragments": [],
+   *      "collections": [],
+   *      "isConfirmed": true,
+   *      "editorInChief": false,
+   *      "handlingEditor": false,
+   *      "isUnsubscribed": true
+   *    }
+   * @apiErrorExample {json} Reset password errors
+   *    HTTP/1.1 400 Bad Request
+   *    HTTP/1.1 404 Not Found
+   */
+  app.patch(
+    '/api/users/subscriptions',
+    authBearer,
+    require('./routes/users/subscriptions')(app.locals.models),
+  )
+
   // register ORCID authentication strategy
   orcidRoutes(app)
 }
diff --git a/packages/component-user-manager/src/routes/users/subscriptions.js b/packages/component-user-manager/src/routes/users/subscriptions.js
new file mode 100644
index 000000000..7633fc64b
--- /dev/null
+++ b/packages/component-user-manager/src/routes/users/subscriptions.js
@@ -0,0 +1,22 @@
+const { services } = require('pubsweet-component-helper-service')
+
+module.exports = models => async (req, res) => {
+  const { isUnsubscribed } = req.body
+
+  if (!services.checkForUndefinedParams(isUnsubscribed))
+    return res.status(400).json({ error: 'Missing required params.' })
+
+  let user
+  try {
+    user = await models.User.find(req.user)
+    user.isUnsubscribed = isUnsubscribed
+    user = await user.save()
+
+    return res.status(200).json({ user })
+  } catch (e) {
+    const notFoundError = await services.handleNotFoundError(e, 'User')
+    return res.status(notFoundError.status).json({
+      error: notFoundError.message,
+    })
+  }
+}
diff --git a/packages/components-faraday/src/components/UserProfile/AccountDetails.js b/packages/components-faraday/src/components/UserProfile/AccountDetails.js
index 768c8a46e..81080db09 100644
--- a/packages/components-faraday/src/components/UserProfile/AccountDetails.js
+++ b/packages/components-faraday/src/components/UserProfile/AccountDetails.js
@@ -29,7 +29,7 @@ export default compose(
   withJournal,
   withState('isEdit', 'setEdit', false),
   withHandlers({
-    setEditMode: ({ setEdit }) => value => setEdit(value),
+    setEditMode: ({ setEdit }) => value => () => setEdit(value),
   }),
 )(AccountDetails)
 
diff --git a/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js b/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js
index 22dadc2aa..7e085536a 100644
--- a/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js
+++ b/packages/components-faraday/src/components/UserProfile/AccountDetailsCard.js
@@ -3,10 +3,10 @@ import React, { Fragment } from 'react'
 import {
   Row,
   RowItem,
-  LabelHeader,
+  LinkText,
   LabelTitle,
+  LabelHeader,
   DefaultText,
-  LinkText,
 } from '../UIComponents/FormItems'
 import { getUserTitle } from '../utils'
 
@@ -48,7 +48,7 @@ const AccountDetailsCard = ({
     </Row>
     <Row noMargin>
       <RowItem>
-        <LinkText onClick={() => setEditMode(true)}>Edit details</LinkText>
+        <LinkText onClick={setEditMode(true)}>Edit details</LinkText>
         <LinkText onClick={() => history.push('/profile/change-password')}>
           Change Password
         </LinkText>
diff --git a/packages/components-faraday/src/components/UserProfile/AccountDetailsEdit.js b/packages/components-faraday/src/components/UserProfile/AccountDetailsEdit.js
index f247552c6..a88c42c6e 100644
--- a/packages/components-faraday/src/components/UserProfile/AccountDetailsEdit.js
+++ b/packages/components-faraday/src/components/UserProfile/AccountDetailsEdit.js
@@ -11,7 +11,7 @@ const AccountDetailsEdit = ({ journal, user, setEditMode, handleSubmit }) => (
   <Root onSubmit={handleSubmit}>
     <EditUserForm journal={journal} title="Edit account details" user={user} />
     <Row>
-      <Button onClick={() => setEditMode(false)}>Cancel</Button>
+      <Button onClick={setEditMode(false)}>Cancel</Button>
       <Button primary type="submit">
         Save
       </Button>
diff --git a/packages/components-faraday/src/components/UserProfile/EmailNotifications.js b/packages/components-faraday/src/components/UserProfile/EmailNotifications.js
index 853c24047..7f20c07ec 100644
--- a/packages/components-faraday/src/components/UserProfile/EmailNotifications.js
+++ b/packages/components-faraday/src/components/UserProfile/EmailNotifications.js
@@ -1,9 +1,14 @@
 import React from 'react'
 import styled from 'styled-components'
+import { compose, withHandlers } from 'recompose'
+import {
+  withModal,
+  ConfirmationModal,
+} from 'pubsweet-component-modal/src/components'
 
 import { Row, RowItem, LabelHeader, LinkText } from '../UIComponents/FormItems'
 
-const EmailNotifications = ({ subscribed = '' }) => (
+const EmailNotifications = ({ subscribed = '', subscribe, unsubscribe }) => (
   <Root>
     <Row noMargin>
       <RowItem>
@@ -13,20 +18,48 @@ const EmailNotifications = ({ subscribed = '' }) => (
     {!subscribed ? (
       <Row noMargin>
         <RowItem>
-          <LinkText>Re-subscribe</LinkText>
+          <LinkText onClick={subscribe}>Re-subscribe</LinkText>
         </RowItem>
       </Row>
     ) : (
       <Row noMargin>
         <RowItem>
-          <LinkText>Unsubscribe</LinkText>
+          <LinkText onClick={unsubscribe}>Unsubscribe</LinkText>
         </RowItem>
       </Row>
     )}
   </Root>
 )
 
-export default EmailNotifications
+export default compose(
+  withModal(props => ({
+    modalComponent: ConfirmationModal,
+  })),
+  withHandlers({
+    subscribe: ({ showModal, hideModal, changeEmailSubscription }) => () => {
+      showModal({
+        title: 'Subscribe to emails',
+        subtitle: 'Are you sure you want to subscribe to emails?',
+        onConfirm: () => {
+          changeEmailSubscription(false)
+          hideModal()
+        },
+        onCancel: hideModal,
+      })
+    },
+    unsubscribe: ({ showModal, hideModal, changeEmailSubscription }) => () => {
+      showModal({
+        title: 'Unsubscribe from emails',
+        subtitle: 'Are you sure you want to unsubscribe from emails?',
+        onConfirm: () => {
+          changeEmailSubscription(true)
+          hideModal()
+        },
+        onCancel: hideModal,
+      })
+    },
+  }),
+)(EmailNotifications)
 
 // #region styles
 const Root = styled.div`
diff --git a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js
index 462abc4c4..f45f86e3f 100644
--- a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js
+++ b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js
@@ -6,11 +6,12 @@ import styled from 'styled-components'
 import { selectCurrentUser } from 'xpub-selectors'
 import { BreadcrumbsHeader } from 'pubsweet-components-faraday/src/components'
 
-import AccountDetails from './AccountDetails'
 import LinkOrcID from './LinkOrcID'
+import AccountDetails from './AccountDetails'
 import EmailNotifications from './EmailNotifications'
+import { changeEmailSubscription } from '../../redux/users'
 
-const UserProfilePage = ({ history, user }) => (
+const UserProfilePage = ({ history, user, changeEmailSubscription }) => (
   <Root>
     <BreadcrumbsHeader
       history={history}
@@ -20,15 +21,21 @@ const UserProfilePage = ({ history, user }) => (
       underlined
     />
     <AccountDetails history={history} user={user} />
-    <EmailNotifications subscribed={get(user, 'subscription')} />
+    <EmailNotifications
+      changeEmailSubscription={changeEmailSubscription}
+      subscribed={!get(user, 'isUnsubscribed')}
+    />
     <LinkOrcID id={get(user, 'id')} orcid={get(user, 'orcid')} />
   </Root>
 )
 
 export default compose(
-  connect(state => ({
-    user: selectCurrentUser(state),
-  })),
+  connect(
+    state => ({
+      user: selectCurrentUser(state),
+    }),
+    { changeEmailSubscription },
+  ),
 )(UserProfilePage)
 
 // #region styles
diff --git a/packages/components-faraday/src/redux/users.js b/packages/components-faraday/src/redux/users.js
index a4e6d1a12..973675ef2 100644
--- a/packages/components-faraday/src/redux/users.js
+++ b/packages/components-faraday/src/redux/users.js
@@ -1,5 +1,6 @@
 import { get } from 'lodash'
-import { create } from 'pubsweet-client/src/helpers/api'
+import { actions } from 'pubsweet-client'
+import { create, update } from 'pubsweet-client/src/helpers/api'
 
 const LOGIN_SUCCESS = 'LOGIN_SUCCESS'
 
@@ -20,3 +21,9 @@ export const confirmUser = (userId, confirmationToken) => dispatch =>
     localStorage.setItem('token', user.token)
     return dispatch(loginSuccess(user))
   })
+
+export const changeEmailSubscription = isUnsubscribed => dispatch => {
+  update(`/users/subscriptions`, {
+    isUnsubscribed,
+  }).then(() => dispatch(actions.getCurrentUser()))
+}
diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js
index 522a8f83e..37367502a 100644
--- a/packages/xpub-faraday/config/default.js
+++ b/packages/xpub-faraday/config/default.js
@@ -46,7 +46,7 @@ module.exports = {
     API_ENDPOINT: '/api',
     baseUrl: process.env.CLIENT_BASE_URL || 'http://localhost:3000',
     'login-redirect': '/',
-    'redux-log': false,
+    'redux-log': true,
     theme: process.env.PUBSWEET_THEME,
   },
   orcid: {
diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js
index 61e603fe9..f8ca55e07 100644
--- a/packages/xpub-faraday/config/validations.js
+++ b/packages/xpub-faraday/config/validations.js
@@ -131,6 +131,7 @@ module.exports = {
     confirmationToken: Joi.string().allow(''),
     agreeTC: Joi.boolean(),
     isActive: Joi.boolean().default(true),
+    isUnsubscribed: Joi.boolean(),
   },
   team: {
     group: Joi.string(),
-- 
GitLab