diff --git a/src/actions/users.js b/src/actions/users.js
new file mode 100644
index 00000000..708ddd1f
--- /dev/null
+++ b/src/actions/users.js
@@ -0,0 +1,35 @@
+/**
+ * Sidebar related redux actions
+ */
+import { fetchMemberProjects } from '../services/projects'
+import {
+ LOAD_ALL_USER_PROJECTS_PENDING,
+ LOAD_ALL_USER_PROJECTS_SUCCESS,
+ LOAD_ALL_USER_PROJECTS_FAILURE
+} from '../config/constants'
+
+/**
+ * Loads projects of the authenticated user
+ */
+export function loadAllUserProjects (isAdmin = true) {
+ return (dispatch) => {
+ dispatch({
+ type: LOAD_ALL_USER_PROJECTS_PENDING
+ })
+
+ const filters = {
+ status: 'active',
+ sort: 'lastActivityAt desc'
+ }
+ if (!isAdmin) {
+ filters['memberOnly'] = true
+ }
+
+ fetchMemberProjects(filters).then(projects => dispatch({
+ type: LOAD_ALL_USER_PROJECTS_SUCCESS,
+ projects
+ })).catch(() => dispatch({
+ type: LOAD_ALL_USER_PROJECTS_FAILURE
+ }))
+ }
+}
diff --git a/src/components/ChallengeEditor/ChallengeView/index.js b/src/components/ChallengeEditor/ChallengeView/index.js
index 6becff77..c7bfbb95 100644
--- a/src/components/ChallengeEditor/ChallengeView/index.js
+++ b/src/components/ChallengeEditor/ChallengeView/index.js
@@ -207,6 +207,12 @@ const ChallengeView = ({
)}
>
)}
+
+
+ Timezone:
+ {Intl.DateTimeFormat().resolvedOptions().timeZone}
+
+
{
challenge.legacy.subTrack === 'WEB_DESIGNS' && challenge.phases.length === 8 ? phases.map((phase, index) => (
currentPhase.indexOf(phase) < 0)
const exceptionHandlesDeleteList = {}
- // The creator of the challenge can't be deleted
- exceptionHandlesDeleteList[challenge.createdBy] = true
_.forEach(submissions, (s) => {
// do not allow to delete submitters who submitted
exceptionHandlesDeleteList[s.createdBy] = true
@@ -182,6 +180,14 @@ export default class Resources extends React.Component {
], (status) => challenge.status.toUpperCase() === status)
) {
if (
+ // The creator of the challenge can't be deleted
+ resourceItem.memberHandle === challenge.createdBy
+ ) {
+ // where the copilot has multiple roles, we should allow the additional roles to be deleted, but not the copilot role
+ if (`${resourceItem.role}`.toLowerCase().indexOf('copilot') >= 0) {
+ exceptionResourceIdDeleteList[resourceItem.id] = true
+ }
+ } else if (
// Copilots can't delete themselves from the challenge
loggedInUserResource &&
_.some(loggedInUserResource.roles, (role) => `${role}`.toLowerCase().indexOf('copilot') >= 0) &&
@@ -189,6 +195,11 @@ export default class Resources extends React.Component {
) {
exceptionResourceIdDeleteList[resourceItem.id] = true
}
+ } else if (
+ // The creator of the challenge can't be deleted
+ resourceItem.memberHandle === challenge.createdBy
+ ) {
+ exceptionResourceIdDeleteList[resourceItem.id] = true
} else if (
// If the current phase is not submission or registration
// then we will disable removing reviewers and copilots.
diff --git a/src/components/ChallengeEditor/index.js b/src/components/ChallengeEditor/index.js
index 479dde10..f181e87b 100644
--- a/src/components/ChallengeEditor/index.js
+++ b/src/components/ChallengeEditor/index.js
@@ -1749,6 +1749,12 @@ class ChallengeEditor extends Component {
)}
{!isTask && (
<>
+
+
+ Timezone:
+ {Intl.DateTimeFormat().resolvedOptions().timeZone}
+
+
{
phases.map((phase, index) => (
{
- return (
-
- )
-}
-
-Sidebar.propTypes = {
- projectId: PropTypes.string,
- resetSidebarActiveParams: PropTypes.func,
- selfService: PropTypes.bool
-}
-
-export default Sidebar
diff --git a/src/config/constants.js b/src/config/constants.js
index d1c2c10e..6aff40cf 100644
--- a/src/config/constants.js
+++ b/src/config/constants.js
@@ -57,6 +57,10 @@ export const LOAD_PROJECTS_PENDING = 'LOAD_PROJECTS_PENDING'
export const LOAD_PROJECTS_FAILURE = 'LOAD_PROJECTS_FAILURE'
export const UNLOAD_PROJECTS_SUCCESS = 'UNLOAD_PROJECTS_SUCCESS'
+export const LOAD_ALL_USER_PROJECTS_SUCCESS = 'LOAD_ALL_USER_PROJECTS_SUCCESS'
+export const LOAD_ALL_USER_PROJECTS_PENDING = 'LOAD_ALL_USER_PROJECTS_PENDING'
+export const LOAD_ALL_USER_PROJECTS_FAILURE = 'LOAD_ALL_USER_PROJECTS_FAILURE'
+
// project billingAccount
export const LOAD_PROJECT_BILLING_ACCOUNT = 'LOAD_PROJECT_BILLING_ACCOUNT'
export const LOAD_PROJECT_BILLING_ACCOUNT_PENDING = 'LOAD_PROJECT_BILLING_ACCOUNT_PENDING'
diff --git a/src/containers/Sidebar/index.js b/src/containers/Sidebar/index.js
deleted file mode 100644
index edb70ba9..00000000
--- a/src/containers/Sidebar/index.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import _ from 'lodash'
-import React, { Component } from 'react'
-import PropTypes from 'prop-types'
-import { connect } from 'react-redux'
-import Sidebar from '../../components/Sidebar'
-import { loadProjects, setActiveProject, resetSidebarActiveParams, unloadProjects } from '../../actions/sidebar'
-
-class SidebarContainer extends Component {
- constructor (props) {
- super(props)
- this.state = {
- searchProjectName: ''
- }
- this.updateProjectName = this.updateProjectName.bind(this)
- }
-
- componentDidMount () {
- const { projectId, activeProjectId, isLoading, selfService } = this.props
- if (!projectId && activeProjectId === -1 && !isLoading && !selfService) {
- this.props.loadProjects()
- }
-
- if (projectId && activeProjectId < 0) {
- this.props.setActiveProject(parseInt(projectId))
- }
- }
-
- componentWillReceiveProps (nextProps) {
- const { projectId, isLoading, selfService, projects } = nextProps
-
- // if we're viewing a specific project,
- // or we're viewing the self serve page,
- // or if the project is already loading,
- // don't load the projects
- if (!!projectId || selfService || isLoading) {
- // if we're not in the middle of loading,
- // and we have projects to unload,
- // unload them
- if (!isLoading && !!projects && !!projects.length) {
- this.props.unloadProjects()
- }
-
- return
- }
-
- // if we already have projects in the list,
- // don't load the projects again
- if (!!projects && !!projects.length) {
- return
- }
-
- // now it's okay to load the projects
- this.props.loadProjects()
- }
-
- updateProjectName (val) {
- this.setState({ searchProjectName: val })
- this.props.loadProjects(val)
- }
-
- render () {
- const { isLoading, setActiveProject, projectId, resetSidebarActiveParams, projects, selfService, unloadProjects } = this.props
- const { searchProjectName } = this.state
-
- return (
-
- )
- }
-}
-
-SidebarContainer.propTypes = {
- projects: PropTypes.arrayOf(PropTypes.shape()),
- isLoading: PropTypes.bool,
- loadProjects: PropTypes.func,
- unloadProjects: PropTypes.func,
- activeProjectId: PropTypes.number,
- setActiveProject: PropTypes.func,
- projectId: PropTypes.string,
- resetSidebarActiveParams: PropTypes.func,
- selfService: PropTypes.bool
-}
-
-const mapStateToProps = ({ sidebar }) => ({
- ...sidebar
-})
-
-const mapDispatchToProps = {
- loadProjects,
- unloadProjects,
- setActiveProject,
- resetSidebarActiveParams
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(SidebarContainer)
diff --git a/src/containers/Tab/index.js b/src/containers/Tab/index.js
index 327d9362..af091a3f 100644
--- a/src/containers/Tab/index.js
+++ b/src/containers/Tab/index.js
@@ -17,13 +17,25 @@ class TabContainer extends Component {
searchProjectName: '',
currentTab: 1
}
- this.updateProjectName = this.updateProjectName.bind(this)
this.onTabChange = this.onTabChange.bind(this)
}
componentDidMount () {
- const { projectId, activeProjectId, isLoading, selfService } = this.props
- if (!projectId && activeProjectId === -1 && !isLoading && !selfService) {
+ const {
+ projectId,
+ activeProjectId,
+ isLoading,
+ selfService,
+ history
+ } = this.props
+ if (
+ !projectId &&
+ activeProjectId === -1 &&
+ !isLoading &&
+ !selfService &&
+ // do not fetch projects for users page
+ history.location.pathname !== '/users'
+ ) {
this.props.loadProjects()
}
@@ -46,15 +58,22 @@ class TabContainer extends Component {
} else {
this.setState({ currentTab: 0 })
}
+ if (
+ isLoading ||
+ // do not fetch projects for users page
+ nextProps.history.location.pathname === '/users'
+ ) {
+ return
+ }
// if we're viewing a specific project,
// or we're viewing the self serve page,
// or if the project is already loading,
// don't load the projects
- if (!!projectId || selfService || isLoading) {
+ if (!!projectId || selfService) {
// if we're not in the middle of loading,
// and we have projects to unload,
// unload them
- if (!isLoading && !!projects && !!projects.length) {
+ if (!!projects && !!projects.length) {
this.props.unloadProjects()
}
@@ -71,11 +90,6 @@ class TabContainer extends Component {
this.props.loadProjects()
}
- updateProjectName (val) {
- this.setState({ searchProjectName: val })
- this.props.loadProjects(val)
- }
-
onTabChange (tab) {
const { history, resetSidebarActiveParams } = this.props
if (tab === 1) {
diff --git a/src/containers/Users/index.js b/src/containers/Users/index.js
index e1b8a3ff..8e45f089 100644
--- a/src/containers/Users/index.js
+++ b/src/containers/Users/index.js
@@ -5,6 +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 {
+ loadAllUserProjects
+} from '../../actions/users'
class Users extends Component {
constructor (props) {
@@ -21,6 +26,11 @@ class Users extends Component {
}
componentDidMount () {
+ const { token, isLoading, loadAllUserProjects } = this.props
+ if (!isLoading) {
+ const isAdmin = checkAdmin(token)
+ loadAllUserProjects(isAdmin)
+ }
}
isEditable () {
@@ -118,18 +128,27 @@ class Users extends Component {
}
}
-const mapStateToProps = ({ sidebar, auth }) => {
+const mapStateToProps = ({ users, auth }) => {
return {
- projects: sidebar.projects,
+ projects: users.allUserProjects,
+ isLoading: users.isLoadingAllUserProjects,
auth,
- loggedInUser: auth.user
+ loggedInUser: auth.user,
+ token: auth.token
}
}
Users.propTypes = {
projects: PT.arrayOf(PT.object),
auth: PT.object,
- loggedInUser: PT.object
+ loggedInUser: PT.object,
+ token: PT.string,
+ isLoading: PT.bool,
+ loadAllUserProjects: PT.func.isRequired
+}
+
+const mapDispatchToProps = {
+ loadAllUserProjects
}
-export default connect(mapStateToProps)(Users)
+export default connect(mapStateToProps, mapDispatchToProps)(Users)
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 5211b302..a220cb0c 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -9,6 +9,7 @@ import projects from './projects'
import challengeSubmissions from './challengeSubmissions'
import sidebar from './sidebar'
import members from './members'
+import users from './users'
export default combineReducers({
auth,
@@ -17,5 +18,6 @@ export default combineReducers({
sidebar,
toastr: toastrReducer,
projects,
- members
+ members,
+ users
})
diff --git a/src/reducers/users.js b/src/reducers/users.js
new file mode 100644
index 00000000..ad5e7192
--- /dev/null
+++ b/src/reducers/users.js
@@ -0,0 +1,26 @@
+/**
+ * Reducer to process actions related to sidebar
+ */
+import {
+ LOAD_ALL_USER_PROJECTS_PENDING,
+ LOAD_ALL_USER_PROJECTS_SUCCESS,
+ LOAD_ALL_USER_PROJECTS_FAILURE
+} from '../config/constants'
+
+const initialState = {
+ allUserProjects: [],
+ isLoadProjectsSuccess: false
+}
+
+export default function (state = initialState, action) {
+ switch (action.type) {
+ case LOAD_ALL_USER_PROJECTS_SUCCESS:
+ return { ...state, allUserProjects: action.projects, isLoadingAllUserProjects: false }
+ case LOAD_ALL_USER_PROJECTS_PENDING:
+ return { ...state, isLoadingAllUserProjects: true }
+ case LOAD_ALL_USER_PROJECTS_FAILURE:
+ return { ...state, isLoadingAllUserProjects: false }
+ default:
+ return state
+ }
+}