diff --git a/src/actions/projects.js b/src/actions/projects.js
index 2d88e519..56f803ee 100644
--- a/src/actions/projects.js
+++ b/src/actions/projects.js
@@ -32,7 +32,7 @@ import {
fetchMemberProjects,
updateProjectApi
} from '../services/projects'
-import { checkAdmin } from '../util/tc'
+import { checkAdmin, checkManager } from '../util/tc'
function _loadProjects (projectNameOrIdFilter = '', paramFilters = {}) {
return (dispatch, getState) => {
@@ -54,7 +54,7 @@ function _loadProjects (projectNameOrIdFilter = '', paramFilters = {}) {
}
}
- if (!checkAdmin(getState().auth.token)) {
+ if (!checkAdmin(getState().auth.token) && !checkManager(getState().auth.token)) {
filters['memberOnly'] = true
}
diff --git a/src/config/constants.js b/src/config/constants.js
index 6aa99441..1310acb4 100644
--- a/src/config/constants.js
+++ b/src/config/constants.js
@@ -308,6 +308,10 @@ export const COPILOT_ROLES = [
'copilot'
]
+export const MANAGER_ROLES = [
+ 'project manager'
+]
+
export const downloadAttachmentURL = (challengeId, attachmentId, token) =>
`${CHALLENGE_API_URL}/${challengeId}/attachments/${attachmentId}/download?token=${token}`
diff --git a/src/containers/Projects/index.js b/src/containers/Projects/index.js
index 733c044c..97a5e189 100644
--- a/src/containers/Projects/index.js
+++ b/src/containers/Projects/index.js
@@ -5,7 +5,7 @@ import { withRouter, Link } from 'react-router-dom'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import Loader from '../../components/Loader'
-import { checkAdminOrCopilot } from '../../util/tc'
+import { checkAdminOrCopilot, checkManager } from '../../util/tc'
import { PrimaryButton } from '../../components/Buttons'
import Select from '../../components/Select'
import ProjectCard from '../../components/ProjectCard'
@@ -18,11 +18,21 @@ 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 selectedStatus = useMemo(() => PROJECT_STATUSES.find(s => s.value === projectStatus))
+ const isProjectManager = checkManager(auth.token)
useEffect(() => {
- loadProjects(search, projectStatus ? { status: projectStatus } : {})
- }, [search, projectStatus])
+ const params = {}
+ if (projectStatus) {
+ params.status = projectStatus
+ }
+
+ if (isProjectManager) {
+ params.memberOnly = showOnlyMyProjects
+ }
+ loadProjects(search, params)
+ }, [search, projectStatus, showOnlyMyProjects, isProjectManager])
// unload projects on dismount
useEffect(() => () => unloadProjects, [])
@@ -46,7 +56,7 @@ const Projects = ({ projects, auth, isLoading, projectsCount, loadProjects, load
)}
-
+
@@ -61,7 +71,7 @@ const Projects = ({ projects, auth, isLoading, projectsCount, loadProjects, load
/>
-
+
@@ -76,6 +86,25 @@ const Projects = ({ projects, auth, isLoading, projectsCount, loadProjects, load
/>
+
+ {
+ checkManager(auth.token) && (
+
+
setOnlyMyProjects(!showOnlyMyProjects)}
+ />
+
+
+ )
+ }
+
{projects.length > 0 ? (
<>
diff --git a/src/containers/Projects/styles.module.scss b/src/containers/Projects/styles.module.scss
index d80341cc..ef18461d 100644
--- a/src/containers/Projects/styles.module.scss
+++ b/src/containers/Projects/styles.module.scss
@@ -43,6 +43,7 @@
display: flex;
gap: 10px;
margin-bottom: 20px;
+ align-items: end;
.searchInput {
width: 100%;
height: 40px;
@@ -51,4 +52,85 @@
border: 1px solid $light-gray;
background-color: $lighter-gray;
}
+
+ .tcCheckbox {
+ @include tc-checkbox;
+
+ .tc-checkbox-label {
+ @include roboto-light();
+
+ line-height: 17px;
+ font-weight: 300;
+ margin-left: 21px;
+ user-select: none;
+ cursor: pointer;
+ width: 195px;
+ font-size: 14px;
+ color: #3d3d3d;
+ }
+
+ height: 18px;
+ width: 210px;
+ margin: 0;
+ padding: 0;
+ vertical-align: bottom;
+ position: relative;
+ display: inline-block;
+ margin-bottom: 4px;
+ margin-left: 8px;
+
+ input[type=checkbox] {
+ display: none;
+ }
+
+ label {
+ @include roboto-light();
+
+ line-height: 17px;
+ font-weight: 300;
+ cursor: pointer;
+ position: absolute;
+ display: inline-block;
+ width: 18px;
+ height: 18px;
+ top: 0;
+ left: 0;
+ border: none;
+ box-shadow: none;
+ background: $tc-gray-30;
+ transition: all 0.15s ease-in-out;
+
+ &::after {
+ opacity: 0;
+ content: '';
+ position: absolute;
+ width: 9px;
+ height: 5px;
+ background: transparent;
+ top: 5px;
+ left: 5px;
+ border-top: none;
+ border-right: none;
+ transform: rotate(-45deg);
+ transition: all 0.15s ease-in-out;
+ }
+
+ &:hover::after {
+ opacity: 0.3;
+ }
+
+ div {
+ margin-left: 24px;
+ width: 300px;
+ }
+ }
+
+ input[type=checkbox]:checked ~ label {
+ background: $tc-blue-20;
+ }
+
+ input[type=checkbox]:checked + label::after {
+ border-color: $white;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/util/tc.js b/src/util/tc.js
index 576e9df4..d5917e3b 100644
--- a/src/util/tc.js
+++ b/src/util/tc.js
@@ -10,7 +10,8 @@ import {
SUBMITTER_ROLE_UUID,
READ_ONLY_ROLES,
ALLOWED_DOWNLOAD_SUBMISSIONS_ROLES,
- ALLOWED_EDIT_RESOURCE_ROLES
+ ALLOWED_EDIT_RESOURCE_ROLES,
+ MANAGER_ROLES
} from '../config/constants'
import _ from 'lodash'
import { decodeToken } from 'tc-auth-lib'
@@ -200,6 +201,11 @@ export const checkAdmin = (token) => {
return roles.some(val => ADMIN_ROLES.indexOf(val.toLowerCase()) > -1)
}
+export const checkManager = (token) => {
+ const tokenData = decodeToken(token)
+ const roles = _.get(tokenData, 'roles')
+ return roles.some(val => MANAGER_ROLES.indexOf(val.toLowerCase()) > -1)
+}
/**
* Checks if token has any of the copilot roles
* @param token