Skip to content

Commit 4f268c0

Browse files
authored
Merge pull request #176 from suppermancool/issue-171
#171 Fix service calls on root page
2 parents 3b6775e + c34a858 commit 4f268c0

File tree

9 files changed

+737
-202
lines changed

9 files changed

+737
-202
lines changed

package-lock.json

+524-113
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"babel-plugin-named-asset-import": "^0.3.0",
1717
"babel-preset-react-app": "^7.0.0",
1818
"bfj": "6.1.1",
19+
"bootstrap": "^4.4.1",
1920
"case-sensitive-paths-webpack-plugin": "2.1.2",
2021
"chalk": "2.4.1",
2122
"classnames": "^2.2.6",
@@ -71,6 +72,7 @@
7172
"react-dropzone": "^10.1.5",
7273
"react-google-charts": "^3.0.13",
7374
"react-helmet": "^5.2.0",
75+
"react-js-pagination": "^3.0.3",
7476
"react-redux": "^6.0.0",
7577
"react-redux-toastr": "^7.5.1",
7678
"react-router-dom": "^4.3.1",

src/actions/challenges.js

+46-15
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,59 @@ import {
2828
LOAD_CHALLENGE_RESOURCES_SUCCESS,
2929
LOAD_CHALLENGE_RESOURCES_FAILURE,
3030
REMOVE_ATTACHMENT,
31-
PAGE_SIZE,
32-
SET_FILTER_CHALLENGE_VALUE
31+
PAGE_SIZE
3332
} from '../config/constants'
3433
import { fetchProjectById } from '../services/projects'
3534

3635
/**
3736
* Member challenges related redux actions
3837
*/
3938

39+
/**
40+
* Loads active challenges of project by page
41+
*/
42+
export function loadChallengesByPage (page, projectId, status, filterChallengeName = null) {
43+
return (dispatch, getState) => {
44+
dispatch({
45+
type: LOAD_CHALLENGES_PENDING,
46+
challenges: [],
47+
projectId: projectId ? `${projectId}` : '',
48+
status,
49+
filterChallengeName,
50+
perPage: PAGE_SIZE,
51+
page
52+
})
53+
54+
const filters = {}
55+
if (!_.isEmpty(filterChallengeName)) {
56+
filters['name'] = filterChallengeName
57+
}
58+
if (_.isInteger(projectId) && projectId > 0) {
59+
filters['projectId'] = projectId
60+
}
61+
if (!_.isEmpty(status)) {
62+
filters['status'] = status === '' ? undefined : _.startCase(status.toLowerCase())
63+
} else if (!(_.isInteger(projectId) && projectId > 0)) {
64+
filters['status'] = 'Active'
65+
}
66+
67+
return fetchChallenges(filters, {
68+
page,
69+
perPage: PAGE_SIZE,
70+
memberId: getState().auth.user ? getState().auth.user.userId : null
71+
}).then((res) => {
72+
dispatch({
73+
type: LOAD_CHALLENGES_SUCCESS,
74+
challenges: res.data,
75+
totalChallenges: parseInt(_.get(res, 'headers.x-total', '0'))
76+
})
77+
}).catch(() => dispatch({
78+
type: LOAD_CHALLENGES_FAILURE,
79+
challenges: []
80+
}))
81+
}
82+
}
83+
4084
/**
4185
* Loads active challenges of project
4286
*/
@@ -234,19 +278,6 @@ export function removeAttachment (attachmentId) {
234278
}
235279
}
236280

237-
/**
238-
* Set filter challenge value
239-
* @param value
240-
*/
241-
export function setFilterChallengeValue (value) {
242-
return (dispatch) => {
243-
dispatch({
244-
type: SET_FILTER_CHALLENGE_VALUE,
245-
value
246-
})
247-
}
248-
}
249-
250281
export function loadChallengeTerms () {
251282
return async (dispatch) => {
252283
const challengeTerms = await fetchChallengeTerms()

src/components/ChallengesComponent/ChallengeList/ChallengeList.module.scss

+6
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,9 @@
106106
text-decoration: none;
107107
}
108108
}
109+
110+
.paginationContainer {
111+
display: flex;
112+
justify-content: flex-end;
113+
margin-top: 30px;
114+
}

src/components/ChallengesComponent/ChallengeList/index.js

