Skip to content

Commit

Permalink
Port over leaderboard stuff from old site
Browse files Browse the repository at this point in the history
  • Loading branch information
jvyden committed Sep 1, 2024
1 parent 19e451d commit 89f27bd
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/app/api/client.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {BehaviorSubject, Observable, tap} from "rxjs";
import {Params} from "@angular/router";
import {ApiImplementation} from "./api-implementation";
import {Contest} from "./types/contests/contest";
import {Score} from "./types/levels/score";

export const defaultPageSize: number = 40;

Expand Down Expand Up @@ -53,6 +54,10 @@ export class ClientService extends ApiImplementation {
return this.http.get<Level>(`/levels/id/${id}`);
}

getScoresForLevel(id: number, scoreType: number, skip: number, count: number = defaultPageSize, params: Params | null = null) {
return this.http.get<ListWithData<Score>>(`/scores/${id}/${scoreType}`, {params: this.setPageQuery(params, skip, count)});
}

private getUser(route: string, cacheLookup: (value: User, index: number, obj: User[]) => boolean): Observable<User> {
const existingUser: User | undefined = this.usersCache.find(cacheLookup);
if (existingUser) {
Expand Down
3 changes: 3 additions & 0 deletions src/app/api/types/levels/score.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ export interface Score {

game: GameVersion;
platform: Platform;

// This isn't part of the API spec. This is internal to refresh-web.
rank: number | undefined;
}
64 changes: 64 additions & 0 deletions src/app/components/items/level-leaderboard.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {Component, Input, OnInit} from '@angular/core';
import {Level} from "../../api/types/levels/level";
import {ContainerTitleComponent} from "../ui/text/container-title.component";
import {DividerComponent} from "../ui/divider.component";
import {Score} from "../../api/types/levels/score";
import {ClientService} from "../../api/client.service";
import {ScorePreviewComponent} from "./score-preview.component";

@Component({
selector: 'app-level-leaderboard',
standalone: true,
imports: [
ContainerTitleComponent,
DividerComponent,
ScorePreviewComponent
],
template: `
<app-container-title>Leaderboard</app-container-title>
<app-divider></app-divider>
@for(score of scores; track score.scoreId) {
<app-score-preview [score]="score"></app-score-preview>
}
`,
styles: ``
})
export class LevelLeaderboardComponent implements OnInit {
@Input({required: true}) public level: Level = null!;
scores: Score[] = [];

scoreType: string = "1";

constructor(private client: ClientService) {
}

ngOnInit(): void {
this.getScores();
}

getScores(clear: boolean = true, skip: number = 0) {
this.client.getScoresForLevel(this.level.levelId, Number(this.scoreType), skip)
.subscribe((data) => {
if (data === undefined) return;

if (clear || this.scores == undefined) {
this.scores = data.data;
} else {
this.scores = this.scores.concat(data.data);
}

let rank = 0;
let i = 0;
for (let score of this.scores) {
const lastScore: Score | undefined = this.scores[i - 1];
if (lastScore?.score == score.score) {
rank -= 1;
}

rank++;
i++;
score.rank = rank;
}
});
}
}
49 changes: 49 additions & 0 deletions src/app/components/items/score-preview.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {Component, Input} from '@angular/core';
import {RouterLink} from "@angular/router";
import { Score } from '../../api/types/levels/score';
import {UserLinkComponent} from "../ui/text/links/user-link.component";
import {DateComponent} from "../ui/info/date.component";

@Component({
selector: 'app-score-preview',
standalone: true,
imports: [
RouterLink,
UserLinkComponent,
DateComponent
],
template: `
<div class="my-5 px-2.5">
<a [routerLink]="'/score/' + score.scoreId" class="flex items-center">
<div class="text-2xl mr-2">
@switch (score.rank) {
@case(1) {
<span class="text-rank-gold">#{{ score.rank }}</span>
}
@case(2) {
<span class="text-rank-silver">#{{ score.rank }}</span>
}
@case(3) {
<span class="text-rank-bronze">#{{ score.rank }}</span>
}
@default() {
<span class="text-rank-other">#{{ score.rank }}</span>
}
}
</div>
<div class="flex flex-col">
<span class="text-lg">{{ score.score.toLocaleString(undefined) }} points</span>
<span class="text-sm">
Achieved by
<b><app-user-link [user]="score.players[0]"></app-user-link></b>
<app-date [date]="score.scoreSubmitted"></app-date>
</span>
</div>
</a>
</div>
`
})
export class ScorePreviewComponent {
@Input({required: true}) score: Score = null!;
}
2 changes: 1 addition & 1 deletion src/app/components/ui/container-header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Component } from '@angular/core';
standalone: true,
imports: [],
template: `
<div class="bg-header-background outline-header-background outline-[1.25rem] outline">
<div class="bg-header-background outline-header-background outline-[1.25rem] outline mb-10">
<ng-content></ng-content>
</div>
`,
Expand Down
16 changes: 16 additions & 0 deletions src/app/components/ui/layouts/two-pane-layout.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {Component, ContentChildren, ElementRef, QueryList, TemplateRef, ViewChildren} from '@angular/core';
import {NgTemplateOutlet} from "@angular/common";

@Component({
selector: 'app-two-pane-layout',
standalone: true,
imports: [
NgTemplateOutlet
],
template: `
<div class="grid grid-cols-2 sm:grid-cols-1 md:grid-cols-1 gap-2.5">
<ng-content></ng-content>
</div>
`
})
export class TwoPaneLayoutComponent {}
15 changes: 15 additions & 0 deletions src/app/pages/level/level.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,19 @@
</div>
<app-level-statistics [level]="level" class="mb-1.5 block" statistics></app-level-statistics>
</app-fancy-header>

<app-two-pane-layout>
<app-container class="w-full">
<app-level-leaderboard [level]="level"></app-level-leaderboard>
</app-container>
<app-container class="w-full">
<app-container-title>Test</app-container-title>
</app-container>
<app-container class="w-full">
<app-container-title>Test</app-container-title>
</app-container>
<app-container class="w-full">
<app-container-title>Test</app-container-title>
</app-container>
</app-two-pane-layout>
}
10 changes: 9 additions & 1 deletion src/app/pages/level/level.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import {FancyHeaderComponent} from "../../components/ui/layouts/fancy-header.com
import {GamePipe} from "../../pipes/game.pipe";
import {LayoutService} from "../../services/layout.service";
import {DateComponent} from "../../components/ui/info/date.component";
import {TwoPaneLayoutComponent} from "../../components/ui/layouts/two-pane-layout.component";
import {ContainerComponent} from "../../components/ui/container.component";
import {ContainerTitleComponent} from "../../components/ui/text/container-title.component";
import {LevelLeaderboardComponent} from "../../components/items/level-leaderboard.component";

@Component({
selector: 'app-level',
Expand All @@ -26,7 +30,11 @@ import {DateComponent} from "../../components/ui/info/date.component";
FancyHeaderComponent,
GamePipe,
AsyncPipe,
DateComponent
DateComponent,
TwoPaneLayoutComponent,
ContainerComponent,
ContainerTitleComponent,
LevelLeaderboardComponent
],
providers: [
SlugPipe
Expand Down

0 comments on commit 89f27bd

Please sign in to comment.