Newer
Older
import React from 'react'
import { get, isEqual } from 'lodash'
import { connect } from 'react-redux'
import { actions } from 'pubsweet-client'
import { ConnectPage } from 'xpub-connect'
import { withJournal } from 'xpub-journal'
import { Icon, Menu, th } from '@pubsweet/ui'
import { withRouter, Link } from 'react-router-dom'
import styled, { withTheme } from 'styled-components'
import { compose, withState, withHandlers } from 'recompose'
const TableRow = ({
toggleUser,
selected,
email,
roles,
username,
firstName = '',
lastName = '',
affiliation,
isConfirmed,
<Row>
<td>
<Input checked={selected} onClick={toggleUser} type="checkbox" />
</td>
<td>{email}</td>
<td>{`${firstName} ${lastName}`}</td>
<td>{affiliation}</td>
<Role>{`Author${isEqual(editorInChief, true) ? ', Editor in Chief' : ''}${
isEqual(handlingEditor, true) ? ', Handling Editor' : ''
}${isEqual(admin, true) ? ', Admin' : ''}`}</Role>
</td>
<td>
<Tag>{isConfirmed ? 'Confirmed' : 'Invited'}</Tag>
</td>
<td>
<Action to={`/admin/users/edit/${id}`}>Edit</Action>
users,
toggleUser,
toggleAllUsers,
incrementPage,
decrementPage,
page,
itemsPerPage,
}) => {
const slicedUsers = users.slice(
page * itemsPerPage,
itemsPerPage * (page + 1),
)
return (
<div>
<Header>
<BreadCrumbs>
<span>Admin Dashboard</span>
<span>Users</span>
</BreadCrumbs>
<AddButton
data-test="button-add-user"
onClick={() => history.push('/admin/users/add')}
>
<Icon color={theme.colorPrimary} size={3}>
plus-circle
</Icon>
Add User
</AddButton>
</Header>
<SubHeader>
<div>
<span>Bulk actions: </span>
<Menu
onChange={value => value}
options={[
{ value: 'deactivate', label: 'Deactivate' },
{ value: 'activate', label: 'Activate' },
]}
value="activate"
/>
onChange={value => value}
options={[
{ value: 'sort', label: 'SORT' },
{ value: 'unsort', label: 'UNSORT' },
]}
value="sort"
/>
<Icon color={theme.colorPrimary} size={4}>
search
</Icon>
</div>
<Pagination
decrementPage={decrementPage}
hasMore={itemsPerPage * (page + 1) < users.length}
incrementPage={incrementPage}
itemsPerPage={itemsPerPage}
maxLength={users.length}
page={page}
/>
</SubHeader>
<Table>
<thead>
<tr>
<td>
<Input
checked={users.every(u => u.selected)}
onClick={toggleAllUsers}
type="checkbox"
/>
</td>
<td>Email</td>
<td>Full name</td>
<td>Affiliation</td>
<td width="220">Roles</td>
<td>Status</td>
<td width="50" />
</tr>
</thead>
<tbody>
{slicedUsers.map(u => (
<TableRow
key={u.id}
{...u}
roleOptions={journal.roles}
toggleUser={toggleUser(u)}
))}
</tbody>
</Table>
</div>
)
}
export default compose(
ConnectPage(() => [actions.getUsers()]),
withRouter,
connect(state => ({ currentUsers: get(state, 'users.users') })),
withState('users', 'setUsers', props =>
props.currentUsers.map(u => ({ ...u, selected: false })),
),
withState('itemsPerPage', 'setItemsPerPage', 20),
withState('page', 'setPage', 0),
withHandlers({
incrementPage: ({ setPage, page, itemsPerPage, users }) => () => {
if (page * itemsPerPage + itemsPerPage < users.length) {
setPage(p => p + 1)
}
},
decrementPage: ({ setPage }) => () => {
setPage(p => (p > 0 ? p - 1 : p))
},
toggleUser: ({ setUsers }) => user => () => {
setUsers(prev =>
prev.map(u => (u.id === user.id ? { ...u, selected: !u.selected } : u)),
)
},
toggleAllUsers: ({ setUsers }) => () => {
setUsers(users => users.map(u => ({ ...u, selected: !u.selected })))
},
}),
)(Users)
// #region styled-components
const AddButton = styled.button`
align-items: center;
background-color: ${th('backgroundColor')};
border: none;
cursor: pointer;
color: ${th('colorPrimary')};
font-family: ${th('fontInterface')};
font-size: ${th('fontSizeBaseSmall')};
text-align: left;
&:active,
&:focus {
outline: none;
}
`
const Header = styled.div`
align-items: center;
flex-direction: row;
const BreadCrumbs = styled.div`
color: ${th('colorPrimary')};
cursor: pointer;
font-size: ${th('fontSizeBase')};
margin-left: calc(${th('subGridUnit')}*2);
text-align: left;
&:after {
content: '>';
padding: 0 calc(${th('subGridUnit')}*2);
}
&:last-child {
font-size: ${th('fontSizeBase')};
font-weight: bold;
&:after {
content: '';
}
}
`
const SubHeader = styled.div`
align-items: center;
border-bottom: ${th('borderDefault')};
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: ${th('gridUnit')};
padding-bottom: calc(${th('subGridUnit')}*2);
> div:first-child {
align-items: center;
display: flex;
> div {
margin-right: calc(${th('subGridUnit')});
}
color: ${th('colorPrimary')};
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
margin-right: calc(${th('subGridUnit')});
text-align: left;
}
`
const Table = styled.table`
border-spacing: 0;
border-collapse: collapse;
border-bottom: ${th('borderDefault')};
color: ${th('colorPrimary')};
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
height: 40px;
text-align: left;
}
`
const Row = styled.tr`
border-bottom: ${th('borderDefault')};
color: ${th('colorPrimary')};
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
height: 40px;
text-align: left;
background-color: ${th('backgroundColorReverse')};
a {
display: block;
}
}
const Tag = styled.span`
border: solid 1px #667080;
color: ${th('colorPrimary')};
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
font-weight: bold;
margin-right: calc(${th('subGridUnit')});
padding: 2px calc(${th('subGridUnit')}*2);
text-align: left;
text-transform: uppercase;
const Role = styled.div`
color: ${th('colorPrimary')};
font-size: ${th('fontSizeBaseSmall')};
line-height: 1.5;
text-align: left;
text-transform: uppercase;
`
color: ${th('colorPrimary')};
`
const Input = styled.input`
height: 20px;
width: 20px;