+47-8
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,28 @@ import React, { Component } from 'react'
66
import PropTypes from 'prop-types'
77
import { DebounceInput } from 'react-debounce-input'
88
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'
9+
import Pagination from 'react-js-pagination'
910

1011
import 'react-tabs/style/react-tabs.css'
1112
import styles from './ChallengeList.module.scss'
1213
import NoChallenge from '../NoChallenge'
1314
import ChallengeCard from '../ChallengeCard'
1415
import Message from '../Message'
16+
1517
import {
1618
CHALLENGE_STATUS
1719
} from '../../../config/constants'
1820

21+
require('bootstrap/scss/bootstrap.scss')
22+
1923
class ChallengeList extends Component {
2024
constructor (props) {
2125
super(props)
2226
this.state = {
2327
searchText: this.props.filterChallengeName
2428
}
2529
this.directUpdateSearchParam = this.updateSearchParam.bind(this) // update search param without debounce
30+
this.handlePageChange = this.handlePageChange.bind(this) // update search param without debounce
2631
this.updateSearchParam = debounce(this.updateSearchParam.bind(this), 1000)
2732
}
2833

@@ -32,17 +37,36 @@ class ChallengeList extends Component {
3237
* @param {String} projectStatus project status
3338
*/
3439
updateSearchParam (searchText, projectStatus) {
35-
this.setState({ searchText })
36-
const { setFilterChallengeValue } = this.props
37-
setFilterChallengeValue({
38-
name: searchText,
39-
status: projectStatus
40+
const { status, filterChallengeName, loadChallengesByPage, activeProjectId } = this.props
41+
this.setState({ searchText }, () => {
42+
if (status !== projectStatus || searchText !== filterChallengeName) {
43+
loadChallengesByPage(1, activeProjectId, projectStatus, searchText)
44+
}
4045
})
4146
}
4247

48+
/**
49+
* Update filter for getting project by pagination
50+
* @param {Number} pageNumber page numer
51+
*/
52+
handlePageChange (pageNumber) {
53+
const { searchText } = this.state
54+
const { page, loadChallengesByPage, activeProjectId, status } = this.props
55+
if (page !== pageNumber) {
56+
loadChallengesByPage(pageNumber, activeProjectId, status, searchText)
57+
}
58+
}
59+
4360
render () {
4461
const { searchText } = this.state
45-
const { activeProject, warnMessage, challenges, status } = this.props
62+
const {
63+
activeProject,
64+
warnMessage,
65+
challenges,
66+
status,
67+
page,
68+
perPage,
69+
totalChallenges } = this.props
4670
if (warnMessage) {
4771
return <Message warnMessage={warnMessage} />
4872
}
@@ -123,6 +147,17 @@ class ChallengeList extends Component {
123147
</ul>
124148
)
125149
}
150+
<div className={styles.paginationContainer}>
151+
<Pagination
152+
activePage={page}
153+
itemsCountPerPage={perPage}
154+
totalItemsCount={totalChallenges}
155+
pageRangeDisplayed={5}
156+
onChange={this.handlePageChange}
157+
itemClass='page-item'
158+
linkClass='page-link'
159+
/>
160+
</div>
126161
</div>
127162
)
128163
}
@@ -138,9 +173,13 @@ ChallengeList.propTypes = {
138173
name: PropTypes.string
139174
}),
140175
warnMessage: PropTypes.string,
141-
setFilterChallengeValue: PropTypes.func,
142176
filterChallengeName: PropTypes.string,
143-
status: PropTypes.string
177+
status: PropTypes.string,
178+
activeProjectId: PropTypes.number,
179+
loadChallengesByPage: PropTypes.func.isRequired,
180+
page: PropTypes.number.isRequired,
181+
perPage: PropTypes.number.isRequired,
182+
totalChallenges: PropTypes.number.isRequired
144183
}
145184

146185
export default ChallengeList

src/components/ChallengesComponent/index.js

+62-12
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,69 @@ import styles from './ChallengesComponent.module.scss'
1414
import Loader from '../Loader'
1515
import xss from 'xss'
1616

