Skip to content

Commit 18768fd

Browse files
authored
Merge pull request #1624 from topcoder-platform/pm-974_2
feat(PM-974): allow PM to view users and delete users from project
2 parents 90f0395 + 7eccfe3 commit 18768fd

File tree

7 files changed

+75
-22
lines changed

7 files changed

+75
-22
lines changed

src/actions/challenges.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import {
5757
} from '../config/constants'
5858
import { loadProject } from './projects'
5959
import { removeChallengeFromPhaseProduct, saveChallengeAsPhaseProduct } from '../services/projects'
60-
import { checkAdmin } from '../util/tc'
60+
import { checkAdmin, checkManager } from '../util/tc'
6161

6262
/**
6363
* Member challenges related redux actions
@@ -159,7 +159,11 @@ export function loadChallengesByPage (
159159
filters['projectId'] = projectId
160160
} else if (_.isObject(projectId) && projectId.value > 0) {
161161
filters['projectId'] = projectId.value
162-
} else if (!checkAdmin(getState().auth.token) && userId) {
162+
} else if (
163+
!checkAdmin(getState().auth.token) &&
164+
!checkManager(getState().auth.token) &&
165+
userId
166+
) {
163167
// Note that we only add the memberId field if *no* project ID is given,
164168
// so that the list of *all challenges shows only those that the member is on
165169
filters['memberId'] = userId

src/actions/sidebar.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
UNLOAD_PROJECTS_SUCCESS,
1212
PROJECTS_PAGE_SIZE
1313
} from '../config/constants'
14-
import { checkAdmin } from '../util/tc'
14+
import { checkAdmin, checkManager } from '../util/tc'
1515
import _ from 'lodash'
1616

1717
/**
@@ -50,7 +50,7 @@ export function loadProjects (filterProjectName = '', paramFilters = {}) {
5050
}
5151
}
5252

53-
if (!checkAdmin(getState().auth.token)) {
53+
if (!checkAdmin(getState().auth.token) && !checkManager(getState().auth.token)) {
5454
filters['memberOnly'] = true
5555
}
5656

src/actions/users.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,55 @@ import {
1010
SEARCH_USER_PROJECTS_SUCCESS,
1111
SEARCH_USER_PROJECTS_FAILURE
1212
} from '../config/constants'
13+
import _ from 'lodash'
1314

1415
/**
1516
* Loads projects of the authenticated user
1617
*/
17-
export function loadAllUserProjects (isAdmin = true) {
18-
return (dispatch) => {
18+
export function loadAllUserProjects (params, isAdmin = true, isManager = true) {
19+
return (dispatch, getState) => {
1920
dispatch({
2021
type: LOAD_ALL_USER_PROJECTS_PENDING
2122
})
2223

24+
const state = getState().users
25+
2326
const filters = {
2427
status: 'active',
25-
sort: 'lastActivityAt desc'
28+
sort: 'lastActivityAt desc',
29+
perPage: 20,
30+
...params
2631
}
27-
if (!isAdmin) {
32+
33+
if (!isAdmin && !isManager) {
2834
filters['memberOnly'] = true
2935
}
3036

31-
fetchMemberProjects(filters).then(({ projects }) => dispatch({
37+
fetchMemberProjects(filters).then(({ projects, pagination }) => dispatch({
3238
type: LOAD_ALL_USER_PROJECTS_SUCCESS,
33-
projects
39+
projects: _.uniqBy((filters.page ? state.allUserProjects || [] : []).concat(projects), 'id'),
40+
total: pagination.xTotal,
41+
page: pagination.xPage
3442
})).catch(() => dispatch({
3543
type: LOAD_ALL_USER_PROJECTS_FAILURE
3644
}))
3745
}
3846
}
3947

48+
export function loadNextProjects (isAdmin = true, isManager = true) {
49+
return (dispatch, getState) => {
50+
const { page, total, allUserProjects } = getState().users
51+
if (allUserProjects.length >= total) {
52+
return
53+
}
54+
55+
loadAllUserProjects(_.assign({}, {
56+
perPage: 20,
57+
page: page + 1
58+
}), isAdmin, isManager)(dispatch, getState)
59+
}
60+
}
61+
4062
/**
4163
* Filter projects of the authenticated user
4264
*

src/components/Users/index.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import PrimaryButton from '../Buttons/PrimaryButton'
99
import Modal from '../Modal'
1010
import SelectUserAutocomplete from '../SelectUserAutocomplete'
1111
import { PROJECT_ROLES, AUTOCOMPLETE_DEBOUNCE_TIME_MS } from '../../config/constants'
12-
import { checkAdmin } from '../../util/tc'
12+
import { checkAdmin, checkManager } from '../../util/tc'
1313
import { addUserToProject, removeUserFromProject } from '../../services/projects'
1414
import ConfirmationModal from '../Modal/ConfirmationModal'
1515

@@ -213,7 +213,8 @@ class Users extends Component {
213213
updateProjectNember,
214214
isEditable,
215215
isSearchingUserProjects,
216-
resultSearchUserProjects
216+
resultSearchUserProjects,
217+
loadNextProjects
217218
} = this.props
218219
const {
219220
searchKey
@@ -228,7 +229,8 @@ class Users extends Component {
228229
const membersExist = projectMembers && projectMembers.length > 0
229230
const isCopilotOrManager = this.checkIsCopilotOrManager(projectMembers, loggedInHandle)
230231
const isAdmin = checkAdmin(this.props.auth.token)
231-
const showAddUser = isEditable && this.state.projectOption && (isCopilotOrManager || isAdmin)
232+
const isManager = checkManager(this.props.auth.token)
233+
const showAddUser = isEditable && this.state.projectOption && (isCopilotOrManager || isAdmin || isManager)
232234

233235
return (
234236
<div className={styles.contentContainer}>
@@ -246,6 +248,7 @@ class Users extends Component {
246248
onChange={(e) => { this.setProjectOption(e) }}
247249
onInputChange={this.debouncedOnInputChange}
248250
isLoading={isSearchingUserProjects}
251+
onMenuScrollBottom={loadNextProjects}
249252
filterOption={() => true}
250253
noOptionsMessage={() => isSearchingUserProjects ? 'Searching...' : 'No options'}
251254
/>
@@ -457,7 +460,8 @@ Users.propTypes = {
457460
projects: PropTypes.arrayOf(PropTypes.object),
458461
projectMembers: PropTypes.arrayOf(PropTypes.object),
459462
searchUserProjects: PropTypes.func.isRequired,
460-
resultSearchUserProjects: PropTypes.arrayOf(PropTypes.object)
463+
resultSearchUserProjects: PropTypes.arrayOf(PropTypes.object),
464+
loadNextProjects: PropTypes.func.isRequired
461465
}
462466

463467
export default Users

src/containers/Projects/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import styles from './styles.module.scss'
1818
const Projects = ({ projects, auth, isLoading, projectsCount, loadProjects, loadMoreProjects, unloadProjects }) => {
1919
const [search, setSearch] = useState()
2020
const [projectStatus, setProjectStatus] = useState('')
21-
const [showOnlyMyProjects, setOnlyMyProjects] = useState(true)
21+
const [showOnlyMyProjects, setOnlyMyProjects] = useState(false)
2222
const selectedStatus = useMemo(() => PROJECT_STATUSES.find(s => s.value === projectStatus))
2323

2424
const isProjectManager = checkManager(auth.token)

src/containers/Users/index.js

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import PT from 'prop-types'
55
import UsersComponent from '../../components/Users'
66
import { PROJECT_ROLES } from '../../config/constants'
77
import { fetchProjectById } from '../../services/projects'
8-
import { checkAdmin } from '../../util/tc'
8+
import { checkAdmin, checkManager } from '../../util/tc'
99

1010
import {
1111
loadAllUserProjects,
12+
loadNextProjects,
1213
searchUserProjects
1314
} from '../../actions/users'
1415

@@ -25,19 +26,32 @@ class Users extends Component {
2526
this.updateProjectNember = this.updateProjectNember.bind(this)
2627
this.removeProjectNember = this.removeProjectNember.bind(this)
2728
this.addNewProjectMember = this.addNewProjectMember.bind(this)
29+
this.loadNextProjects = this.loadNextProjects.bind(this)
2830
}
2931

3032
componentDidMount () {
31-
const { token, isLoading, loadAllUserProjects } = this.props
33+
const { token, isLoading, loadAllUserProjects, page } = this.props
3234
if (!isLoading) {
3335
const isAdmin = checkAdmin(token)
34-
loadAllUserProjects(isAdmin)
36+
const isManager = checkManager(token)
37+
const params = {
38+
page
39+
}
40+
loadAllUserProjects(params, isAdmin, isManager)
3541
this.setState({
3642
isAdmin
3743
})
3844
}
3945
}
4046

47+
loadNextProjects () {
48+
const { loadNextProjects: nextProjectsHandler, token } = this.props
49+
const isAdmin = checkAdmin(token)
50+
const isManager = checkManager(token)
51+
52+
nextProjectsHandler(isAdmin, isManager)
53+
}
54+
4155
isEditable () {
4256
const { loginUserRoleInProject } = this.state
4357
if (loginUserRoleInProject === PROJECT_ROLES.READ) {
@@ -129,6 +143,7 @@ class Users extends Component {
129143
updateProjectNember={this.updateProjectNember}
130144
removeProjectNember={this.removeProjectNember}
131145
addNewProjectMember={this.addNewProjectMember}
146+
loadNextProjects={this.loadNextProjects}
132147
projectMembers={projectMembers}
133148
auth={auth}
134149
isAdmin={isAdmin}
@@ -146,6 +161,7 @@ class Users extends Component {
146161
const mapStateToProps = ({ users, auth }) => {
147162
return {
148163
projects: users.allUserProjects,
164+
page: users.page,
149165
isLoading: users.isLoadingAllUserProjects,
150166
resultSearchUserProjects: users.searchUserProjects,
151167
isSearchingUserProjects: users.isSearchingUserProjects,
@@ -164,12 +180,15 @@ Users.propTypes = {
164180
isLoading: PT.bool,
165181
isSearchingUserProjects: PT.bool,
166182
loadAllUserProjects: PT.func.isRequired,
167-
searchUserProjects: PT.func.isRequired
183+
searchUserProjects: PT.func.isRequired,
184+
loadNextProjects: PT.func.isRequired,
185+
page: PT.number
168186
}
169187

170188
const mapDispatchToProps = {
171189
loadAllUserProjects,
172-
searchUserProjects
190+
searchUserProjects,
191+
loadNextProjects
173192
}
174193

175194
export default connect(mapStateToProps, mapDispatchToProps)(Users)

src/reducers/users.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ const initialState = {
1414
allUserProjects: [],
1515
isLoadingAllUserProjects: false,
1616
searchUserProjects: [],
17-
isSearchingUserProjects: false
17+
isSearchingUserProjects: false,
18+
page: 1,
19+
total: null
1820
}
1921

2022
export default function (state = initialState, action) {
@@ -23,7 +25,9 @@ export default function (state = initialState, action) {
2325
return {
2426
...state,
2527
allUserProjects: action.projects,
26-
isLoadingAllUserProjects: false
28+
isLoadingAllUserProjects: false,
29+
page: action.page,
30+
total: action.total
2731
}
2832
case LOAD_ALL_USER_PROJECTS_PENDING:
2933
return { ...state, isLoadingAllUserProjects: true }

0 commit comments

Comments
 (0)