Skip to content

Commit 87dbaf3

Browse files
authored
Leaderboard refactor (#3274)
* Remove unused comments * Make direct requests for exporting leaderboard instead of caching in store * Remove action and reducer to get all users for overall leaderboards * Rename paginated overall leaderboard XP to just overall leaderboard XP * Rename endpoints for contest leaderboards * Remove unused leaderboard state fields * Rename request endpoints for contest-related operations * Remove toggles and inputs for leaderboard during course creation * Rename visibleEntries to count * Show leaderboards only after assessment has been published * Update tests after hiding leaderboards in contest * Use session hook instead of accessing individually
1 parent 85cf944 commit 87dbaf3

File tree

11 files changed

+102
-661
lines changed

11 files changed

+102
-661
lines changed

src/commons/application/ApplicationTypes.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ export const defaultAchievement: AchievementState = {
348348
};
349349

350350
export const defaultLeaderboard: LeaderboardState = {
351-
userXp: [],
352351
paginatedUserXp: { rows: [], userCount: 0 },
353352
contestScore: [],
354353
contestPopularVote: [],

src/commons/assessmentWorkspace/AssessmentWorkspace.tsx

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,7 @@ const AssessmentWorkspace: React.FC<AssessmentWorkspaceProps> = props => {
464464
const isTeamAssessment =
465465
assessmentOverview !== undefined ? assessmentOverview.maxTeamSize > 1 : false;
466466
const isContestVoting = question?.type === QuestionTypes.voting;
467+
const isPublished = assessmentOverview?.isPublished;
467468
const handleContestEntryClick = (_submissionId: number, answer: string) => {
468469
// TODO: Hardcoded to make use of the first editor tab. Refactoring is needed for this workspace to enable Folder mode.
469470
handleEditorValueChange(0, answer);
@@ -538,34 +539,38 @@ const AssessmentWorkspace: React.FC<AssessmentWorkspaceProps> = props => {
538539
/>
539540
),
540541
id: SideContentType.contestVoting
541-
},
542-
{
543-
label: 'Score Leaderboard',
544-
iconName: IconNames.CROWN,
545-
body: (
546-
<SideContentContestLeaderboard
547-
handleContestEntryClick={handleContestEntryClick}
548-
orderedContestEntries={(question as IContestVotingQuestion)?.scoreLeaderboard ?? []}
549-
leaderboardType={SideContentType.scoreLeaderboard}
550-
/>
551-
),
552-
id: SideContentType.scoreLeaderboard
553-
},
554-
{
555-
label: 'Popular Vote Leaderboard',
556-
iconName: IconNames.PEOPLE,
557-
body: (
558-
<SideContentContestLeaderboard
559-
handleContestEntryClick={handleContestEntryClick}
560-
orderedContestEntries={
561-
(question as IContestVotingQuestion)?.popularVoteLeaderboard ?? []
562-
}
563-
leaderboardType={SideContentType.popularVoteLeaderboard}
564-
/>
565-
),
566-
id: SideContentType.popularVoteLeaderboard
567542
}
568543
);
544+
if (isPublished) {
545+
tabs.push(
546+
{
547+
label: 'Score Leaderboard',
548+
iconName: IconNames.CROWN,
549+
body: (
550+
<SideContentContestLeaderboard
551+
handleContestEntryClick={handleContestEntryClick}
552+
orderedContestEntries={(question as IContestVotingQuestion)?.scoreLeaderboard ?? []}
553+
leaderboardType={SideContentType.scoreLeaderboard}
554+
/>
555+
),
556+
id: SideContentType.scoreLeaderboard
557+
},
558+
{
559+
label: 'Popular Vote Leaderboard',
560+
iconName: IconNames.PEOPLE,
561+
body: (
562+
<SideContentContestLeaderboard
563+
handleContestEntryClick={handleContestEntryClick}
564+
orderedContestEntries={
565+
(question as IContestVotingQuestion)?.popularVoteLeaderboard ?? []
566+
}
567+
leaderboardType={SideContentType.popularVoteLeaderboard}
568+
/>
569+
),
570+
id: SideContentType.popularVoteLeaderboard
571+
}
572+
);
573+
}
569574
} else {
570575
tabs.push(
571576
{

src/commons/assessmentWorkspace/__tests__/__snapshots__/AssessmentWorkspace.test.tsx.snap

Lines changed: 0 additions & 468 deletions
Large diffs are not rendered by default.

src/commons/dropdown/DropdownCreateCourse.tsx

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ const DropdownCreateCourse: React.FC<Props> = props => {
4040
enableAchievements: true,
4141
enableSourcecast: true,
4242
enableStories: false,
43-
enableOverallLeaderboard: true,
44-
enableContestLeaderboard: true,
45-
topLeaderboardDisplay: 100,
46-
topContestLeaderboardDisplay: 10,
4743
sourceChapter: Chapter.SOURCE_1,
4844
sourceVariant: Variant.DEFAULT,
4945
moduleHelpText: ''
@@ -201,28 +197,6 @@ const DropdownCreateCourse: React.FC<Props> = props => {
201197
})
202198
}
203199
/>
204-
<Switch
205-
checked={courseConfig.enableOverallLeaderboard}
206-
inline
207-
label="Enable Overall Leaderboard"
208-
onChange={e =>
209-
setCourseConfig({
210-
...courseConfig,
211-
enableOverallLeaderboard: (e.target as HTMLInputElement).checked
212-
})
213-
}
214-
/>
215-
<Switch
216-
checked={courseConfig.enableContestLeaderboard}
217-
inline
218-
label="Enable Contest Leaderboard"
219-
onChange={e =>
220-
setCourseConfig({
221-
...courseConfig,
222-
enableContestLeaderboard: (e.target as HTMLInputElement).checked
223-
})
224-
}
225-
/>
226200
</div>
227201
<div>
228202
<Switch
@@ -262,42 +236,6 @@ const DropdownCreateCourse: React.FC<Props> = props => {
262236
/>
263237
</div>
264238
</div>
265-
<div>
266-
<FormGroup
267-
label="Leaderboard Top XX Display"
268-
labelInfo="(configurable later on)"
269-
labelFor="leaderboard-top-display"
270-
>
271-
<InputGroup
272-
id="leaderboard-top-display"
273-
value={String(courseConfig.topLeaderboardDisplay)}
274-
onChange={e =>
275-
setCourseConfig({
276-
...courseConfig,
277-
topLeaderboardDisplay: Number(e.target.value)
278-
})
279-
}
280-
/>
281-
</FormGroup>
282-
</div>
283-
<div>
284-
<FormGroup
285-
label="Contest Leaderboard Top XX Display"
286-
labelInfo="(configurable later on)"
287-
labelFor="contest-leaderboard-top-display"
288-
>
289-
<InputGroup
290-
id="contest-leaderboard-top-display"
291-
value={String(courseConfig.topContestLeaderboardDisplay)}
292-
onChange={e =>
293-
setCourseConfig({
294-
...courseConfig,
295-
topContestLeaderboardDisplay: Number(e.target.value)
296-
})
297-
}
298-
/>
299-
</FormGroup>
300-
</div>
301239
<div>
302240
<FormGroup
303241
label="Default Source Chapter"

src/commons/sagas/LeaderboardSaga.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,20 @@ import { actions } from '../utils/ActionsHelper';
77
import { selectTokens } from './BackendSaga';
88
import {
99
getAllContests,
10-
getAllTotalXp,
1110
getContestPopularVoteLeaderboard,
1211
getContestScoreLeaderboard,
13-
getPaginatedTotalXp
12+
getOverallLeaderboardXP
1413
} from './RequestsSaga';
1514

1615
const LeaderboardSaga = combineSagaHandlers({
17-
[LeaderboardActions.getAllUsersXp.type]: function* () {
18-
const tokens: Tokens = yield selectTokens();
19-
20-
const usersXp = yield call(getAllTotalXp, tokens);
21-
22-
if (usersXp) {
23-
yield put(actions.saveAllUsersXp(usersXp));
24-
}
25-
},
26-
27-
[LeaderboardActions.getPaginatedLeaderboardXp.type]: function* (action) {
16+
[LeaderboardActions.getOverallLeaderboardXP.type]: function* (action) {
2817
const tokens: Tokens = yield selectTokens();
2918
const { page, pageSize } = action.payload;
3019

31-
const paginatedUsersXp = yield call(getPaginatedTotalXp, page, pageSize, tokens);
20+
const paginatedUsersXp = yield call(getOverallLeaderboardXP, page, pageSize, tokens);
3221

3322
if (paginatedUsersXp) {
34-
yield put(actions.savePaginatedLeaderboardXp(paginatedUsersXp));
23+
yield put(actions.saveOverallLeaderboardXP(paginatedUsersXp));
3524
}
3625
},
3726

src/commons/sagas/RequestsSaga.ts

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -463,10 +463,12 @@ export const getTotalXp = async (tokens: Tokens, courseRegId?: number): Promise<
463463
};
464464

465465
/**
466-
* GET /courses/{courseId}/all_user_xp
466+
* GET /courses/{courseId}/leaderboards/xp_all
467467
*/
468-
export const getAllTotalXp = async (tokens: Tokens): Promise<number | null> => {
469-
const resp = await request(`${courseId()}/all_users_xp`, 'GET', {
468+
export const getAllOverallLeaderboardXP = async (
469+
tokens: Tokens
470+
): Promise<LeaderboardRow[] | null> => {
471+
const resp = await request(`${courseId()}/leaderboards/xp_all`, 'GET', {
470472
...tokens
471473
});
472474

@@ -489,16 +491,16 @@ export const getAllTotalXp = async (tokens: Tokens): Promise<number | null> => {
489491
};
490492

491493
/**
492-
* GET /courses/{courseId}/get_paginated_display
494+
* GET /courses/{courseId}/leaderboards/xp
493495
*/
494-
export const getPaginatedTotalXp = async (
496+
export const getOverallLeaderboardXP = async (
495497
page: number,
496498
pageSize: number,
497499
tokens: Tokens
498500
): Promise<{ rows: LeaderboardRow[]; userCount: number } | null> => {
499501
const offset = (page - 1) * pageSize;
500502
const params = new URLSearchParams({ offset: `${offset}`, page_size: `${pageSize}` });
501-
const resp = await request(`${courseId()}/get_paginated_display?${params.toString()}`, 'GET', {
503+
const resp = await request(`${courseId()}/leaderboards/xp?${params.toString()}`, 'GET', {
502504
...tokens
503505
});
504506

@@ -523,16 +525,16 @@ export const getPaginatedTotalXp = async (
523525
};
524526

525527
/**
526-
* GET /courses/{courseId}/assessments/{assessmentid}/scoreLeaderboard
528+
* GET /courses/{courseId}/assessments/{assessmentid}/contest_score_leaderboard
527529
*/
528530
export const getContestScoreLeaderboard = async (
529531
assessmentId: number,
530-
visibleEntries: number,
532+
count: number,
531533
tokens: Tokens
532534
): Promise<ContestLeaderboardRow[] | null> => {
533-
const params = new URLSearchParams({ visible_entries: `${visibleEntries}` });
535+
const params = new URLSearchParams({ count: `${count}` });
534536
const resp = await request(
535-
`${courseId()}/assessments/${assessmentId}/scoreLeaderboard?${params.toString()}`,
537+
`${courseId()}/assessments/${assessmentId}/contest_score_leaderboard?${params.toString()}`,
536538
'GET',
537539
{
538540
...tokens
@@ -560,16 +562,16 @@ export const getContestScoreLeaderboard = async (
560562
};
561563

562564
/**
563-
* GET /courses/{courseId}/assessments/{assessmentid}/popularVoteLeaderboard
565+
* GET /courses/{courseId}/assessments/{assessmentid}/contest_popular_leaderboard
564566
*/
565567
export const getContestPopularVoteLeaderboard = async (
566568
assessmentId: number,
567-
visibleEntries: number,
569+
count: number,
568570
tokens: Tokens
569571
): Promise<ContestLeaderboardRow[] | null> => {
570-
const params = new URLSearchParams({ visible_entries: `${visibleEntries}` });
572+
const params = new URLSearchParams({ count: `${count}` });
571573
const resp = await request(
572-
`${courseId()}/assessments/${assessmentId}/popularVoteLeaderboard?${params.toString()}`,
574+
`${courseId()}/assessments/${assessmentId}/contest_popular_leaderboard?${params.toString()}`,
573575
'GET',
574576
{
575577
...tokens
@@ -1300,14 +1302,14 @@ export const deleteSourcecastEntry = async (
13001302
};
13011303

13021304
/**
1303-
* POST /courses/{courseId}/admin/assessments/{assessmentId}/calculateContestScore
1305+
* POST /courses/{courseId}/admin/assessments/{assessmentId}/contest_calculate_score
13041306
*/
13051307
export const calculateContestScore = async (
13061308
assessmentId: number,
13071309
tokens: Tokens
13081310
): Promise<Response | null> => {
13091311
const resp = await request(
1310-
`${courseId()}/admin/assessments/${assessmentId}/calculateContestScore`,
1312+
`${courseId()}/admin/assessments/${assessmentId}/contest_calculate_score`,
13111313
'POST',
13121314
{
13131315
...tokens
@@ -1318,14 +1320,14 @@ export const calculateContestScore = async (
13181320
};
13191321

13201322
/**
1321-
* POST /courses/{courseId}/admin/assessments/{assessmentId}/dispatchContestXp
1323+
* POST /courses/{courseId}/admin/assessments/{assessmentId}/contest_dispatch_xp
13221324
*/
13231325
export const dispatchContestXp = async (
13241326
assessmentId: number,
13251327
tokens: Tokens
13261328
): Promise<Response | null> => {
13271329
const resp = await request(
1328-
`${courseId()}/admin/assessments/${assessmentId}/dispatchContestXp`,
1330+
`${courseId()}/admin/assessments/${assessmentId}/contest_dispatch_xp`,
13291331
'POST',
13301332
{
13311333
...tokens
@@ -1336,16 +1338,16 @@ export const dispatchContestXp = async (
13361338
};
13371339

13381340
/**
1339-
* GET /courses/{courseId}/assessments/{assessmentId}/scoreLeaderboard
1341+
* GET /courses/{courseId}/assessments/{assessmentId}/contest_score_leaderboard
13401342
*/
13411343
export const getScoreLeaderboard = async (
13421344
assessmentId: number,
1343-
visibleEntries: number | undefined,
1345+
count: number | undefined,
13441346
tokens: Tokens
13451347
): Promise<ContestEntry[] | null> => {
1346-
const params = new URLSearchParams({ visible_entries: `${visibleEntries}` });
1348+
const params = new URLSearchParams({ count: `${count}` });
13471349
const resp = await request(
1348-
`${courseId()}/assessments/${assessmentId}/scoreLeaderboard?${params.toString()}`,
1350+
`${courseId()}/assessments/${assessmentId}/contest_score_leaderboard?${params.toString()}`,
13491351
'GET',
13501352
{
13511353
...tokens
@@ -1368,16 +1370,16 @@ export const getScoreLeaderboard = async (
13681370
};
13691371

13701372
/**
1371-
* GET /courses/{courseId}/assessments/{assessmentId}/popularVoteLeaderboard
1373+
* GET /courses/{courseId}/assessments/{assessmentId}/contest_popular_leaderboard
13721374
*/
13731375
export const getPopularVoteLeaderboard = async (
13741376
assessmentId: number,
1375-
visibleEntries: number | undefined,
1377+
count: number | undefined,
13761378
tokens: Tokens
13771379
): Promise<ContestEntry[] | null> => {
1378-
const params = new URLSearchParams({ visible_entries: `${visibleEntries}` });
1380+
const params = new URLSearchParams({ count: `${count}` });
13791381
const resp = await request(
1380-
`${courseId()}/assessments/${assessmentId}/popularVoteLeaderboard?${params.toString()}`,
1382+
`${courseId()}/assessments/${assessmentId}/contest_popular_leaderboard?${params.toString()}`,
13811383
'GET',
13821384
{
13831385
...tokens

src/features/leaderboard/LeaderboardActions.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ import {
77
} from './LeaderboardTypes';
88

99
const LeaderboardActions = createActions('leaderboard', {
10-
getAllUsersXp: 0,
11-
saveAllUsersXp: (userXp: LeaderboardRow[]) => userXp,
12-
getPaginatedLeaderboardXp: (page: number, pageSize: number) => ({ page, pageSize }),
13-
savePaginatedLeaderboardXp: (payload: { rows: LeaderboardRow[]; userCount: number }) => payload,
10+
getOverallLeaderboardXP: (page: number, pageSize: number) => ({ page, pageSize }),
11+
saveOverallLeaderboardXP: (payload: { rows: LeaderboardRow[]; userCount: number }) => payload,
1412
getAllContestScores: (assessmentId: number, visibleEntries: number) => ({
1513
assessmentId,
1614
visibleEntries

src/features/leaderboard/LeaderboardReducer.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ export const LeaderboardReducer: Reducer<LeaderboardState, SourceActionType> = c
99
defaultLeaderboard,
1010
builder => {
1111
builder
12-
.addCase(LeaderboardActions.saveAllUsersXp, (state, action) => {
13-
state.userXp = action.payload;
14-
})
15-
.addCase(LeaderboardActions.savePaginatedLeaderboardXp, (state, action) => {
12+
.addCase(LeaderboardActions.saveOverallLeaderboardXP, (state, action) => {
1613
state.paginatedUserXp = {
1714
rows: action.payload.rows || [],
1815
userCount: action.payload.userCount || 0

src/features/leaderboard/LeaderboardTypes.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export type ContestLeaderboardRow = {
1919
};
2020

2121
export type LeaderboardState = {
22-
userXp: LeaderboardRow[];
2322
paginatedUserXp: { rows: LeaderboardRow[]; userCount: number };
2423
contestScore: ContestLeaderboardRow[];
2524
contestPopularVote: ContestLeaderboardRow[];

0 commit comments

Comments
 (0)