Skip to content

Commit 560bfb8

Browse files
authored
Merge pull request #3080 from codecrafters-io/pk-branch-4
feat(leaderboard): show accurate stage counts and add header explanations
2 parents 7170243 + a37c720 commit 560bfb8

File tree

10 files changed

+58
-52
lines changed

10 files changed

+58
-52
lines changed

app/components/leaderboard-page/entries-table.hbs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,7 @@
33
<div>
44
<table class="min-w-full bg-white">
55
<thead>
6-
<tr>
7-
<LeaderboardPage::EntriesTable::HeaderRowCell @title="Rank" @alignment="left" />
8-
<LeaderboardPage::EntriesTable::HeaderRowCell @title="User" @alignment="left" />
9-
10-
<LeaderboardPage::EntriesTable::HeaderRowCell
11-
@title="Stages Completed"
12-
@alignment="right"
13-
class="hidden md:table-cell"
14-
@explanationMarkdown={{this.explanationMarkdownForStagesCompleted}}
15-
/>
16-
17-
<LeaderboardPage::EntriesTable::HeaderRowCell
18-
@title="Score"
19-
@alignment="right"
20-
@explanationMarkdown={{this.explanationMarkdownForScore}}
21-
/>
22-
</tr>
6+
<LeaderboardPage::EntriesTable::HeaderRow @language={{@language}} />
237
</thead>
248
<tbody>
259
{{#each this.sortedTopEntries as |entry index|}}

app/components/leaderboard-page/entries-table.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,6 @@ export default class LeaderboardPageEntriesTable extends Component<Signature> {
3232
}
3333
}
3434

35-
get explanationMarkdownForScore() {
36-
return `
37-
The highest possible score for this track is ${this.args.language.leaderboard!.highestPossibleScore}.
38-
39-
Harder stages have higher scores assigned to them.
40-
`.trim();
41-
}
42-
43-
get explanationMarkdownForStagesCompleted() {
44-
return `There are ${this.args.language.stagesCount} stages available in this track.`;
45-
}
46-
4735
get hasEntries() {
4836
return this.args.topEntries.length > 0;
4937
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<tr ...attributes>
2+
<LeaderboardPage::EntriesTable::HeaderRowCell @title="Rank" @alignment="left" />
3+
<LeaderboardPage::EntriesTable::HeaderRowCell @title="User" @alignment="left" />
4+
5+
<LeaderboardPage::EntriesTable::HeaderRowCell
6+
@title="Stages Completed"
7+
@alignment="right"
8+
class="hidden md:table-cell"
9+
@explanationMarkdown={{this.explanationMarkdownForStagesCompleted}}
10+
/>
11+
12+
<LeaderboardPage::EntriesTable::HeaderRowCell @title="Score" @alignment="right" @explanationMarkdown={{this.explanationMarkdownForScore}} />
13+
</tr>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Component from '@glimmer/component';
2+
import type LanguageModel from 'codecrafters-frontend/models/language';
3+
4+
interface Signature {
5+
Element: HTMLTableRowElement;
6+
7+
Args: {
8+
language: LanguageModel;
9+
};
10+
}
11+
12+
export default class LeaderboardPageEntriesTableHeaderRow extends Component<Signature> {
13+
get explanationMarkdownForScore() {
14+
return `
15+
The highest possible score for this track is ${this.args.language.leaderboard!.highestPossibleScore}.
16+
17+
Harder stages have higher scores assigned to them.
18+
`.trim();
19+
}
20+
21+
get explanationMarkdownForStagesCompleted() {
22+
return `There are ${this.args.language.liveOrBetaStagesCount} stages available in this track.`;
23+
}
24+
}
25+
26+
declare module '@glint/environment-ember-loose/registry' {
27+
export default interface Registry {
28+
'LeaderboardPage::EntriesTable::HeaderRow': typeof LeaderboardPageEntriesTableHeaderRow;
29+
}
30+
}

app/components/leaderboard-page/header.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default class LeaderboardPageHeader extends Component<Signature> {
2121
return this.store
2222
.peekAll('language')
2323
.sortBy('sortPositionForTrack')
24-
.filter((language) => language.stagesCount > 0);
24+
.filter((language) => language.liveOrBetaStagesCount > 0);
2525
}
2626

2727
@action

app/components/track-page/header/index.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
{{/if}}
2828
{{/if}}
2929

30-
<TrackPage::Header::Statistic @description="{{format-number @language.stagesCount}} exercises" @icon="terminal" class="shrink-0" />
30+
<TrackPage::Header::Statistic @description="{{format-number @language.liveOrBetaStagesCount}} exercises" @icon="terminal" class="shrink-0" />
3131
</div>
3232

3333
{{#if (has-block "cta")}}

app/components/tracks-page/track-card/index.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828
{{! Footer }}
2929
<div class="flex items-center justify-between">
3030
{{#if this.currentUserHasStartedTrack}}
31-
<TracksPage::TrackCard::ProgressBar @completedStagesCount={{this.completedStagesCount}} @stagesCount={{this.stagesCount}} />
31+
<TracksPage::TrackCard::ProgressBar @completedStagesCount={{this.completedStagesCount}} @stagesCount={{@language.liveOrBetaStagesCount}} />
3232
{{else}}
3333
<div class="flex items-center">
3434
{{svg-jar "academic-cap" class="w-4 mr-1 fill-current text-gray-400 dark:text-gray-600"}}
35-
<span class="text-xs text-gray-500">{{this.stagesCount}} stages</span>
35+
<span class="text-xs text-gray-500">{{@language.liveOrBetaStagesCount}} stages</span>
3636
</div>
3737
{{/if}}
3838

app/components/tracks-page/track-card/index.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,6 @@ export default class TrackCard extends Component<Signature> {
3939
}
4040
}
4141

42-
get stagesCount() {
43-
return this.store
44-
.peekAll('course')
45-
.rejectBy('releaseStatusIsAlpha')
46-
.rejectBy('releaseStatusIsDeprecated')
47-
.filter((course) => course.betaOrLiveLanguages.includes(this.args.language))
48-
.mapBy('stages.length')
49-
.reduce((a, b) => a + b, 0);
50-
}
51-
5242
@action
5343
async navigateToTrack() {
5444
await this.router.transitionTo('track', this.args.language.slug);

app/controllers/leaderboard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ export default class LeaderboardController extends Controller {
1313
return this.store
1414
.peekAll('language')
1515
.sortBy('sortPositionForTrack')
16-
.filter((language) => language.stagesCount > 0);
16+
.filter((language) => language.liveOrBetaStagesCount > 0);
1717
}
1818
}

app/models/language.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,15 @@ export default class LanguageModel extends Model {
152152
return this.slug === 'go';
153153
}
154154

155+
get liveOrBetaStagesCount() {
156+
return this.store
157+
.peekAll('course')
158+
.filter((course) => course.releaseStatusIsLive || course.releaseStatusIsBeta)
159+
.filter((course) => course.betaOrLiveLanguages.includes(this))
160+
.map((course) => course.stages.length)
161+
.reduce((a, b) => a + b, 0);
162+
}
163+
155164
get sortPositionForTrack() {
156165
return [
157166
// Popular tracks, sorted by usage
@@ -164,14 +173,6 @@ export default class LanguageModel extends Model {
164173
].join('');
165174
}
166175

167-
get stagesCount() {
168-
return this.store
169-
.peekAll('course')
170-
.filter((course) => course.betaOrLiveLanguages.includes(this))
171-
.map((course) => course.stages.length)
172-
.reduce((a, b) => a + b, 0);
173-
}
174-
175176
get tealLogoUrl() {
176177
return {
177178
c: tealLogoC,

0 commit comments

Comments
 (0)