17-
const ChallengesComponent = ({ challenges, isLoading, warnMessage, setFilterChallengeValue, filterChallengeName, activeProject, status }) => {
17+
const ChallengesComponent = ({
18+
challenges,
19+
isLoading,
20+
warnMessage,
21+
filterChallengeName,
22+
activeProject,
23+
status,
24+
loadChallengesByPage,
25+
activeProjectId,
26+
page,
27+
perPage,
28+
totalChallenges
29+
}) => {
1830
return (
1931
<Sticky top={10} bottomBoundary='#SidebarContainer'>
2032
<div>
2133
<Helmet title={activeProject ? activeProject.name : ''} />
2234
<div className={styles.titleContainer}>
23-
{(activeProject && activeProject.id) ? (<a className={styles.buttonLaunchNew} href={`${CONNECT_APP_URL}/projects/${activeProject.id}`} target={'_blank'}>
24-
<PrimaryButton text={'View Project in Connect'} type={'info'} />
25-
</a>) : (<span />)}
26-
<div className={styles.title} dangerouslySetInnerHTML={{ __html: xss(activeProject ? activeProject.name : '') }} />
27-
{(activeProject && activeProject.id) ? (<Link className={styles.buttonLaunchNew} to={`/projects/${activeProject.id}/challenges/new`}>
28-
<PrimaryButton text={'Launch New'} type={'info'} />
29-
</Link>) : (<span />)}
35+
{(activeProject && activeProject.id) ? (
36+
<a
37+
className={styles.buttonLaunchNew}
38+
href={`${CONNECT_APP_URL}/projects/${activeProject.id}`}
39+
target={'_blank'}
40+
>
41+
<PrimaryButton text={'View Project in Connect'} type={'info'} />
42+
</a>
43+
) : (
44+
<span />
45+
)}
46+
<div
47+
className={styles.title}
48+
dangerouslySetInnerHTML={{
49+
__html: xss(activeProject ? activeProject.name : '')
50+
}}
51+
/>
52+
{(activeProject && activeProject.id) ? (
53+
<Link
54+
className={styles.buttonLaunchNew}
55+
to={`/projects/${activeProject.id}/challenges/new`}
56+
>
57+
<PrimaryButton text={'Launch New'} type={'info'} />
58+
</Link>
59+
) : (
60+
<span />
61+
)}
3062
</div>
3163
<div className={styles.challenges}>
32-
{isLoading && challenges.length === 0 ? <Loader /> : <ChallengeList challenges={challenges} warnMessage={warnMessage} activeProject={activeProject} setFilterChallengeValue={setFilterChallengeValue} filterChallengeName={filterChallengeName} status={status} />}
33-
{isLoading && challenges.length > 0 && <Loader />}
64+
{isLoading ? (
65+
<Loader />
66+
) : (
67+
<ChallengeList
68+
challenges={challenges}
69+
warnMessage={warnMessage}
70+
activeProject={activeProject}
71+
filterChallengeName={filterChallengeName}
72+
status={status}
73+
loadChallengesByPage={loadChallengesByPage}
74+
activeProjectId={activeProjectId}
75+
page={page}
76+
perPage={perPage}
77+
totalChallenges={totalChallenges}
78+
/>
79+
)}
3480
</div>
3581
</div>
3682
</Sticky>
@@ -45,9 +91,13 @@ ChallengesComponent.propTypes = {
4591
}),
4692
isLoading: PropTypes.bool,
4793
warnMessage: PropTypes.string,
48-
setFilterChallengeValue: PropTypes.func,
4994
filterChallengeName: PropTypes.string,
50-
status: PropTypes.string
95+
status: PropTypes.string,
96+
activeProjectId: PropTypes.number,
97+
loadChallengesByPage: PropTypes.func.isRequired,
98+
page: PropTypes.number.isRequired,
99+
perPage: PropTypes.number.isRequired,
100+
totalChallenges: PropTypes.number.isRequired
51101
}
52102

53103
ChallengesComponent.defaultProps = {

src/containers/ChallengeEditor/index.js

-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
loadChallengeDetails,
1414
createAttachment,
1515
removeAttachment,
16-
setFilterChallengeValue,
1716
loadResources,
1817
loadResourceRoles
1918
} from '../../actions/challenges'
@@ -137,7 +136,6 @@ const mapDispatchToProps = {
137136
createAttachment,
138137
removeAttachment,
139138
loadChallengeTerms,
140-
setFilterChallengeValue,
141139
loadResources,
142140
loadResourceRoles
143141
}

0 commit comments

Comments
 (0)