Skip to content

Commit

Permalink
add error messages, and async/await to leaderboard related enpoint calls
Browse files Browse the repository at this point in the history
  • Loading branch information
CollinBeczak committed Jan 9, 2024
1 parent 9f48640 commit ca96e27
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 56 deletions.
21 changes: 16 additions & 5 deletions src/components/HOCs/WithLeaderboard/WithLeaderboard.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import React, { Component } from 'react'
import { connect } from "react-redux"
import { bindActionCreators } from 'redux'
import _omit from 'lodash/omit'
import _isArray from 'lodash/isArray'
import _isBoolean from 'lodash/isBoolean'
import _map from 'lodash/map'
Expand All @@ -19,7 +22,7 @@ import { fetchLeaderboard, fetchLeaderboardForUser, fetchReviewerLeaderboard,
* @author [Neil Rotstan](https://github.com/nrotstan)
*/
const WithLeaderboard = function(WrappedComponent, initialMonthsPast=1, initialOptions={}) {
return class extends Component {
class WithLeaderboardClass extends Component {
state = {
leaderboard: null,
leaderboardLoading: false,
Expand Down Expand Up @@ -89,7 +92,7 @@ const WithLeaderboard = function(WrappedComponent, initialMonthsPast=1, initialO
this.setState({leaderboardLoading: true, showingCount, fetchId: currentFetch})

const fetch = userType === USER_TYPE_REVIEWER ?
fetchReviewerLeaderboard : fetchLeaderboard
this.props.fetchReviewerLeaderboard : this.props.fetchLeaderboard

fetch(...this.leaderboardParams(numberMonths, countryCode),
showingCount, startDate, endDate).then(leaderboard => {
Expand All @@ -98,7 +101,7 @@ const WithLeaderboard = function(WrappedComponent, initialMonthsPast=1, initialO

const userId = _get(this.props, 'user.id')
if (userId && !options.ignoreUser && userType !== USER_TYPE_REVIEWER) {
fetchLeaderboardForUser(userId, 1,
this.props.fetchLeaderboardForUser(userId, 1,
...this.leaderboardParams(numberMonths, countryCode),
startDate, endDate).then(userLeaderboard => {
this.mergeInUserLeaderboard(userLeaderboard)
Expand Down Expand Up @@ -207,7 +210,8 @@ const WithLeaderboard = function(WrappedComponent, initialMonthsPast=1, initialO
render() {
const moreResults = this.state.leaderboard ? this.state.showingCount <= this.state.leaderboard.length : true

return <WrappedComponent leaderboard={this.state.leaderboard}
return <WrappedComponent {..._omit(this.props, ['fetchLeaderboard', 'fetchLeaderboardForUser', 'fetchReviewerLeaderboard'])}
leaderboard={this.state.leaderboard}
leaderboardLoading={this.state.leaderboardLoading}
monthsPast={this.monthsPast()}
startDate={this.startDate()}
Expand All @@ -222,6 +226,13 @@ const WithLeaderboard = function(WrappedComponent, initialMonthsPast=1, initialO
{...this.props} />
}
}
return WithLeaderboardClass;
}

export default WithLeaderboard
const mapDispatchToProps = (dispatch) => bindActionCreators({ fetchLeaderboard, fetchLeaderboardForUser, fetchReviewerLeaderboard }, dispatch)


const WithCurrentLeaderboard = (WrappedComponent) =>
connect(null, mapDispatchToProps)(WithLeaderboard(WrappedComponent))

export default WithCurrentLeaderboard
8 changes: 4 additions & 4 deletions src/components/HOCs/WithUserMetrics/WithUserMetrics.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import format from 'date-fns/format'
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import _omit from 'lodash/omit'
import _get from 'lodash/get'
import { fetchLeaderboardForUser } from '../../../services/Leaderboard/Leaderboard'
Expand Down Expand Up @@ -31,7 +32,7 @@ export const WithUserMetrics = function(WrappedComponent, userProp) {
if ( this.props[userProp] &&
(!_get(this.props[userProp], 'settings.leaderboardOptOut') ||
_get(this.props[userProp], 'id') === _get(this.props.currentUser, 'userId'))) {
fetchLeaderboardForUser(this.props[userProp].id, 0, -1).then(userLeaderboard => {
this.props.fetchLeaderboardForUser(this.props[userProp].id, 0, -1).then(userLeaderboard => {
this.setState({loading: false, leaderboardMetrics: userLeaderboard[0]})
})

Expand Down Expand Up @@ -182,15 +183,14 @@ export const WithUserMetrics = function(WrappedComponent, userProp) {
setTasksReviewerMonthsPast={this.setTasksReviewerMonthsPast}
setTasksReviewerDateRange={this.setTasksReviewerDateRange}
loading={this.state.loading}
{..._omit(this.props, ['updateLeaderboardMetrics'])} />)
{..._omit(this.props, ['fetchLeaderboardForUser'])} />)
}
}
}

const mapStateToProps = () => ({})

const mapDispatchToProps = () => ({
})
const mapDispatchToProps = (dispatch) => bindActionCreators({ fetchLeaderboardForUser }, dispatch)

export default (WrappedComponent, userProp="targetUser") =>
connect(mapStateToProps, mapDispatchToProps)(WithUserMetrics(WrappedComponent, userProp))
2 changes: 2 additions & 0 deletions src/services/Error/AppErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export default {

leaderboard: {
fetchFailure: messages.leaderboardFetchFailure,
reviewerLeaderboard: messages.reviewerLeaderboard,
userFetchFailure: messages.userFetchFailure,
},

task: {
Expand Down
10 changes: 10 additions & 0 deletions src/services/Error/Messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ export default defineMessages({
defaultMessage: "Unable to fetch leaderboard.",
},

reviewerLeaderboard: {
id: "Errors.leaderboard.reviewerLeaderboard",
defaultMessage: "Unable to retrieve reviewer leaderboard data.",
},

userFetchFailure: {
id: "Errors.leaderboard.userFetchFailure",
defaultMessage: "Unable to retrieve leaderboard data for user.",
},

taskNone: {
id: "Errors.task.none",
defaultMessage: "No tasks remain in this challenge.",
Expand Down
114 changes: 67 additions & 47 deletions src/services/Leaderboard/Leaderboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import startOfMonth from 'date-fns/start_of_month'
import endOfDay from 'date-fns/end_of_day'
import { CHALLENGE_INCLUDE_LOCAL } from '../Challenge/Challenge'
import { setupCustomCache } from '../../utils/setupCustomCache'
import { addError } from '../Error/Error'
import AppErrors from '../Error/AppErrors'

// Default leaderboard count
export const DEFAULT_LEADERBOARD_COUNT = 10
Expand Down Expand Up @@ -33,47 +35,50 @@ const leaderboardCache = setupCustomCache(CACHE_TIME);
* filters, returning a Promise that resolves to the leaderboard data. Note
* that leaderboard data is *not* stored in the redux store.
*/
export const fetchLeaderboard = async (numberMonths=null, onlyEnabled=true,
forProjects=null, forChallenges=null,
forUsers=null, forCountries=null,
limit=10, startDate=null, endDate=null) => {
const params = {
limit,
onlyEnabled
}

initializeLeaderboardParams(params, numberMonths, forProjects, forChallenges,
forUsers, forCountries, startDate, endDate)

const cachedLeaderboard = leaderboardCache.get({}, params, GLOBAL_LEADERBOARD_CACHE);

if (cachedLeaderboard) {
return cachedLeaderboard;
}

try {
const results = await new Endpoint(api.users.leaderboard, { params }).execute()

if (results) {
leaderboardCache.set({}, params, results, GLOBAL_LEADERBOARD_CACHE)
}

return results
} catch (error) {
console.error('Error fetching leaderboard:', error)
return []
}
}
export const fetchLeaderboard = (numberMonths=null, onlyEnabled=true,
forProjects=null, forChallenges=null,
forUsers=null, forCountries=null,
limit=10, startDate=null, endDate=null) => {
const params = {
limit,
onlyEnabled
}
return async function (dispatch) {
initializeLeaderboardParams(params, numberMonths, forProjects, forChallenges,
forUsers, forCountries, startDate, endDate)

const cachedLeaderboard = leaderboardCache.get({}, params, GLOBAL_LEADERBOARD_CACHE);

if (cachedLeaderboard) {
return cachedLeaderboard;
}

try {
const results = await new Endpoint(api.users.leaderboard, { params }).execute()

if (results) {
leaderboardCache.set({}, params, results, GLOBAL_LEADERBOARD_CACHE)
}

return results
} catch (error) {
console.error('Error fetching leaderboard:', error)
dispatch(addError(AppErrors.leaderboard.fetchFailure))
return []
}
}
}

/**
* Retrieve leaderboard data for a user from the server for the given date range and
* filters, returning a Promise that resolves to the leaderboard data. Note
* that leaderboard data is *not* stored in the redux store.
*/
export const fetchLeaderboardForUser = async (userId, bracket=0, numberMonths=1,
export const fetchLeaderboardForUser = (userId, bracket=0, numberMonths=1,
onlyEnabled=true, forProjects=null, forChallenges=null,
forUsers, forCountries=null, startDate=null,
endDate=null) => {
return async function (dispatch) {
const params = {
bracket,
onlyEnabled
Expand All @@ -92,33 +97,48 @@ export const fetchLeaderboardForUser = async (userId, bracket=0, numberMonths=1,
return cachedLeaderboard;
}

const results = await new Endpoint(api.users.userLeaderboard, {variables, params}).execute()
try {
const results = await new Endpoint(api.users.userLeaderboard, {variables, params}).execute()

if (results) {
leaderboardCache.set(variables, params, results, USER_LEADERBOARD_CACHE)
}
if (results) {
leaderboardCache.set(variables, params, results, USER_LEADERBOARD_CACHE)
}

return results;
return results;
} catch (error) {
console.error('Error fetching leaderboard:', error)
dispatch(addError(AppErrors.leaderboard.userFetchFailure))
return null
}
}
}

/**
* Retrieve reviewer leaderboard data from the server for the given date range and
* filters, returning a Promise that resolves to the leaderboard data. Note
* that leaderboard data is *not* stored in the redux store.
*/
export const fetchReviewerLeaderboard = function(numberMonths=null, onlyEnabled=true,
export const fetchReviewerLeaderboard = (numberMonths=null, onlyEnabled=true,
forProjects=null, forChallenges=null,
forUsers=null, forCountries=null,
limit=10, startDate=null, endDate=null) {
const params = {
limit,
onlyEnabled
limit=10, startDate=null, endDate=null) => {
return async function (dispatch) {
try {
const params = {
limit,
onlyEnabled
}

initializeLeaderboardParams(params, numberMonths, forProjects, forChallenges,
forUsers, forCountries, startDate, endDate)
const result = await new Endpoint(api.users.reviewerLeaderboard, {params}).execute()
return result
} catch (error) {
console.error("Error in fetchReviewerLeaderboard:", error)
dispatch(addError(AppErrors.leaderboard.reviewerLeaderboard))
return []
}
}

initializeLeaderboardParams(params, numberMonths, forProjects, forChallenges,
forUsers, forCountries, startDate, endDate)

return new Endpoint(api.users.reviewerLeaderboard, {params}).execute()
}


Expand Down

0 comments on commit ca96e27

Please sign in to comment.