Skip to content

Commit 9fc8489

Browse files
author
Vikas Agarwal
committed
Github issue#1326, Load all active projects for customer card view
— Added infinite scroll to the customer’s view. It was necessary to load projects in paged manner because API does not support loading all project at once. API has hard limit of 20 for loading projects. As of Infinite scroll is causing two load calls when user scrolls to bottom, hence we might need to go with a simple load more button.
1 parent 55cf3ee commit 9fc8489

File tree

7 files changed

+76
-23
lines changed

7 files changed

+76
-23
lines changed

npm-shrinkwrap.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"react-datetime": "2.7.1",
8787
"react-dom": "^15.6.1",
8888
"react-dotdotdot": "^1.0.4",
89+
"react-infinite-scroller": "^1.1.1",
8990
"react-layout-pane": "^0.1.16",
9091
"react-modal": "^1.9.7",
9192
"react-redux": "^4.4.5",

src/projects/actions/loadProjects.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { loadMembers } from '../../actions/members'
1010

1111
// ignore action
1212
/*eslint-disable no-unused-vars */
13-
const getProjectsWithMembers = (dispatch, getState, criteria, pageNum) => {
13+
const getProjectsWithMembers = (dispatch, getState, criteria, pageNum, keepPrevious) => {
1414
return new Promise((resolve, reject) => {
1515
dispatch({
1616
type: GET_PROJECTS_SEARCH_CRITERIA,
@@ -38,7 +38,10 @@ const getProjectsWithMembers = (dispatch, getState, criteria, pageNum) => {
3838
}
3939
return dispatch({
4040
type: GET_PROJECTS,
41-
payload: getProjects(criteria, pageNum)
41+
payload: getProjects(criteria, pageNum),
42+
meta: {
43+
keepPrevious : true
44+
}
4245
})
4346
.then(({ value, action }) => {
4447
let userIds = []
@@ -59,11 +62,11 @@ const getProjectsWithMembers = (dispatch, getState, criteria, pageNum) => {
5962
}
6063
/*eslint-enable*/
6164

62-
export function loadProjects(criteria, pageNum=1) {
65+
export function loadProjects(criteria, pageNum=1, keepPrevious=false) {
6366
return (dispatch, getState) => {
6467
return dispatch({
6568
type: PROJECT_SEARCH,
66-
payload: getProjectsWithMembers(dispatch, getState, criteria, pageNum)
69+
payload: getProjectsWithMembers(dispatch, getState, criteria, pageNum, keepPrevious)
6770
})
6871
}
6972
}

src/projects/list/components/Projects/Projects.jsx

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ const errorHandler = showErrorMessageIfError(props => !props.error)
2727
const spinner = spinnerWhileLoading(props => !props.isLoading)
2828
const enhance = compose(errorHandler, spinner)
2929
const EnhancedGrid = enhance(ProjectsGridView)
30-
const EnhancedCards = enhance(ProjectsCardView)
30+
// not using enhance here to avoid duplciate loading spinner, we are already using infinte scroll's loader
31+
// FIXME: this is preventing spinner icon in inital load though
32+
const EnhancedCards = errorHandler(ProjectsCardView)
3133

3234
class Projects extends Component {
3335
constructor(props) {
@@ -37,15 +39,22 @@ class Projects extends Component {
3739
this.onPageChange = this.onPageChange.bind(this)
3840
this.applyFilters = this.applyFilters.bind(this)
3941
this.init = this.init.bind(this)
42+
this.removeScrollPosition = this.removeScrollPosition.bind(this)
4043
}
4144

4245
componentDidUpdate() {
4346
window.scrollTo(0, parseInt(window.sessionStorage.getItem('projectsPageScrollTop')))
4447
}
4548

4649
componentWillUnmount(){
47-
const scrollingElement = document.scrollingElement || document.documentElement
48-
window.sessionStorage.setItem('projectsPageScrollTop', scrollingElement.scrollTop)
50+
window.removeEventListener('beforeunload', this.removeScrollPosition)
51+
// if grid view, store projects scroll top for next mount
52+
if (this.props.gridView) {
53+
const scrollingElement = document.scrollingElement || document.documentElement
54+
window.sessionStorage.setItem('projectsPageScrollTop', scrollingElement.scrollTop)
55+
} else { // for card view remove the scroll position
56+
this.removeScrollPosition()
57+
}
4958
}
5059

5160
componentWillReceiveProps(nextProps) {
@@ -60,6 +69,11 @@ class Projects extends Component {
6069
this.init(this.props)
6170
}
6271

72+
componentDidMount() {
73+
// sets window unload hook to show unsaved changes alert and persist incomplete project
74+
window.addEventListener('beforeunload', this.removeScrollPosition)
75+
}
76+
6377
init(props) {
6478
document.title = 'Projects - Topcoder'
6579
// this.searchTermFromQuery = this.props.location.query.q || ''
@@ -81,8 +95,20 @@ class Projects extends Component {
8195
}
8296
}
8397

84-
onPageChange(pageNum) {
98+
removeScrollPosition() {
99+
// remove scroll position from local storage
85100
window.sessionStorage.removeItem('projectsPageScrollTop')
101+
}
102+
103+
onPageChange(pageNum) {
104+
// if grid view, remove scroll position on page change
105+
if (this.props.gridView) {
106+
window.sessionStorage.removeItem('projectsPageScrollTop')
107+
} else {
108+
// for card view update the scroll position in local storage
109+
const scrollingElement = document.scrollingElement || document.documentElement
110+
window.sessionStorage.setItem('projectsPageScrollTop', scrollingElement.scrollTop)
111+
}
86112
this.routeWithParams(this.props.criteria, pageNum)
87113
}
88114

@@ -129,6 +155,7 @@ class Projects extends Component {
129155
// onPageChange={this.onPageChange}
130156
// sortHandler={this.sortHandler}
131157
applyFilters={this.applyFilters}
158+
onPageChange={this.onPageChange}
132159
/>
133160
)
134161
return (
@@ -163,7 +190,8 @@ const mapStateToProps = ({ projectSearch, members, loadUser }) => {
163190
totalCount : projectSearch.totalCount,
164191
pageNum : projectSearch.pageNum,
165192
criteria : projectSearch.criteria,
166-
isPowerUser
193+
isPowerUser,
194+
gridView : isPowerUser
167195
}
168196
}
169197

src/projects/list/components/Projects/ProjectsCardView.jsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React, { PropTypes } from 'react'
22
import _ from 'lodash'
3+
import InfiniteScroll from 'react-infinite-scroller';
34
import ProjectCard from './ProjectCard'
45
import NewProjectCard from './NewProjectCard'
6+
import LoadingIndicator from '../../../../components/LoadingIndicator/LoadingIndicator'
57

68
import { setDuration } from '../../../../helpers/projectHelper'
79

@@ -11,7 +13,7 @@ require('./ProjectsGridView.scss')
1113
const ProjectsCardView = props => {
1214
//const { projects, members, totalCount, criteria, pageNum, applyFilters, sortHandler, onPageChange, error, isLoading, onNewProjectIntent } = props
1315
// TODO: use applyFilters and onNewProjectIntent. Temporary delete to avoid lint errors.
14-
const { projects, members, currentUser} = props
16+
const { projects, members, currentUser, onPageChange, pageNum, totalCount} = props
1517
// const currentSortField = _.get(criteria, 'sort', '')
1618

1719
// annotate projects with member data
@@ -38,8 +40,16 @@ const ProjectsCardView = props => {
3840
}
3941
return (
4042
<div className="projects card-view">
41-
{ projects.map(renderProject)}
42-
<div className="project-card"><NewProjectCard /></div>
43+
<InfiniteScroll
44+
initialLoad={false}
45+
pageStart={pageNum}
46+
loadMore={onPageChange}
47+
hasMore={ ((pageNum - 1) * 20 + 20 < totalCount)}
48+
loader={<LoadingIndicator />}
49+
>
50+
{ projects.map(renderProject)}
51+
<div className="project-card"><NewProjectCard /></div>
52+
</InfiniteScroll>
4353
</div>
4454
)
4555
}
@@ -51,13 +61,13 @@ ProjectsCardView.propTypes = {
5161
totalCount: PropTypes.number.isRequired,
5262
members: PropTypes.object.isRequired,
5363
// isLoading: PropTypes.bool.isRequired,
54-
error: PropTypes.bool.isRequired
64+
error: PropTypes.bool.isRequired,
5565
// there are no pagination, no sorting feature or no filtering for card view
5666
// hence commented all next
5767
// onPageChange: PropTypes.func.isRequired,
5868
// sortHandler: PropTypes.func.isRequired,
5969
// applyFilters: PropTypes.func.isRequired,
60-
// pageNum: PropTypes.number.isRequired,
70+
pageNum: PropTypes.number.isRequired,
6171
// criteria: PropTypes.object.isRequired
6272
}
6373

src/projects/list/components/Projects/ProjectsGridView.scss

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,13 @@
8686
}
8787

8888
.card-view {
89-
display: flex;
90-
flex-flow: row wrap;
91-
justify-content: center;
92-
max-width: 1160px;// media query needed for smaller/bigger screens
93-
margin: 20px auto;
89+
> div {// InfiniteScroll's div
90+
display: flex;
91+
flex-flow: row wrap;
92+
justify-content: center;
93+
max-width: 1160px;// media query needed for smaller/bigger screens
94+
margin: 20px auto;
95+
}
9496

9597
.project-card {
9698
margin-bottom: 4 * $base-unit;

src/projects/reducers/projectSearch.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
GET_PROJECTS_PENDING, GET_PROJECTS_SUCCESS, GET_PROJECTS_FAILURE,
44
LOAD_MORE_PROJECTS, CLEAR_PROJECT_SEARCH, GET_PROJECTS_SEARCH_CRITERIA
55
} from '../../config/constants'
6+
import update from 'react-addons-update'
67

78
export const initialState = {
89
isLoading: true,
@@ -44,10 +45,10 @@ export default function(state = initialState, action) {
4445
isLoading: false
4546
})
4647
case GET_PROJECTS_SUCCESS:
47-
return Object.assign({}, state, {
48-
projects: action.payload.projects,
49-
totalCount: action.payload.totalCount
50-
})
48+
const updatedProjects = action.meta.keepPrevious
49+
? { projects : { $push : action.payload.projects }, totalCount: { $set : action.payload.totalCount} }
50+
: { projects : { $set : action.payload.projects }, totalCount: { $set : action.payload.totalCount} }
51+
return update(state, updatedProjects)
5152

5253
case PROJECT_SEARCH_FAILURE:
5354
case GET_PROJECTS_FAILURE:

0 commit comments

Comments
 (0)