From 6ed5a2c454a994a99f977be09787e95fc31aea87 Mon Sep 17 00:00:00 2001 From: Vikas Agarwal Date: Wed, 3 Jun 2020 09:14:29 +0530 Subject: [PATCH] feat: git#669 project search improvements - allows search by id and exact phrase (to enable searching projects by title) feat: git#669 project search improvements - moved the project search from left panel to main content area to have sufficient space to locate the project feat: git#669 project search improvements - allows searching non my projects as well to support admin users (e.g. support team) to locate other projects/challenges fix: minor style fix for the left panel --- package-lock.json | 120 ++++++----------- public/index.html | 2 +- src/actions/sidebar.js | 16 ++- src/components/Sidebar/Sidebar.module.scss | 31 +---- src/components/Sidebar/index.js | 47 +------ .../Challenges/Challenges.module.scss | 51 +++++++ src/containers/Challenges/index.js | 125 ++++++++++++++---- src/containers/Sidebar/index.js | 2 +- src/containers/TopbarContainer/index.js | 15 ++- src/reducers/sidebar.js | 2 +- src/routes.js | 2 +- 11 files changed, 224 insertions(+), 189 deletions(-) create mode 100644 src/containers/Challenges/Challenges.module.scss diff --git a/package-lock.json b/package-lock.json index 46facb70..5c6ddc0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3220,14 +3220,12 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "optional": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "optional": true, "requires": { "is-extglob": "^2.1.1" } @@ -3241,8 +3239,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "optional": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "to-regex-range": { "version": "5.0.1", @@ -6148,8 +6145,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -6167,13 +6163,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6186,18 +6180,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -6300,8 +6291,7 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -6311,7 +6301,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6324,20 +6313,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.9.0", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6354,7 +6340,6 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "optional": true, "requires": { "minimist": "^1.2.5" } @@ -6410,8 +6395,7 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "npm-packlist": { "version": "1.4.8", @@ -6436,8 +6420,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -6447,7 +6430,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6516,8 +6498,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -6547,7 +6528,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6565,7 +6545,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6604,13 +6583,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.1.1", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -10411,8 +10388,7 @@ "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "optional": true + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pify": { "version": "2.3.0", @@ -17118,9 +17094,9 @@ "angular-cookies": "^1.5.1", "angular-material": "^1.1.21", "angular-messages": "^1.5.2", - "appirio-tech-ng-iso-constants": "github:appirio-tech/ng-iso-constants#v1.0.7", + "appirio-tech-ng-iso-constants": "github:appirio-tech/ng-iso-constants#d8466ab76828208ccdaaeb10816a3f35cd59c39b", "appirio-tech-ng-ui-components": "^2.2.4", - "appirio-tech-react-components": "github:appirio-tech/react-components#feature/connectv2", + "appirio-tech-react-components": "github:appirio-tech/react-components#a471d4f9d1a4cd5a1a2f53aea3d1cc5dd6d78aea", "auth0-js": "^9.6.1", "babel-polyfill": "^6.7.4", "filestack-js": "^1.13.2", @@ -17206,7 +17182,8 @@ }, "acorn": { "version": "5.7.1", - "resolved": "" + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==" }, "acorn-globals": { "version": "1.0.9", @@ -17646,7 +17623,7 @@ "react-textarea-autosize": "^5.2.1", "react-transition-group": "^2.2.1", "redux-thunk": "^2.1.0", - "tc-ui": "git+https://github.com/appirio-tech/tc-ui.git#feature/connectv2", + "tc-ui": "git+https://github.com/appirio-tech/tc-ui.git#e577a0e704136f1e9ecce92ce4c0626aab932691", "uncontrollable": "^4.0.1" }, "dependencies": { @@ -20685,7 +20662,8 @@ }, "extend": { "version": "3.0.1", - "resolved": "" + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" }, "extglob": { "version": "0.3.2", @@ -21071,8 +21049,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": false, - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "optional": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.2.0", @@ -21093,14 +21070,12 @@ "balanced-match": { "version": "1.0.0", "resolved": false, - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -21115,20 +21090,17 @@ "code-point-at": { "version": "1.1.0", "resolved": false, - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", "resolved": false, - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", "resolved": false, - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "optional": true + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", @@ -21245,8 +21217,7 @@ "inherits": { "version": "2.0.3", "resolved": false, - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -21258,7 +21229,6 @@ "version": "1.0.0", "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -21273,7 +21243,6 @@ "version": "3.0.4", "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -21281,14 +21250,12 @@ "minimist": { "version": "0.0.8", "resolved": false, - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.3.5", "resolved": false, "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -21307,7 +21274,6 @@ "version": "0.5.1", "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, "requires": { "minimist": "0.0.8" } @@ -21394,8 +21360,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": false, - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", @@ -21407,7 +21372,6 @@ "version": "1.4.0", "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "optional": true, "requires": { "wrappy": "1" } @@ -21493,8 +21457,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": false, - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -21530,7 +21493,6 @@ "version": "1.0.2", "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -21550,7 +21512,6 @@ "version": "3.0.1", "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -21594,14 +21555,12 @@ "wrappy": { "version": "1.0.2", "resolved": false, - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "optional": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "yallist": { "version": "3.0.3", "resolved": false, - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "optional": true + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } }, @@ -23154,7 +23113,8 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" } @@ -27904,8 +27864,7 @@ "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "optional": true + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, "binary-extensions": { "version": "1.13.1", @@ -27917,7 +27876,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "optional": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", @@ -28047,7 +28005,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -28083,7 +28040,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "optional": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -28177,8 +28133,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "optional": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-glob": { "version": "4.0.1", @@ -28193,7 +28148,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "optional": true, "requires": { "kind-of": "^3.0.2" } diff --git a/public/index.html b/public/index.html index e1058e7d..5954f369 100644 --- a/public/index.html +++ b/public/index.html @@ -7,7 +7,7 @@ content="width=device-width, initial-scale=1, shrink-to-fit=no" /> - Topcoder Challenge Creation App + Work Manager - Topcoder diff --git a/src/actions/sidebar.js b/src/actions/sidebar.js index 04dd84a8..1abd3c90 100644 --- a/src/actions/sidebar.js +++ b/src/actions/sidebar.js @@ -21,7 +21,7 @@ export function setActiveProject (projectId) { /** * Loads projects of the authenticated user */ -export function loadProjects (filterProjectName = '') { +export function loadProjects (filterProjectName = '', myProjects = true) { return (dispatch) => { dispatch({ type: LOAD_PROJECTS_PENDING @@ -29,11 +29,19 @@ export function loadProjects (filterProjectName = '') { const filters = {} if (!_.isEmpty(filterProjectName)) { - filters['name'] = `*${filterProjectName}*` + if (!isNaN(filterProjectName)) { // if it is number + filters['id'] = parseInt(filterProjectName, 10) + } else { // text search + filters['keyword'] = decodeURIComponent(filterProjectName) + } } filters['status'] = 'active' - filters['sort'] = 'lastActivityAt' - filters['memberOnly'] = 'true' + filters['sort'] = 'lastActivityAt desc' + // filters['perPage'] = 20 + // filters['page'] = 1 + if (myProjects) { + filters['memberOnly'] = true + } fetchMemberProjects(filters).then(projects => dispatch({ type: LOAD_PROJECTS_SUCCESS, diff --git a/src/components/Sidebar/Sidebar.module.scss b/src/components/Sidebar/Sidebar.module.scss index 3c36e57a..8b87d068 100644 --- a/src/components/Sidebar/Sidebar.module.scss +++ b/src/components/Sidebar/Sidebar.module.scss @@ -5,34 +5,11 @@ height: 100vh; background-color: $dark-gray; overflow: auto; - - ul { - list-style: none; - width: 100%; - padding: 0; - margin-top: 0; - - li { - cursor: pointer; - } - } - - a { - text-decoration: none; - } - - .noProjects { - @include roboto; - font-weight: 400; - padding-left: 30px; - padding-right: 20px; - color: $white; - } } .logo { width: calc(100% - 100px); - padding: 30px 50px 42px 50px; + padding: 30px 50px 42px 30px; @media screen and (max-width: 300px * 4) { width: calc(100% - 20px); padding: 30px 10px 42px 10px; @@ -46,10 +23,8 @@ font-weight: 400; line-height: 31px; color: $white; - display: flex; - justify-content: center; - align-items: center; - margin-bottom: 37px + margin-bottom: 37px; + padding-left: 30px; } .homeLink { diff --git a/src/components/Sidebar/index.js b/src/components/Sidebar/index.js index 97bc0c76..9869e77f 100644 --- a/src/components/Sidebar/index.js +++ b/src/components/Sidebar/index.js @@ -5,71 +5,28 @@ import React from 'react' import { Link } from 'react-router-dom' import PropTypes from 'prop-types' import cn from 'classnames' -import _ from 'lodash' -import ProjectCard from '../ProjectCard' -import { DebounceInput } from 'react-debounce-input' -import Loader from '../Loader' import TopcoderLogo from '../../assets/images/topcoder-logo.png' import styles from './Sidebar.module.scss' const Sidebar = ({ - projects, isLoading, setActiveProject, - projectId, resetSidebarActiveParams, - updateProjectsList, searchProjectName + projectId, resetSidebarActiveParams }) => { - const projectComponents = projects.map(p => ( -
  • - -
  • - )) - return (
    Challenge Editor
    - { - !isLoading && !searchProjectName && _.get(projectComponents, 'length', 0) === 0 && ( -
    - You don't have any active projects yet! -
    - ) - }
    Active challenges
    - updateProjectsList(e.target.value)} - value={searchProjectName} - /> - { - isLoading ? : ( -
      - {projectComponents} -
    - ) - }
    ) } Sidebar.propTypes = { - projects: PropTypes.arrayOf(PropTypes.shape()), - isLoading: PropTypes.bool, - setActiveProject: PropTypes.func, projectId: PropTypes.string, - resetSidebarActiveParams: PropTypes.func, - searchProjectName: PropTypes.string, - updateProjectsList: PropTypes.func + resetSidebarActiveParams: PropTypes.func } export default Sidebar diff --git a/src/containers/Challenges/Challenges.module.scss b/src/containers/Challenges/Challenges.module.scss new file mode 100644 index 00000000..01cafd76 --- /dev/null +++ b/src/containers/Challenges/Challenges.module.scss @@ -0,0 +1,51 @@ +@import "../../styles/includes"; + +.projectSearch { + padding: 20px 20px 0px; + + .projectSearchHeader { + display: flex; + + label { + line-height: 40px; + margin-right: 10px; + } + } + + ul { + background-color: $lighter-gray; + list-style: none; + width: 100%; + padding: 0; + margin-top: 0; + border-radius: 3px; + flex: 1; + + li { + cursor: pointer; + } + } + + input[type="text"] { + flex: 2; + } + + input[type="checkbox"] { + margin-left: 20px; + margin-right: 10px; + height: 40px; + } + + a { + color: $dark-gray; + text-decoration: none; + } + + .noProjects { + @include roboto; + font-weight: 400; + padding-left: 30px; + padding-right: 20px; + color: $white; + } +} \ No newline at end of file diff --git a/src/containers/Challenges/index.js b/src/containers/Challenges/index.js index f51dde62..6525e4b2 100644 --- a/src/containers/Challenges/index.js +++ b/src/containers/Challenges/index.js @@ -2,21 +2,39 @@ * Container to render Challenges page */ import _ from 'lodash' -import React, { Component } from 'react' +import React, { Component, Fragment } from 'react' // import { Redirect } from 'react-router-dom' import PropTypes from 'prop-types' import { connect } from 'react-redux' +import { DebounceInput } from 'react-debounce-input' import ChallengesComponent from '../../components/ChallengesComponent' +import ProjectCard from '../../components/ProjectCard' +import Loader from '../../components/Loader' import { loadChallengesByPage } from '../../actions/challenges' import { loadProject } from '../../actions/projects' -import { resetSidebarActiveParams } from '../../actions/sidebar' +import { loadProjects, setActiveProject, resetSidebarActiveParams } from '../../actions/sidebar' import { CHALLENGE_STATUS } from '../../config/constants' +import styles from './Challenges.module.scss' class Challenges extends Component { + constructor (props) { + super(props) + this.state = { + searchProjectName: '', + onlyMyProjects: true + } + + this.updateProjectName = this.updateProjectName.bind(this) + this.toggleMyProjects = this.toggleMyProjects.bind(this) + } + componentDidMount () { - const { activeProjectId, resetSidebarActiveParams, menu, projectId } = this.props + const { activeProjectId, resetSidebarActiveParams, menu, projectId, isLoading } = this.props + if (activeProjectId === -1 && !isLoading) { + this.props.loadProjects() + } if (menu === 'NULL' && activeProjectId !== -1) { resetSidebarActiveParams() } else { @@ -28,7 +46,9 @@ class Challenges extends Component { } componentWillReceiveProps (nextProps) { - this.reloadChallenges(nextProps) + if (this.props.activeProjectId !== nextProps.activeProjectId) { + this.reloadChallenges(nextProps) + } } reloadChallenges (props) { @@ -43,6 +63,17 @@ class Challenges extends Component { } } + updateProjectName (val) { + this.setState({ searchProjectName: val }) + this.props.loadProjects(val, this.state.onlyMyProjects) + } + + toggleMyProjects (evt) { + this.setState({ onlyMyProjects: evt.target.checked }, () => { + this.props.loadProjects(this.state.searchProjectName, this.state.onlyMyProjects) + }) + } + render () { const { challenges, @@ -56,26 +87,70 @@ class Challenges extends Component { loadChallengesByPage, page, perPage, - totalChallenges + totalChallenges, + setActiveProject } = this.props + const { searchProjectName, onlyMyProjects } = this.state const projectInfo = _.find(projects, { id: activeProjectId }) || {} + const projectComponents = projects.map(p => ( +
  • + +
  • + )) return ( - + +
    +
    + + this.updateProjectName(e.target.value)} + value={searchProjectName} + /> + + +
    + { + activeProjectId === -1 &&
    No project selected. Select one below
    + } + { + isLoading ? : ( +
      + {projectComponents} +
    + ) + } +
    + { activeProjectId !== -1 && + } +
    ) } } @@ -96,7 +171,9 @@ Challenges.propTypes = { resetSidebarActiveParams: PropTypes.func, page: PropTypes.number.isRequired, perPage: PropTypes.number.isRequired, - totalChallenges: PropTypes.number.isRequired + totalChallenges: PropTypes.number.isRequired, + loadProjects: PropTypes.func.isRequired, + setActiveProject: PropTypes.func.isRequired } const mapStateToProps = ({ challenges, sidebar, projects }) => ({ @@ -111,7 +188,9 @@ const mapStateToProps = ({ challenges, sidebar, projects }) => ({ const mapDispatchToProps = { loadChallengesByPage, resetSidebarActiveParams, - loadProject + loadProject, + loadProjects, + setActiveProject } export default connect(mapStateToProps, mapDispatchToProps)(Challenges) diff --git a/src/containers/Sidebar/index.js b/src/containers/Sidebar/index.js index b8764a94..ea8fa1ef 100644 --- a/src/containers/Sidebar/index.js +++ b/src/containers/Sidebar/index.js @@ -15,7 +15,7 @@ class SidebarContainer extends Component { } componentDidMount () { - this.props.loadProjects() + // this.props.loadProjects() const { projectId, activeProjectId } = this.props diff --git a/src/containers/TopbarContainer/index.js b/src/containers/TopbarContainer/index.js index d56bb7a5..3533e475 100644 --- a/src/containers/TopbarContainer/index.js +++ b/src/containers/TopbarContainer/index.js @@ -4,12 +4,19 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { loadUser } from '../../actions/auth' +import { setActiveProject } from '../../actions/sidebar' import { connect } from 'react-redux' import TopBar from '../../components/TopBar' class TopbarContainer extends Component { componentDidMount () { this.props.loadUser() + + const { projectId, activeProjectId } = this.props + + if (projectId && activeProjectId < 0) { + this.props.setActiveProject(parseInt(projectId)) + } } render () { @@ -20,7 +27,10 @@ class TopbarContainer extends Component { TopbarContainer.propTypes = { loadUser: PropTypes.func.isRequired, - auth: PropTypes.object.isRequired + setActiveProject: PropTypes.func.isRequired, + auth: PropTypes.object.isRequired, + activeProjectId: PropTypes.number, + projectId: PropTypes.string } const mapStateToProps = ({ auth }) => ({ @@ -28,7 +38,8 @@ const mapStateToProps = ({ auth }) => ({ }) const mapDispatchToProps = { - loadUser + loadUser, + setActiveProject } export default connect(mapStateToProps, mapDispatchToProps)(TopbarContainer) diff --git a/src/reducers/sidebar.js b/src/reducers/sidebar.js index 5e775474..3881840d 100644 --- a/src/reducers/sidebar.js +++ b/src/reducers/sidebar.js @@ -18,7 +18,7 @@ const initialState = { export default function (state = initialState, action) { switch (action.type) { case SET_ACTIVE_PROJECT: - return { ...state, activeProjectId: action.projectId } + return { ...state, activeProjectId: action.projectId, projects: [], isLoading: false } case LOAD_PROJECTS_SUCCESS: return { ...state, projects: action.projects, isLoading: false, isLoggedIn: true } case LOAD_PROJECTS_PENDING: diff --git a/src/routes.js b/src/routes.js index 72de1741..6e83c648 100644 --- a/src/routes.js +++ b/src/routes.js @@ -82,7 +82,7 @@ class Routes extends React.Component { renderApp( , - , + , )()} /> {/* If path is not defined redirect to landing page */}