Commit 6ee05fd1 authored by Nikos Marinos's avatar Nikos Marinos

Merge remote-tracking branch 'origin/dev' into dev

parents 41e50c48 b9154f92
Pipeline #12970 passed with stages
in 5 minutes and 42 seconds
......@@ -2,9 +2,10 @@ import React from 'react'
import { ApolloConsumer } from 'react-apollo'
import styled from 'styled-components'
import { th } from '@pubsweet/ui-toolkit'
import { TextField, RadioGroup, ErrorText, H2, H3 } from '@pubsweet/ui'
import { LoadingIcon, Notification } from '../ui'
import { Action, TextField, RadioGroup, ErrorText, H2, H3 } from '@pubsweet/ui'
import { LoadingIcon, Notification, Toggle } from './ui'
import { GET_USER } from './operations'
import UserIdSearch from './UserIdSearch'
const Joi = require('joi')
......@@ -23,13 +24,21 @@ const NewReviewerForm = styled.div`
display: flex;
align-items: flex-start;
flex-wrap: wrap;
margin-bottom: calc(${th('gridUnit')} * 2);
& > * {
padding: 0 calc(${th('gridUnit')} * 2);
width: calc(${th('gridUnit')} * 42);
}
button {
font-size: ${th('fontSizeBaseSmall')};
}
`
const SearchArea = styled.div`
padding: 0 calc(${th('gridUnit')} * 2);
`
class SelectReviewer extends React.Component {
state = {
showToggle: false,
newFormDisabled: true,
loading: true,
options: [],
......@@ -121,6 +130,7 @@ class SelectReviewer extends React.Component {
surname: selectedReviewer.name.surname,
email: selectedReviewer.email,
newFormDisabled: false,
showToggle: true,
}
}
}
......@@ -143,10 +153,17 @@ class SelectReviewer extends React.Component {
surname,
email,
newFormDisabled,
showToggle,
options,
loading,
} = this.state
const { funding, reviewer, reviewerNote, submitter } = this.props
const {
currentUser,
funding,
reviewer,
reviewerNote,
submitter,
} = this.props
return (
<ApolloConsumer>
{client => {
......@@ -196,12 +213,15 @@ class SelectReviewer extends React.Component {
}
const setReviewer = async value => {
if (value === 'new') {
this.setState({ newFormDisabled: false }, () => {
this.nameInput.querySelector('input').focus()
})
this.setState(
{ showToggle: true, newFormDisabled: false },
() => {
this.nameInput.querySelector('input').focus()
},
)
} else {
const newReviewer = {}
this.setState({ newFormDisabled: true })
this.setState({ showToggle: false, newFormDisabled: true })
if (value === 'reviewer') {
if (reviewerNote) {
this.props.setReviewerNote('delete')
......@@ -231,6 +251,21 @@ class SelectReviewer extends React.Component {
}
}
}
const setReviewerWithId = user => {
const { name, email } = user.identities[0]
const newReviewer = {
id: user.id,
name,
email,
}
this.props.setReviewerNote(newReviewer)
this.setState({
name: name.givenNames,
surname: name.surname,
email,
newFormDisabled: false,
})
}
return (
<div>
<H2>Reviewer</H2>
......@@ -257,6 +292,36 @@ class SelectReviewer extends React.Component {
options={options}
value={selected}
/>
{currentUser.admin && showToggle && (
<NewReviewerForm>
<Toggle>
<Action
className={!newFormDisabled && 'current'}
onClick={() =>
this.setState({ newFormDisabled: false })
}
>
Enter new
</Action>
<Action
className={newFormDisabled && 'current'}
onClick={() =>
this.setState({ newFormDisabled: true })
}
>
Enter ID
</Action>
</Toggle>
</NewReviewerForm>
)}
{showToggle && newFormDisabled && (
<SearchArea>
<UserIdSearch
success={user => setReviewerWithId(user)}
successLabel="Select"
/>
</SearchArea>
)}
{!newFormDisabled && (
<NewReviewerForm>
<div ref={this.setNameRef}>
......
import React from 'react'
import styled from 'styled-components'
import { th } from '@pubsweet/ui-toolkit'
import { Button, Link } from '@pubsweet/ui'
import { withApollo } from 'react-apollo'
import { SearchForm as Search, Notification } from './ui'
import { GET_USER_ID } from './operations'
const Result = styled.div`
border: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')};
background-color: ${th('colorBackgroundHue')};
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
& > * {
margin: ${th('gridUnit')};
}
a {
min-width: 310px;
}
button:first-child {
margin-right: ${th('gridUnit')};
}
@media screen and (max-width: 733px) {
span {
display: block;
}
}
`
const SearchForm = styled(Search)`
max-width: 400px;
`
class UserIdSearch extends React.Component {
state = {
query: '',
result: null,
error: null,
}
onSearch(searchForm, e) {
e.preventDefault()
this.setState({
result: null,
error: null,
})
const options = {
query: GET_USER_ID,
variables: { id: this.state.query },
}
this.props.client
.query(options)
.then(response => this.setState({ result: response.data.epmc_user }))
.catch(e => {
const error = e.graphQLErrors
? 'Please enter a valid existing ID'
: 'Error occured. please try again'
this.setState({ error })
})
}
render() {
const { result, query } = this.state
const { name, email } = (result && result.identities[0]) || ''
const { title, givenNames, surname } = name || ''
return (
<React.Fragment>
{this.state.error && (
<Notification type="error">{this.state.error}</Notification>
)}
{!result && (
<SearchForm
name="searchById"
noButton="true"
onChange={e => this.setState({ query: e.target.value.trim() })}
onSubmit={e => this.onSearch('usersById', e)}
placeholder="Enter account ID"
value={query}
/>
)}
{result && (
<Result>
<Link to={`/manage-account/${result.id}`}>
<span>{result.id}</span>
</Link>
<span>{`${title ? `${title} ` : ''}${givenNames} ${surname}`}</span>
<span>{email}</span>
<div>
<Button onClick={() => this.props.success(result)} primary>
{this.props.successLabel}
</Button>
<Button onClick={() => this.setState({ result: null })}>
Cancel
</Button>
</div>
</Result>
)}
</React.Fragment>
)
}
}
export default withApollo(UserIdSearch)
import React from 'react'
import styled from 'styled-components'
import { th } from '@pubsweet/ui-toolkit'
import { Link, Icon } from '@pubsweet/ui'
import { withApollo } from 'react-apollo'
import {
SearchForm,
ZebraList,
ZebraListItem,
ConfirmDialog,
Notification,
} from '../ui/'
import { GET_USER } from './queries'
import { ConfirmDialog, Notification } from '../ui/'
import UserIdSearch from '../UserIdSearch'
import { MERGE_USER } from './mutations'
const SearchArea = styled.div`
float: right;
width: 100%;
margin-bottom: calc(${th('gridUnit')} * 2);
form {
display: inline-block;
width: calc(${th('gridUnit')} * 45);
div:first-child {
margin-bottom: 0;
}
button {
top: 8px;
}
}
.separator {
margin-right: 16px;
margin-left: 16px;
font-size: 16px;
}
@media screen and (max-width: 733px) {
float: none;
form {
display: block;
margin-left: 0 !important;
margin-bottom: calc(${th('gridUnit')} * 2);
width: 100% !important;
}
}
`
const ListItem = styled(ZebraListItem)`
display: flex;
align-items: top;
justify-content: space-between;
div > span {
margin: 8px;
width: 200px;
display: inline-flex;
}
a {
width: 300px;
margin: 4px;
}
@media screen and (max-width: 733px) {
span {
display: block;
}
}
`
class MergeAccount extends React.Component {
constructor(props) {
super(props)
this.state = {
searchById: props.searchById ? props.searchById : '',
results: [],
isOpen: false,
}
this.onSearchValChanged = this.onSearchValChanged.bind(this)
this.onSearchValSubmitted = this.onSearchValSubmitted.bind(this)
}
toggleMerge = () => {
const { isOpen, searchById, success, error, results } = this.state
this.setState({
isOpen: !isOpen,
searchById,
results,
success,
error,
})
state = {
isOpen: false,
mergeId: null,
success: null,
error: null,
}
mergeAccount = input => {
const { isOpen } = this.state
if (!input) {
this.toggleMerge()
this.setState({ isOpen: !isOpen })
return
}
this.setState({
results: [],
success: '',
error: '',
})
......@@ -96,7 +25,7 @@ class MergeAccount extends React.Component {
mutation: MERGE_USER,
variables: {
input: {
from: this.state.results[0].id,
from: this.state.mergeId,
to: this.props.user.id,
},
},
......@@ -105,114 +34,41 @@ class MergeAccount extends React.Component {
.mutate(options)
.then(response => {
if (response.data.mergeUser) {
this.setState({ success: 'Account has been merged successfully!' })
this.setState({
success: 'Account has been merged successfully!',
isOpen: !isOpen,
})
} else {
this.setState({ error: 'Error occured. please try again' })
this.setState({
error: 'Error occured. please try again',
isOpen: !isOpen,
})
}
this.toggleMerge()
})
.catch(e => {
this.setState({ error: 'Error occured. please try again' })
this.toggleMerge()
this.setState({
error: 'Error occured. please try again',
isOpen: !isOpen,
})
})
}
onSearchValSubmitted(searchForm, e) {
e.preventDefault()
this.setState({
results: [],
success: '',
error: '',
})
const options = {
query: GET_USER,
variables: { id: this.state.searchById },
}
this.props.client
.query(options)
.then(response => this.setState({ results: [response.data.epmc_user] }))
.catch(e => {
const error = e.graphQLErrors
? 'Please enter a valid existing ID'
: 'Error occured. please try again'
this.setState({ error })
})
}
onSearchValChanged(e) {
this.setState({ [e.target.name]: e.target.value })
}
render() {
const { searchById, results } = this.state
const cancelResult = () => {
this.state.results = []
}
const { isOpen, success, error } = this.state
const merge = async input => {
this.mergeAccount(input)
}
return (
<div>
{this.state.success && (
<Notification type="success"> {this.state.success} </Notification>
)}
{this.state.error && (
<Notification type="error">{this.state.error}</Notification>
)}
{!this.state.results.length && (
<SearchArea>
<SearchForm
name="searchById"
noButton="true"
onChange={this.onSearchValChanged}
onSubmit={e => this.onSearchValSubmitted('usersById', e)}
placeholder="Enter account ID"
value={searchById}
/>
</SearchArea>
)}
<ZebraList>
{results.map(user => {
let localIdentity = user.identities.filter(
identity => identity.type === 'local' || identity.type === 'ftp',
)[0]
if (!localIdentity) {
;[localIdentity] = user.identities
}
return (
<ListItem key={user.id}>
<div>
<Link to={`/manage-account/${user.id}`}>
<span>{user.id}</span>
</Link>
<span>
{`
${
localIdentity.name.title ? localIdentity.name.title : ''
}
${localIdentity.name.givenNames}
${localIdentity.name.surname}
`}
</span>
<span>{localIdentity.email}</span>
<Link onClick={this.toggleMerge} to="#">
<Icon color="currentColor" size={2}>
minimize
</Icon>
Merge
</Link>
<Link onClick={cancelResult} to="#">
<Icon color="currentColor" size={2}>
minus-square
</Icon>
Cancel
</Link>
</div>
</ListItem>
)
})}
</ZebraList>
{success && <Notification type="success">{success}</Notification>}
{error && <Notification type="error">{error}</Notification>}
<UserIdSearch
success={v => this.setState({ mergeId: v.id, isOpen: !isOpen })}
successLabel="Merge"
/>
<ConfirmDialog
action={merge}
isOpen={this.state.isOpen}
isOpen={isOpen}
message="Once the content is merged, the other account will be deactivated. Are you sure you want to merge?"
/>
</div>
......
import gql from 'graphql-tag'
export const GET_USER = gql`
query($email: String!) {
userByEmail(email: $email) {
id
}
}
`
export const GET_USER_ID = gql`
query($id: ID!) {
epmc_user(id: $id) {
id
identities {
type
email
name {
title
givenNames
surname
}
meta {
publisher
}
}
teams
}
}
`
export const ManuscriptFragment = gql`
fragment ManuscriptFragment on Manuscript {
id
......
......@@ -23,10 +23,10 @@ import { NoteMutations, ManuscriptMutations } from '../SubmissionMutations'
import SubmissionCancel from '../SubmissionCancel'
import { GET_MANUSCRIPT } from '../operations'
import GrantSearch from '../GrantSearch'
import SelectReviewer from '../SelectReviewer'
import CreatePageHeader from './CreateHeader'
import CreateInfo from './CreateInfo'
import Citation from './Citation'
import SelectReviewer from './SelectReviewer'
const FadeIn = createGlobalStyle`
@keyframes fadeIn {
......
......@@ -4,8 +4,8 @@ import { th } from '@pubsweet/ui-toolkit'
import { Button, H2, Icon } from '@pubsweet/ui'
import { SplitPage, StepPanel, InfoPanel, Buttons, CloseModal } from '../ui'
import UploadFiles, { SubmissionTypes } from '../upload-files'
import SelectReviewer from '../SelectReviewer'
import CreateInfo from './CreateInfo'
import SelectReviewer from './SelectReviewer'
const CloseEdit = styled(CloseModal)`
margin: calc(${th('gridUnit')} * 6) auto calc(${th('gridUnit')} * 2);
......
......@@ -9,14 +9,6 @@ export const CURRENT_USER = gql`
}
`
export const GET_USER = gql`
query($email: String!) {
userByEmail(email: $email) {
id
}
}
`
export const CREATE_MANUSCRIPT = gql`
mutation CreateManuscript($data: CreateManuscriptInput!) {
createManuscript(data: $data) {
......
......@@ -61,25 +61,28 @@ const SubmitButton = styled(Button)`
const Text = styled(TextField)`
width: 100%;
`
const SearchForm = props => (
<Form
hasLabel={props.label}
noButton={props.noButton}
onSubmit={props.onSubmit}
>
const SearchForm = ({
label,
noButton,
onSubmit,
name,
onChange,
placeholder,
value,
disabled,
buttonLabel,
...props
}) => (
<Form hasLabel={label} noButton={noButton} onSubmit={onSubmit} {...props}>
<Text
label={props.label}
name={props.name}
onChange={props.onChange}
placeholder={props.placeholder}
value={props.value}
label={label}
name={name}
onChange={onChange}
placeholder={placeholder}
value={value}
/>
<SubmitButton
disabled={props.disabled}
primary={props.buttonLabel}
type="submit"
>
{props.buttonLabel ? (
<SubmitButton disabled={disabled} primary={buttonLabel} type="submit">
{buttonLabel ? (
props.buttonLabel
) : (
<Icon color="currentColor" size={3}>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment