diff --git a/src/actions/challenges.js b/src/actions/challenges.js index f1dabb7e..60eb631f 100644 --- a/src/actions/challenges.js +++ b/src/actions/challenges.js @@ -57,7 +57,7 @@ import { } from '../config/constants' import { loadProject } from './projects' import { removeChallengeFromPhaseProduct, saveChallengeAsPhaseProduct } from '../services/projects' -import { checkAdmin } from '../util/tc' +import { checkAdmin, checkManager } from '../util/tc' /** * Member challenges related redux actions @@ -159,7 +159,11 @@ export function loadChallengesByPage ( filters['projectId'] = projectId } else if (_.isObject(projectId) && projectId.value > 0) { filters['projectId'] = projectId.value - } else if (!checkAdmin(getState().auth.token) && userId) { + } else if ( + !checkAdmin(getState().auth.token) && + !checkManager(getState().auth.token) && + userId + ) { // Note that we only add the memberId field if *no* project ID is given, // so that the list of *all challenges shows only those that the member is on filters['memberId'] = userId diff --git a/src/actions/sidebar.js b/src/actions/sidebar.js index 4fd02fd1..0c02d8f4 100644 --- a/src/actions/sidebar.js +++ b/src/actions/sidebar.js @@ -11,7 +11,7 @@ import { UNLOAD_PROJECTS_SUCCESS, PROJECTS_PAGE_SIZE } from '../config/constants' -import { checkAdmin } from '../util/tc' +import { checkAdmin, checkManager } from '../util/tc' import _ from 'lodash' /** @@ -50,7 +50,7 @@ export function loadProjects (filterProjectName = '', paramFilters = {}) { } } - if (!checkAdmin(getState().auth.token)) { + if (!checkAdmin(getState().auth.token) && !checkManager(getState().auth.token)) { filters['memberOnly'] = true } diff --git a/src/actions/users.js b/src/actions/users.js index 46a9a56f..31a65ab2 100644 --- a/src/actions/users.js +++ b/src/actions/users.js @@ -10,33 +10,55 @@ import { SEARCH_USER_PROJECTS_SUCCESS, SEARCH_USER_PROJECTS_FAILURE } from '../config/constants' +import _ from 'lodash' /** * Loads projects of the authenticated user */ -export function loadAllUserProjects (isAdmin = true) { - return (dispatch) => { +export function loadAllUserProjects (params, isAdmin = true, isManager = true) { + return (dispatch, getState) => { dispatch({ type: LOAD_ALL_USER_PROJECTS_PENDING }) + const state = getState().users + const filters = { status: 'active', - sort: 'lastActivityAt desc' + sort: 'lastActivityAt desc', + perPage: 20, + ...params } - if (!isAdmin) { + + if (!isAdmin && !isManager) { filters['memberOnly'] = true } - fetchMemberProjects(filters).then(({ projects }) => dispatch({ + fetchMemberProjects(filters).then(({ projects, pagination }) => dispatch({ type: LOAD_ALL_USER_PROJECTS_SUCCESS, - projects + projects: _.uniqBy((filters.page ? state.allUserProjects || [] : []).concat(projects), 'id'), + total: pagination.xTotal, + page: pagination.xPage })).catch(() => dispatch({ type: LOAD_ALL_USER_PROJECTS_FAILURE })) } } +export function loadNextProjects (isAdmin = true, isManager = true) { + return (dispatch, getState) => { + const { page, total, allUserProjects } = getState().users + if (allUserProjects.length >= total) { + return + } + + loadAllUserProjects(_.assign({}, { + perPage: 20, + page: page + 1 + }), isAdmin, isManager)(dispatch, getState) + } +} + /** * Filter projects of the authenticated user * diff --git a/src/components/Users/index.js b/src/components/Users/index.js index 07d862dc..1eb1b46f 100644 --- a/src/components/Users/index.js +++ b/src/components/Users/index.js @@ -9,7 +9,7 @@ import PrimaryButton from '../Buttons/PrimaryButton' import Modal from '../Modal' import SelectUserAutocomplete from '../SelectUserAutocomplete' import { PROJECT_ROLES, AUTOCOMPLETE_DEBOUNCE_TIME_MS } from '../../config/constants' -import { checkAdmin } from '../../util/tc' +import { checkAdmin, checkManager } from '../../util/tc' import { addUserToProject, removeUserFromProject } from '../../services/projects' import ConfirmationModal from '../Modal/ConfirmationModal' @@ -213,7 +213,8 @@ class Users extends Component { updateProjectNember, isEditable, isSearchingUserProjects, - resultSearchUserProjects + resultSearchUserProjects, + loadNextProjects } = this.props const { searchKey @@ -228,7 +229,8 @@ class Users extends Component { const membersExist = projectMembers && projectMembers.length > 0 const isCopilotOrManager = this.checkIsCopilotOrManager(projectMembers, loggedInHandle) const isAdmin = checkAdmin(this.props.auth.token) - const showAddUser = isEditable && this.state.projectOption && (isCopilotOrManager || isAdmin) + const isManager = checkManager(this.props.auth.token) + const showAddUser = isEditable && this.state.projectOption && (isCopilotOrManager || isAdmin || isManager) return (
@@ -246,6 +248,7 @@ class Users extends Component { onChange={(e) => { this.setProjectOption(e) }} onInputChange={this.debouncedOnInputChange} isLoading={isSearchingUserProjects} + onMenuScrollBottom={loadNextProjects} filterOption={() => true} noOptionsMessage={() => isSearchingUserProjects ? 'Searching...' : 'No options'} /> @@ -457,7 +460,8 @@ Users.propTypes = { projects: PropTypes.arrayOf(PropTypes.object), projectMembers: PropTypes.arrayOf(PropTypes.object), searchUserProjects: PropTypes.func.isRequired, - resultSearchUserProjects: PropTypes.arrayOf(PropTypes.object) + resultSearchUserProjects: PropTypes.arrayOf(PropTypes.object), + loadNextProjects: PropTypes.func.isRequired } export default Users diff --git a/src/containers/Projects/index.js b/src/containers/Projects/index.js index 97a5e189..e3dd4167 100644 --- a/src/containers/Projects/index.js +++ b/src/containers/Projects/index.js @@ -18,7 +18,7 @@ import styles from './styles.module.scss' const Projects = ({ projects, auth, isLoading, projectsCount, loadProjects, loadMoreProjects, unloadProjects }) => { const [search, setSearch] = useState() const [projectStatus, setProjectStatus] = useState('') - const [showOnlyMyProjects, setOnlyMyProjects] = useState(true) + const [showOnlyMyProjects, setOnlyMyProjects] = useState(false) const selectedStatus = useMemo(() => PROJECT_STATUSES.find(s => s.value === projectStatus)) const isProjectManager = checkManager(auth.token) diff --git a/src/containers/Users/index.js b/src/containers/Users/index.js index 7a1ecf3f..c8666784 100644 --- a/src/containers/Users/index.js +++ b/src/containers/Users/index.js @@ -5,10 +5,11 @@ import PT from 'prop-types' import UsersComponent from '../../components/Users' import { PROJECT_ROLES } from '../../config/constants' import { fetchProjectById } from '../../services/projects' -import { checkAdmin } from '../../util/tc' +import { checkAdmin, checkManager } from '../../util/tc' import { loadAllUserProjects, + loadNextProjects, searchUserProjects } from '../../actions/users' @@ -25,19 +26,32 @@ class Users extends Component { this.updateProjectNember = this.updateProjectNember.bind(this) this.removeProjectNember = this.removeProjectNember.bind(this) this.addNewProjectMember = this.addNewProjectMember.bind(this) + this.loadNextProjects = this.loadNextProjects.bind(this) } componentDidMount () { - const { token, isLoading, loadAllUserProjects } = this.props + const { token, isLoading, loadAllUserProjects, page } = this.props if (!isLoading) { const isAdmin = checkAdmin(token) - loadAllUserProjects(isAdmin) + const isManager = checkManager(token) + const params = { + page + } + loadAllUserProjects(params, isAdmin, isManager) this.setState({ isAdmin }) } } + loadNextProjects () { + const { loadNextProjects: nextProjectsHandler, token } = this.props + const isAdmin = checkAdmin(token) + const isManager = checkManager(token) + + nextProjectsHandler(isAdmin, isManager) + } + isEditable () { const { loginUserRoleInProject } = this.state if (loginUserRoleInProject === PROJECT_ROLES.READ) { @@ -129,6 +143,7 @@ class Users extends Component { updateProjectNember={this.updateProjectNember} removeProjectNember={this.removeProjectNember} addNewProjectMember={this.addNewProjectMember} + loadNextProjects={this.loadNextProjects} projectMembers={projectMembers} auth={auth} isAdmin={isAdmin} @@ -146,6 +161,7 @@ class Users extends Component { const mapStateToProps = ({ users, auth }) => { return { projects: users.allUserProjects, + page: users.page, isLoading: users.isLoadingAllUserProjects, resultSearchUserProjects: users.searchUserProjects, isSearchingUserProjects: users.isSearchingUserProjects, @@ -164,12 +180,15 @@ Users.propTypes = { isLoading: PT.bool, isSearchingUserProjects: PT.bool, loadAllUserProjects: PT.func.isRequired, - searchUserProjects: PT.func.isRequired + searchUserProjects: PT.func.isRequired, + loadNextProjects: PT.func.isRequired, + page: PT.number } const mapDispatchToProps = { loadAllUserProjects, - searchUserProjects + searchUserProjects, + loadNextProjects } export default connect(mapStateToProps, mapDispatchToProps)(Users) diff --git a/src/reducers/users.js b/src/reducers/users.js index 8dc18247..e293c154 100644 --- a/src/reducers/users.js +++ b/src/reducers/users.js @@ -14,7 +14,9 @@ const initialState = { allUserProjects: [], isLoadingAllUserProjects: false, searchUserProjects: [], - isSearchingUserProjects: false + isSearchingUserProjects: false, + page: 1, + total: null } export default function (state = initialState, action) { @@ -23,7 +25,9 @@ export default function (state = initialState, action) { return { ...state, allUserProjects: action.projects, - isLoadingAllUserProjects: false + isLoadingAllUserProjects: false, + page: action.page, + total: action.total } case LOAD_ALL_USER_PROJECTS_PENDING: return { ...state, isLoadingAllUserProjects: true }