diff --git a/packages/component-user/server/resolvers.js b/packages/component-user/server/resolvers.js index 429336658f7c3ca2f646f66a83d12c35f6ec3d3e..f356534b151cd42131695ee28a160404c1db8969 100644 --- a/packages/component-user/server/resolvers.js +++ b/packages/component-user/server/resolvers.js @@ -2,48 +2,38 @@ const Notification = require('./notifications/notification') const { parseUserFromAdmin } = require('./user') +const { + editUser, + activateUser, + deactivateUser, + createUserAsAdmin, +} = require('./use-cases') + const resolvers = { Mutation: { async addUserAsAdmin(_, { input }, ctx) { - const reqUser = await ctx.connectors.User.fetchOne(ctx.user, ctx) - if (!reqUser.admin) { - throw new Error('Unauthorized') - } - - try { - const user = await ctx.connectors.User.create( - parseUserFromAdmin(input), + return createUserAsAdmin + .initialize({ ctx, - ) - const notification = new Notification(user) - await notification.notifyUserAddedByAdmin(input.role) - - return user - } catch (e) { - return e - } + Notification, + User: ctx.connectors.User, + }) + .execute({ input: parseUserFromAdmin(input) }) }, async editUserAsAdmin(_, { id, input }, ctx) { - try { - const user = await ctx.connectors.User.update( - id, - parseUserFromAdmin(input), - ctx, - ) - - return user - } catch (e) { - return e - } + return editUser + .initialize({ User: ctx.connectors.User, ctx }) + .execute({ id, input }) }, - async activateUserAsAdmin(_, { id, input }, ctx) { - try { - const user = await ctx.connectors.User.update(id, input, ctx) - - return user - } catch (e) { - return e + async toggleUserActiveStatusAsAdmin(_, { id, input }, ctx) { + if (input.isActive) { + return activateUser + .initialize({ User: ctx.connectors.User, ctx }) + .execute({ id, input }) } + return deactivateUser + .initialize({ User: ctx.connectors.User, ctx }) + .execute({ id, input }) }, }, } diff --git a/packages/component-user/server/typeDefs.js b/packages/component-user/server/typeDefs.js index b10f93aa670507a190294092a54a77732a7ffbe5..249a380d2e775f1911c69fe9d95f75cc0279dffe 100644 --- a/packages/component-user/server/typeDefs.js +++ b/packages/component-user/server/typeDefs.js @@ -20,7 +20,7 @@ module.exports = ` role: AllowedRole } - input ActivateUserInput { + input UserStatusInput { email: String! username: String! isActive: Boolean @@ -29,7 +29,7 @@ module.exports = ` extend type Mutation { addUserAsAdmin(input: UserInput!): User editUserAsAdmin(id: ID!, input: UserInput!): User - activateUserAsAdmin(id: ID!, input: ActivateUserInput): User + toggleUserActiveStatusAsAdmin(id: ID!, input: UserStatusInput): User } enum AllowedRole { diff --git a/packages/component-user/server/use-cases/activateUser.js b/packages/component-user/server/use-cases/activateUser.js new file mode 100644 index 0000000000000000000000000000000000000000..74256c6c944c15922345f378648d6fa5e35bf744 --- /dev/null +++ b/packages/component-user/server/use-cases/activateUser.js @@ -0,0 +1,6 @@ +module.exports.initialize = ({ User, ctx }) => ({ + execute: async ({ id, input }) => { + const username = input.username.replace('invalid***', '') + return User.update(id, { ...input, username }, ctx) + }, +}) diff --git a/packages/component-user/server/use-cases/createUserAsAdmin.js b/packages/component-user/server/use-cases/createUserAsAdmin.js new file mode 100644 index 0000000000000000000000000000000000000000..6a46215e4067744cd558983c6bd8aed3be95aacb --- /dev/null +++ b/packages/component-user/server/use-cases/createUserAsAdmin.js @@ -0,0 +1,14 @@ +module.exports.initialize = ({ User, Notification, ctx }) => ({ + execute: async ({ input }) => { + const { admin } = await User.fetchOne(ctx.user, ctx) + if (!admin) { + throw new Error('Unauthorized') + } + + const user = await User.create(input, ctx) + const notification = new Notification(user) + await notification.notifyUserAddedByAdmin(input.role) + + return user + }, +}) diff --git a/packages/component-user/server/use-cases/deactivateUser.js b/packages/component-user/server/use-cases/deactivateUser.js new file mode 100644 index 0000000000000000000000000000000000000000..02747935df34668c7887643131441b89c2129c35 --- /dev/null +++ b/packages/component-user/server/use-cases/deactivateUser.js @@ -0,0 +1,7 @@ +module.exports.initialize = ({ User, ctx }) => ({ + execute: async ({ id, input }) => { + const username = `invalid***${input.username}` + + return User.update(id, { ...input, username }, ctx) + }, +}) diff --git a/packages/component-user/server/use-cases/editUser.js b/packages/component-user/server/use-cases/editUser.js new file mode 100644 index 0000000000000000000000000000000000000000..fff98ac5cebd104c24f899fa92bebd847c7c10c4 --- /dev/null +++ b/packages/component-user/server/use-cases/editUser.js @@ -0,0 +1,3 @@ +module.exports.initialize = ({ User, ctx }) => ({ + execute: ({ id, input }) => User.update(id, input, ctx), +}) diff --git a/packages/component-user/server/use-cases/index.js b/packages/component-user/server/use-cases/index.js new file mode 100644 index 0000000000000000000000000000000000000000..00ff37cad94784492bb38a8579aab8d664feff9c --- /dev/null +++ b/packages/component-user/server/use-cases/index.js @@ -0,0 +1,11 @@ +const activateUser = require('./activateUser') +const deactivateUser = require('./deactivateUser') +const editUser = require('./editUser') +const createUserAsAdmin = require('./createUserAsAdmin') + +module.exports = { + editUser, + activateUser, + deactivateUser, + createUserAsAdmin, +} diff --git a/packages/component-user/server/user.js b/packages/component-user/server/user.js index 39eea7df484118cb31e9f308be00cef2d8be4b63..1ad3234a40b06d4497f4809bbf08fed308151790 100644 --- a/packages/component-user/server/user.js +++ b/packages/component-user/server/user.js @@ -17,6 +17,7 @@ module.exports = { return { ...omit(input, ['role']), ...roles, + isActive: true, isConfirmed: false, notifications: { email: { diff --git a/packages/components-faraday/src/components/Admin/AdminDashboard.js b/packages/components-faraday/src/components/Admin/AdminDashboard.js deleted file mode 100644 index f07b7c426db7ecf2156cb9bf2542ea133957b156..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/AdminDashboard.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { Fragment } from 'react' -import { H1 } from '@pubsweet/ui' -import { Row, IconCard } from 'pubsweet-component-faraday-ui' - -const AdminDashboard = ({ history }) => ( - <Fragment> - <H1 mt={2}>Admin dashboard</H1> - <Row justify="flex-start" mt={2}> - <IconCard - icon="users" - iconSize={6} - label="Users" - onClick={() => history.push('/admin/users')} - /> - </Row> - </Fragment> -) - -export default AdminDashboard diff --git a/packages/components-faraday/src/components/Admin/AdminRoute.js b/packages/components-faraday/src/components/Admin/AdminRoute.js deleted file mode 100644 index 4b95cac85c1e8f52f6384f7fad2c47d8d25c0cb1..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/AdminRoute.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react' -import { get } from 'lodash' -import { compose } from 'recompose' -import { connect } from 'react-redux' -import { Redirect, withRouter, Route } from 'react-router-dom' -import { AuthenticatedComponent } from 'pubsweet-client' - -const AdminRoute = ({ - currentUser, - redirectPath = '/', - component: Component, - ...rest -}) => { - const isAdmin = get(currentUser, 'user.admin') - return ( - <Route - {...rest} - render={props => ( - <AuthenticatedComponent> - {isAdmin ? <Component {...props} /> : <Redirect to="/" />} - </AuthenticatedComponent> - )} - /> - ) -} - -export default compose( - withRouter, - connect(state => ({ - currentUser: state.currentUser, - })), -)(AdminRoute) diff --git a/packages/components-faraday/src/components/Admin/AdminUserForm.js b/packages/components-faraday/src/components/Admin/AdminUserForm.js deleted file mode 100644 index 4a3c3bba4279e573b4f5cd34138b5607c47df2aa..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/AdminUserForm.js +++ /dev/null @@ -1,207 +0,0 @@ -import React, { Fragment } from 'react' -import { get } from 'lodash' -import { Formik } from 'formik' -import styled from 'styled-components' -import { th } from '@pubsweet/ui-toolkit' -import { required } from 'xpub-validators' -import { - H2, - Button, - Spinner, - TextField, - ValidatedFieldFormik, -} from '@pubsweet/ui' -import { compose, setDisplayName, withHandlers, withProps } from 'recompose' -import { - Row, - Item, - Text, - Label, - IconButton, - RowOverrideAlert, - ItemOverrideAlert, - ValidatedMenuField, - withRoles, - withFetching, - withCountries, -} from 'pubsweet-component-faraday-ui' - -const FormModal = ({ - roles, - title, - titles, - onClose, - onSubmit, - onConfirm, - countries, - isFetching, - fetchingError, - initialValues, - confirmText = 'OK', - cancelText = 'Cancel', -}) => ( - <Root> - <IconButton icon="x" onClick={onClose} right={5} secondary top={5} /> - <H2>{title}</H2> - <Formik - initialValues={initialValues} - onSubmit={onSubmit} - validate={values => { - const errors = {} - - if (get(values, 'email', '') === '') { - errors.email = 'Required' - } - - if (get(values, 'affiliation', '') === '') { - errors.affiliation = 'Required' - } - - return errors - }} - > - {({ handleSubmit, ...rest }) => ( - <Fragment> - <Row alignItems="baseline" mb={1} mt={1}> - <ItemOverrideAlert mr={1} vertical> - <Label required>Email</Label> - <ValidatedFieldFormik - component={TextField} - inline - name="email" - validate={[required]} - /> - </ItemOverrideAlert> - <ItemOverrideAlert ml={1} vertical> - <Label required>Role</Label> - <ValidatedMenuField name="role" options={roles} /> - </ItemOverrideAlert> - </Row> - - <Row mb={2}> - <Item mr={1} vertical> - <Label>First Name</Label> - <ValidatedFieldFormik - component={TextField} - inline - name="firstName" - /> - </Item> - <Item ml={1} vertical> - <Label>Last Name</Label> - <ValidatedFieldFormik - component={TextField} - inline - name="lastName" - /> - </Item> - </Row> - - <RowOverrideAlert alignItems="center" mb={2}> - <ItemOverrideAlert mr={1} vertical> - <Label>Title</Label> - <ValidatedMenuField name="title" options={titles} /> - </ItemOverrideAlert> - <ItemOverrideAlert ml={1} vertical> - <Label>Country</Label> - <ValidatedMenuField name="country" options={countries} /> - </ItemOverrideAlert> - </RowOverrideAlert> - - <Row mb={3}> - <Item vertical> - <Label required>Affiliation</Label> - <ValidatedFieldFormik - component={TextField} - inline - name="affiliation" - /> - </Item> - </Row> - - {fetchingError && ( - <Row mb={1}> - <Text error>{fetchingError}</Text> - </Row> - )} - - {isFetching ? ( - <Spinner /> - ) : ( - <Row> - <Button onClick={onClose}>Cancel</Button> - <Button onClick={handleSubmit} primary> - {confirmText} - </Button> - </Row> - )} - </Fragment> - )} - </Formik> - </Root> -) - -// #region FormHelpers -const setInitialRole = a => { - if (get(a, 'admin')) { - return 'admin' - } - if (get(a, 'handlingEditor')) { - return 'handlingEditor' - } - if (get(a, 'editorInChief')) { - return 'editorInChief' - } - return 'author' -} - -// #endregion - -export default compose( - withRoles, - withFetching, - withCountries, - withProps(({ user, edit }) => ({ - initialValues: { - ...user, - role: setInitialRole(user), - }, - confirmText: edit ? 'EDIT USER' : 'SAVE USER', - title: edit ? 'Edit User' : 'Add User', - })), - withHandlers({ - onSubmit: ({ onSubmit, ...props }) => (values, formProps) => { - if (typeof onSubmit === 'function') { - onSubmit(values, { formProps, props }) - } - }, - onClose: ({ onCancel, ...props }) => () => { - if (typeof onCancel === 'function') { - onCancel(props) - } - props.hideModal() - }, - }), - - setDisplayName('FormModal'), -)(FormModal) - -// #region styles -const Root = styled.div` - align-items: center; - background: ${th('colorBackgroundHue')}; - border: ${th('borderWidth')} ${th('borderStyle')} transparent; - border-radius: ${th('borderRadius')}; - box-shadow: ${th('boxShadow')}; - display: flex; - flex-direction: column; - position: relative; - padding: calc(${th('gridUnit')} * 3); - width: calc(${th('gridUnit')} * 60); - - ${H2} { - margin: 0; - text-align: center; - } -` -// #endregion diff --git a/packages/components-faraday/src/components/Admin/AdminUsers.js b/packages/components-faraday/src/components/Admin/AdminUsers.js deleted file mode 100644 index 1dfe97fac2b10463d037ef5b742f0edbdf279721..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/AdminUsers.js +++ /dev/null @@ -1,219 +0,0 @@ -import React, { Fragment } from 'react' -import { get } from 'lodash' -import { Button } from '@pubsweet/ui' -import styled from 'styled-components' -import { th } from '@pubsweet/ui-toolkit' -import { withJournal } from 'xpub-journal' -import { compose, withHandlers, withProps } from 'recompose' - -import { - Row, - Text, - Item, - Label, - OpenModal, - Pagination, - ActionLink, - handleError, - withPagination, -} from 'pubsweet-component-faraday-ui' - -import { updateUserStatus } from './utils' -import { OpenUserForm, withUsersGQL } from './' - -const Users = ({ - page, - users, - theme, - history, - journal, - getUsers, - isFetching, - getUserName, - getUserRoles, - itemsPerPage, - deactivateUser, - getStatusLabel, - paginatedItems, - toggleUserStatus, - // - addUser, - updateUser, - toggleUserActiveStatus, - ...rest -}) => ( - <Fragment> - <Row alignItems="center" justify="space-between" mb={1}> - <Item alignItems="center"> - <ActionLink - data-test-id="go-to-dashboard" - icon="arrow-left" - mr={2} - onClick={history.goBack} - > - Admin Dashboard - </ActionLink> - <OpenUserForm modalKey="addUser" onSubmit={addUser} /> - </Item> - - <Pagination {...rest} itemsPerPage={itemsPerPage} page={page} /> - </Row> - - <Table> - <thead> - <tr> - <th> - <Label>Full Name</Label> - </th> - <th colSpan={2}> - <Label>Email</Label> - </th> - <th> - <Label>Affiliation</Label> - </th> - <th> - <Label>Roles</Label> - </th> - <th> - <Label>Status</Label> - </th> - <th> </th> - </tr> - </thead> - <tbody> - {paginatedItems.map(user => ( - <UserRow key={user.id}> - <td> - <Text pl={1}>{getUserName(user)}</Text> - </td> - <td colSpan={2}> - <Text>{user.email}</Text> - </td> - <td> - <Text>{user.affiliation}</Text> - </td> - <td> - <Text customId>{getUserRoles(user)}</Text> - </td> - <td> - <Text secondary>{getStatusLabel(user)}</Text> - </td> - - <HiddenCell> - <Item alignItems="center" justify="flex-end"> - <OpenUserForm - edit - modalKey={`edit-${user.id}`} - onSubmit={updateUser} - user={user} - /> - <OpenModal - isFetching={isFetching} - modalKey={`deactivate-${user.id}`} - onConfirm={toggleUserActiveStatus(user)} - subtitle={`${user.firstName} ${user.lastName}`} - title={`Are you sure to ${ - !user.isActive ? 'activate' : 'deactivate' - } user?`} - > - {showModal => ( - <ActivateButton - ml={1} - mr={1} - onClick={showModal} - size="small" - > - {!user.isActive ? 'ACTIVATE' : 'DEACTIVATE'} - </ActivateButton> - )} - </OpenModal> - </Item> - </HiddenCell> - </UserRow> - ))} - </tbody> - </Table> - </Fragment> -) - -export default compose( - withJournal, - withUsersGQL, - withProps(({ journal: { roles = {} }, users }) => ({ - roles: Object.keys(roles), - items: users, - })), - withPagination, - withHandlers({ - getStatusLabel: () => ({ admin, isConfirmed, isActive = true }) => { - if (admin) return 'ACTIVE' - if (!isActive) { - return 'INACTIVE' - } - return isConfirmed ? 'ACTIVE' : 'INVITED' - }, - deactivateUser: ({ setFetching, getUsers }) => user => ({ - hideModal, - setModalError, - }) => { - setFetching(true) - updateUserStatus(user) - .then(() => { - setFetching(false) - getUsers() - hideModal() - }) - .catch(err => { - setFetching(false) - handleError(setModalError)(err) - }) - }, - getUserName: () => user => { - if (user.admin) { - return 'Admin' - } - return `${get(user, 'firstName', '')} ${get(user, 'lastName', '')}` - }, - getUserRoles: ({ journal: { roles = {} } }) => user => { - const parsedRoles = Object.entries(roles) - .reduce((acc, role) => (user[role[0]] ? [...acc, role[1]] : acc), []) - .join(', ') - - return parsedRoles || 'Author' - }, - }), -)(Users) - -// #region styled-components -const Table = styled.table` - border-collapse: collapse; - - & th, - & td { - border: none; - text-align: start; - vertical-align: middle; - height: calc(${th('gridUnit')} * 5); - } -` - -const HiddenCell = styled.td` - opacity: 0; -` - -const UserRow = styled.tr` - background-color: ${th('colorBackgroundHue2')}; - border-bottom: 1px solid ${th('colorBorder')}; - - &:hover { - background-color: ${th('colorBackgroundHue3')}; - - ${HiddenCell} { - opacity: 1; - } - } -` -const ActivateButton = styled(Button)` - width: 90px; -` -// #endregion diff --git a/packages/components-faraday/src/components/Admin/OpenUserForm.js b/packages/components-faraday/src/components/Admin/OpenUserForm.js deleted file mode 100644 index ae406374e15c9bb5b2696faf626c5d94c12a5820..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/OpenUserForm.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' - -import { - OpenModal, - ActionLink, - IconButton, -} from 'pubsweet-component-faraday-ui' - -import AdminUserForm from './AdminUserForm' - -const OpenUserForm = ({ edit, user, onSubmit, modalKey }) => ( - <OpenModal - component={AdminUserForm} - edit={edit} - modalKey={modalKey} - onSubmit={onSubmit} - user={user} - > - {showModal => - edit ? ( - <IconButton icon="edit-2" iconSize={2} onClick={showModal} pt={1 / 2} /> - ) : ( - <ActionLink icon="plus" onClick={showModal}> - ADD USER - </ActionLink> - ) - } - </OpenModal> -) - -export default OpenUserForm diff --git a/packages/components-faraday/src/components/Admin/index.js b/packages/components-faraday/src/components/Admin/index.js deleted file mode 100644 index 0bb7e9bedd5aa30878c77cf7bea2da6a179a7d31..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/index.js +++ /dev/null @@ -1,6 +0,0 @@ -export { default as withUsersGQL } from './withUsersGQL' - -export { default as AdminUsers } from './AdminUsers' -export { default as AdminRoute } from './AdminRoute' -export { default as OpenUserForm } from './OpenUserForm' -export { default as AdminDashboard } from './AdminDashboard' diff --git a/packages/components-faraday/src/components/Admin/utils.js b/packages/components-faraday/src/components/Admin/utils.js deleted file mode 100644 index 14835de252aa01e7e57419f3f28edbb8eca00136..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/utils.js +++ /dev/null @@ -1,86 +0,0 @@ -import { pick, omit, isBoolean, replace } from 'lodash' -import { update } from 'pubsweet-client/src/helpers/api' - -const generatePasswordHash = () => - Array.from({ length: 4 }, () => - Math.random() - .toString(36) - .slice(4), - ).join('') - -export const setAdmin = values => { - const newValues = { ...values, isActive: true } - if (newValues.roles && newValues.roles.includes('admin')) { - newValues.admin = true - } else { - newValues.admin = false - } - - return { - ...omit(newValues, ['role']), - username: newValues.email, - isConfirmed: false, - password: 'defaultpass', - editorInChief: newValues.role === 'editorInChief', - handlingEditor: newValues.role === 'handlingEditor', - notifications: { - email: { - system: true, - user: true, - }, - }, - accessTokens: { - passwordReset: generatePasswordHash(), - unsubscribe: generatePasswordHash(), - }, - } -} - -export const parseUpdateUser = values => { - const parsedValues = { - ...values, - editorInChief: values.editorInChief || false, - handlingEditor: values.handlingEditor || false, - admin: values.admin || false, - } - const valuesToSave = [ - 'admin', - 'firstName', - 'lastName', - 'affiliation', - 'title', - 'roles', - 'editorInChief', - 'handlingEditor', - 'isActive', - 'username', - 'country', - 'accessTokens', - ] - - return pick(parsedValues, valuesToSave) -} - -const toggleUserStatus = user => { - const { isActive, username } = user - let newState = true - let newUsername = '' - - if (!isBoolean(isActive) || isActive) { - newState = false - newUsername = `invalid***${username}` - } else { - newUsername = replace(username, 'invalid***', '') - } - - return { - ...user, - isActive: newState, - username: newUsername, - } -} - -export const updateUserStatus = user => { - const updatedUser = toggleUserStatus(user) - return update(`/users/${user.id}`, parseUpdateUser(updatedUser)) -} diff --git a/packages/components-faraday/src/components/Admin/withUsersGQL.js b/packages/components-faraday/src/components/Admin/withUsersGQL.js deleted file mode 100644 index 4ca7aeaf895e63cb3d9840751992106df899d8c1..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/withUsersGQL.js +++ /dev/null @@ -1,136 +0,0 @@ -import gql from 'graphql-tag' -import { graphql } from 'react-apollo' -import { compose, withHandlers, withProps } from 'recompose' - -const userFragment = gql` - fragment userDetails on User { - id - admin - email - title - country - username - lastName - isActive - firstName - affiliation - editorInChief - handlingEditor - } -` - -const getUsersQuery = gql` - { - users { - ...userDetails - } - } - ${userFragment} -` - -const addUserAsAdmin = gql` - mutation addUserAsAdmin($id: ID!, $input: UserInput!) { - addUserAsAdmin(id: $id, input: $input) { - ...userDetails - } - } - ${userFragment} -` - -const editUserAsAdmin = gql` - mutation editUserAsAdmin($id: ID!, $input: UserInput!) { - editUserAsAdmin(id: $id, input: $input) { - ...userDetails - } - } - ${userFragment} -` - -const activateUserAsAdmin = gql` - mutation activateUserAsAdmin($id: ID!, $input: ActivateUserInput) { - activateUserAsAdmin(id: $id, input: $input) { - ...userDetails - } - } - ${userFragment} -` - -export default compose( - graphql(getUsersQuery), - graphql(addUserAsAdmin, { - name: 'addUser', - options: { - refetchQueries: [{ query: getUsersQuery }], - }, - }), - graphql(editUserAsAdmin, { - name: 'updateUser', - }), - graphql(activateUserAsAdmin, { - name: 'activateUser', - }), - withHandlers({ - addUser: ({ addUser }) => ( - { __typename, id, admin, ...input }, - { props: { hideModal, setFetching } }, - ) => { - setFetching(true) - addUser({ - variables: { - id, - input: { - ...input, - username: input.email, - }, - }, - }).then(() => { - setFetching(false) - hideModal() - }) - }, - updateUser: ({ updateUser }) => ( - { __typename, id, admin, handlingEditor, editorInChief, ...input }, - { props: { hideModal, setFetching, setError } }, - ) => { - setFetching(true) - updateUser({ - variables: { - id, - input, - }, - }) - .then(() => { - setFetching(false) - hideModal() - }) - .catch(e => { - setFetching(false) - setError(e.message) - }) - }, - toggleUserActiveStatus: ({ activateUser }) => ({ - __typename, - admin, - handlingEditor, - editorInChief, - id, - email, - username, - isActive, - }) => ({ hideModal }) => { - activateUser({ - variables: { - id, - input: { - email, - username, - isActive, - }, - }, - }).then(hideModal) - }, - }), - withProps(({ data }) => ({ - users: data.users, - })), -)