Skip to content

Commit 89449ba

Browse files
Merge pull request topcoder-platform#5 from zjuasmn/stats
add member stats history/distribution/activeChallenges
2 parents 1f91d41 + aaa8043 commit 89449ba

File tree

3 files changed

+254
-0
lines changed

3 files changed

+254
-0
lines changed

src/actions/members.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { createActions } from 'redux-actions';
77
import { getService } from '../services/members';
88
import { getService as getUserService } from '../services/user';
9+
import { getService as getChallengesService } from '../services/challenges';
910

1011
/**
1112
* @static
@@ -104,6 +105,101 @@ async function getStatsDone(handle, uuid, tokenV3) {
104105
return { data, handle, uuid };
105106
}
106107

108+
/**
109+
* Payload creator for the action that inits the loading of member active challenges.
110+
* @param {String} handle
111+
* @param {String} uuid
112+
* @returns {Object} Payload
113+
*/
114+
async function getActiveChallengesInit(handle, uuid) {
115+
return { handle, uuid };
116+
}
117+
118+
/**
119+
* Payload creator for the action that loads the member active challenges.
120+
* @param {String} handle
121+
* @param {String} uuid
122+
* @param {String} tokenV3
123+
* @returns {Object} Payload
124+
*/
125+
async function getActiveChallengesDone(handle, uuid, tokenV3) {
126+
const filter = { status: 'ACTIVE' };
127+
const service = getChallengesService(tokenV3);
128+
/* TODO: Reuse `getAll` from `actions/challenge-listing`
129+
/* after it moved from `community-app` to here.
130+
*/
131+
function getAll(getter, page = 0, prev = null) {
132+
const PAGE_SIZE = 50;
133+
return getter({
134+
limit: PAGE_SIZE,
135+
offset: page * PAGE_SIZE,
136+
}).then(({ challenges: chunk }) => {
137+
if (!chunk.length) return prev || [];
138+
return getAll(getter, 1 + page, prev ? prev.concat(chunk) : chunk);
139+
});
140+
}
141+
const calls = [
142+
getAll(params =>
143+
service.getUserChallenges(handle, filter, params)),
144+
getAll(params =>
145+
service.getUserMarathonMatches(handle, filter, params)),
146+
];
147+
148+
const [challenges] = await Promise.all(calls);
149+
150+
return { handle, challenges, uuid };
151+
}
152+
153+
/**
154+
* @static
155+
* @desc Create an action that signals beginning of member stats distribution history.
156+
* @param {String} handle Member handle.
157+
* @param {String} uuid Operation UUID.
158+
* @return {Action}
159+
*/
160+
async function getStatsHistoryInit(handle, uuid) {
161+
return { handle, uuid };
162+
}
163+
164+
/**
165+
* @static
166+
* @desc Create an action that loads the member stats history.
167+
* @param {String} handle Member handle.
168+
* @param {String} uuid Operation UUID.
169+
* @param {String} tokenV3 v3 auth token.
170+
* @return {Action}
171+
*/
172+
async function getStatsHistoryDone(handle, uuid, tokenV3) {
173+
const data = await getService(tokenV3).getStatsHistory(handle);
174+
return { data, handle, uuid };
175+
}
176+
177+
/**
178+
* @static
179+
* @desc Create an action that signals beginning of member stats distribution loading.
180+
* @param {String} handle Member handle.
181+
* @param {String} uuid Operation UUID.
182+
* @return {Action}
183+
*/
184+
async function getStatsDistributionInit(handle, uuid) {
185+
return { handle, uuid };
186+
}
187+
188+
/**
189+
* @static
190+
* @desc Create an action that loads the member stats distribution.
191+
* @param {String} handle Member handle.
192+
* @param {String} track Main track name.
193+
* @param {String} subTrack Subtrack name.
194+
* @param {String} uuid Operation UUID.
195+
* @param {String} tokenV3 v3 auth token.
196+
* @return {Action}
197+
*/
198+
async function getStatsDistributionDone(handle, track, subTrack, uuid, tokenV3) {
199+
const data = await getService(tokenV3).getStatsDistribution(handle, track, subTrack);
200+
return { data, handle, uuid };
201+
}
202+
107203
export default createActions({
108204
MEMBERS: {
109205
DROP: drop,
@@ -114,5 +210,11 @@ export default createActions({
114210
GET_FINANCES_DONE: getFinancesDone,
115211
GET_STATS_INIT: getStatsInit,
116212
GET_STATS_DONE: getStatsDone,
213+
GET_STATS_HISTORY_INIT: getStatsHistoryInit,
214+
GET_STATS_HISTORY_DONE: getStatsHistoryDone,
215+
GET_STATS_DISTRIBUTION_INIT: getStatsDistributionInit,
216+
GET_STATS_DISTRIBUTION_DONE: getStatsDistributionDone,
217+
GET_ACTIVE_CHALLENGES_INIT: getActiveChallengesInit,
218+
GET_ACTIVE_CHALLENGES_DONE: getActiveChallengesDone,
117219
},
118220
});

src/reducers/members.js

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,126 @@ function onGetStatsDone(state, { error, payload }) {
162162
};
163163
}
164164

165+
/**
166+
* Inits the loading of member stats history.
167+
* @param {Object} state
168+
* @param {Object} action
169+
* @return {Object} New state.
170+
*/
171+
function onGetStatsHistoryInit(state, action) {
172+
const { handle, uuid } = action.payload;
173+
let res = state[handle];
174+
res = res ? _.clone(res) : {};
175+
res.statsHistory = { loadingUuid: uuid };
176+
return {
177+
...state,
178+
[handle]: res,
179+
};
180+
}
181+
182+
/**
183+
* Finalizes the loading of member stats history.
184+
* @param {Object} state
185+
* @param {Object} action
186+
* @return {Object} New state.
187+
*/
188+
function onGetStatsHistoryDone(state, { error, payload }) {
189+
if (error) {
190+
logger.error('Failed to get member statsHistory', payload);
191+
fireErrorMessage('Failed to get member statsHistory', '');
192+
return state;
193+
}
194+
195+
const { data, handle, uuid } = payload;
196+
if (uuid !== _.get(state[handle], 'statsHistory.loadingUuid')) return state;
197+
return {
198+
...state,
199+
[handle]: {
200+
...state[handle],
201+
statsHistory: { data, timestamp: Date.now() },
202+
},
203+
};
204+
}
205+
206+
/**
207+
* Inits the loading of member stats distribution.
208+
* @param {Object} state
209+
* @param {Object} action
210+
* @return {Object} New state.
211+
*/
212+
function onGetStatsDistributionInit(state, action) {
213+
const { handle, uuid } = action.payload;
214+
let res = state[handle];
215+
res = res ? _.clone(res) : {};
216+
res.statsDistribution = { loadingUuid: uuid };
217+
return {
218+
...state,
219+
[handle]: res,
220+
};
221+
}
222+
223+
/**
224+
* Finalizes the loading of member stats distribution.
225+
* @param {Object} state
226+
* @param {Object} action
227+
* @return {Object} New state.
228+
*/
229+
function onGetStatsDistributionDone(state, { error, payload }) {
230+
if (error) {
231+
logger.error('Failed to get member statsDistribution', payload);
232+
fireErrorMessage('Failed to get member statsDistribution', '');
233+
return state;
234+
}
235+
236+
const { data, handle, uuid } = payload;
237+
if (uuid !== _.get(state[handle], 'statsDistribution.loadingUuid')) return state;
238+
return {
239+
...state,
240+
[handle]: {
241+
...state[handle],
242+
statsDistribution: { data, timestamp: Date.now() },
243+
},
244+
};
245+
}
246+
247+
/**
248+
* Inits the loading of member active challenges.
249+
* @param {Object} state
250+
* @param {Object} action
251+
* @return {Object} New state.
252+
*/
253+
function onGetActiveChallengesInit(state, action) {
254+
const { handle } = action.payload;
255+
return {
256+
...state,
257+
[handle]: { ...state[handle], activeChallengesCount: null },
258+
};
259+
}
260+
261+
/**
262+
* Finalizes the loading of member active challenges.
263+
* @param {Object} state
264+
* @param {Object} action
265+
* @return {Object} New state.
266+
*/
267+
function onGetActiveChallengesDone(state, { error, payload }) {
268+
if (error) {
269+
logger.error('Failed to get member active challenges', payload);
270+
fireErrorMessage('Failed to get member active challenges', '');
271+
return state;
272+
}
273+
274+
const { handle, challenges } = payload;
275+
276+
return {
277+
...state,
278+
[handle]: {
279+
...state[handle],
280+
activeChallengesCount: challenges.length,
281+
},
282+
};
283+
}
284+
165285
/**
166286
* Creates a new Members reducer with the specified initial state.
167287
* @param {Object} initialState Optional. Initial state.
@@ -178,6 +298,12 @@ function create(initialState = {}) {
178298
[a.getFinancesDone]: onGetFinancesDone,
179299
[a.getStatsInit]: onGetStatsInit,
180300
[a.getStatsDone]: onGetStatsDone,
301+
[a.getStatsHistoryInit]: onGetStatsHistoryInit,
302+
[a.getStatsHistoryDone]: onGetStatsHistoryDone,
303+
[a.getStatsDistributionInit]: onGetStatsDistributionInit,
304+
[a.getStatsDistributionDone]: onGetStatsDistributionDone,
305+
[a.getActiveChallengesInit]: onGetActiveChallengesInit,
306+
[a.getActiveChallengesDone]: onGetActiveChallengesDone,
181307
}, initialState);
182308
}
183309

src/services/members.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* members via API V3.
55
*/
66

7+
import qs from 'qs';
78
import { getApiResponsePayloadV3 } from '../utils/tc';
89
import { getApiV3 } from './api';
910

@@ -84,6 +85,31 @@ class MembersService {
8485
return getApiResponsePayloadV3(res);
8586
}
8687

88+
/**
89+
* Gets member statistics history
90+
* @param {String} handle
91+
* @return {Promise} Resolves to the stats object.
92+
*/
93+
async getStatsHistory(handle) {
94+
const res = await this.private.api.get(`/members/${handle}/stats/history`);
95+
return getApiResponsePayloadV3(res);
96+
}
97+
98+
/**
99+
* Gets member statistics distribution
100+
* @param {String} handle
101+
* @param {String} track
102+
* @param {String} subTrack
103+
* @return {Promise} Resolves to the stats object.
104+
*/
105+
async getStatsDistribution(handle, track, subTrack) {
106+
const res = await this.private.api.get(`/members/stats/distribution?filter=${encodeURIComponent(qs.stringify({
107+
track,
108+
subTrack,
109+
}))}`);
110+
return getApiResponsePayloadV3(res);
111+
}
112+
87113
/**
88114
* Gets a list of suggested member names for the supplied partial.
89115
*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy