Skip to content

Commit

Permalink
Merge pull request #73 from turecross321/master
Browse files Browse the repository at this point in the history
Implement marking levels as re-uploads
  • Loading branch information
jvyden authored Apr 21, 2024
2 parents 2d3faf4 + 213f032 commit 5c8070c
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 233 deletions.
255 changes: 124 additions & 131 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/app/api/types/level-edit-request.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {GameVersion} from "./game-version";

export interface LevelEditRequest {
title: string | undefined;
description: string | undefined;
iconHash: string | undefined;
gameVersion: string | undefined;
originalPublisher: string | undefined;
isReUpload: boolean | undefined;
}
4 changes: 3 additions & 1 deletion src/app/api/types/level.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export interface Level {
hearts: number
totalPlays: number
uniquePlays: number
publisher: User
publisher: User | undefined
originalPublisher: string | undefined
isReUpload: boolean
teamPicked: boolean
gameVersion: number
score: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
<fa-icon [icon]="faCircleCheck" class="pr-1"></fa-icon>
</tooltip>
<level-statistics [level]="_level" class="text-sm"></level-statistics>
<p-gentle *ngIf="_level.publisher">by <user-link [user]="_level.publisher" class="pl-0.5"></user-link></p-gentle>
<p-gentle>by <user-link [user]="_level.publisher" class="pl-0.5" *ngIf="_level.publisher"
[ngClass]="_level.isReUpload ? 'line-through' : ''"></user-link>
<tooltip class="pl-0.5"
[text]="'This level is a re-upload, originally created by ' + _level.originalPublisher + '.'">
<span>{{ _level.originalPublisher }}</span>
</tooltip></p-gentle>
<p-gentle>Created in {{getGameVersion(_level.gameVersion)}} <date [date]="_level.publishDate"></date></p-gentle>
</div>
</div>
Expand Down
9 changes: 7 additions & 2 deletions src/app/pages/edit-level/edit-level.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

<div *ngIf="ownUser?.role == UserRoles.Admin">
<page-header class="text-2xl">Admin Settings</page-header>
<form-dropdown name="Game Version" [options]="gameVersions" [(value)]="gameVersion"></form-dropdown>
<div class="flex flex-col gap-y-2.5">
<form-dropdown name="Game Version" [options]="gameVersions" [(value)]="gameVersion"></form-dropdown>
<form-checkbox name="Mark as re-upload" [(value)]="isReUpload" [icon]="faClone"></form-checkbox>
<form-input name="Original Publisher" [(value)]="originalPublisher" [icon]="faUser"></form-input>
</div>
</div>
<divider></divider>

Expand All @@ -29,7 +33,8 @@
<div class="flex gap-3.5">
<div class="group flex h-auto w-44 max-md:w-24 justify-center items-center aspect-square my-2.5">
<input type="file" (change)="iconChanged($event).then()" class="hidden" id="pfpInput">
<label for="pfpInput" class="flex rounded-full bg-[#000000aa] h-auto w-44 max-md:w-24 justify-center items-center aspect-square z-10 opacity-0 group-hover:opacity-100 transition-opacity">
<label for="pfpInput"
class="flex rounded-full bg-[#000000aa] h-auto w-44 max-md:w-24 justify-center items-center aspect-square z-10 opacity-0 group-hover:opacity-100 transition-opacity">
<fa-icon [icon]="faPencil" class="text-4xl"></fa-icon>
</label>
<img [src]="GetAssetImageLink(iconHash)"
Expand Down
17 changes: 16 additions & 1 deletion src/app/pages/edit-level/edit-level.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import {catchError, of} from "rxjs";
import {HttpErrorResponse} from "@angular/common/http";
import {AuthService} from "../../api/auth.service";
import {ApiClient, GetAssetImageLink} from "../../api/api-client.service";
import {faCancel, faCertificate, faFloppyDisk, faPencil, faTrash} from "@fortawesome/free-solid-svg-icons";
import {
faCancel,
faCertificate, faClone,
faFloppyDisk,
faPencil,
faTrash,
faUser
} from "@fortawesome/free-solid-svg-icons";
import {LevelEditRequest} from "../../api/types/level-edit-request";
import {UserRoles} from "../../api/types/user-roles";
import {DropdownOption} from "../../components/form-dropdown/form-dropdown.component";
Expand All @@ -24,6 +31,8 @@ export class EditLevelComponent implements OnInit {
title: string = "";
description: string = "";
gameVersion: string = "0";
isReUpload: boolean = false;
originalPublisher: string | undefined = undefined;

gameVersions: DropdownOption[] = [
{
Expand Down Expand Up @@ -77,6 +86,8 @@ export class EditLevelComponent implements OnInit {
this.description = data.description;
this.gameVersion = data.gameVersion.toString();
this.iconHash = data.iconHash;
this.isReUpload = data.isReUpload;
this.originalPublisher = data.originalPublisher;
});
});

Expand All @@ -94,6 +105,8 @@ export class EditLevelComponent implements OnInit {
description: this.description,
iconHash: undefined,
gameVersion: this.gameVersion,
originalPublisher: this.originalPublisher,
isReUpload: this.isReUpload,
}

this.apiClient.EditLevel(payload, this.level.levelId, this.ownUser?.role == UserRoles.Admin);
Expand Down Expand Up @@ -130,4 +143,6 @@ export class EditLevelComponent implements OnInit {
protected readonly faCancel = faCancel;
protected readonly UserRoles = UserRoles;
protected readonly GetAssetImageLink = GetAssetImageLink;
protected readonly faUser = faUser;
protected readonly faClone = faClone;
}
202 changes: 107 additions & 95 deletions src/app/pages/level/level.component.html
Original file line number Diff line number Diff line change
@@ -1,122 +1,134 @@
<page-header-block *ngIf="level">
<div class="flex gap-3.5">
<level-avatar [level]="level" size="h-auto w-44 max-md:w-24"></level-avatar>
<div class="flex-grow">
<div class="font-bold text-3xl mb-1">
{{ level.title.length == 0 ? 'Unnamed Level' : level.title }}
<div class="flex gap-3.5">
<level-avatar [level]="level" size="h-auto w-44 max-md:w-24"></level-avatar>
<div class="flex-grow">
<div class="font-bold text-3xl mb-1">
{{ level.title.length == 0 ? 'Unnamed Level' : level.title }}

<tooltip text="This level has been team picked." *ngIf="level.teamPicked">
<fa-icon [icon]="faCircleCheck" class="text-xl pr-1"></fa-icon>
</tooltip>
<tooltip text="This level has been team picked." *ngIf="level.teamPicked">
<fa-icon [icon]="faCircleCheck" class="text-xl pr-1"></fa-icon>
</tooltip>

<div class="inline-block text-sm font-normal" *ngIf="level.publisher">
<span-gentle>by
<user-link [user]="level.publisher" class="pl-1"></user-link>
</span-gentle>
</div>
<div class="text-sm font-normal">
<span-gentle>Published for {{getGameVersion(level.gameVersion)}} </span-gentle>
<span-gentle>
<date [date]="level.publishDate"></date>
</span-gentle>
<span-gentle *ngIf="level.publishDate != level.updateDate">,
last updated <date [date]="level.updateDate"></date></span-gentle>
</div>
</div>
<div class="inline-block text-sm font-normal">
<span-gentle>by
<user-link [user]="level.publisher" class="pl-1" *ngIf="level.publisher"
[ngClass]="level.isReUpload ? 'line-through' : ''"></user-link>
<tooltip *ngIf="level.isReUpload" class="pl-1"
[text]="'This level is a re-upload, originally created by ' + level.originalPublisher + '.'">
<span>{{ level.originalPublisher }}</span>
</tooltip>
</span-gentle>
</div>
<div class="text-sm font-normal">
<span-gentle>Published for {{ getGameVersion(level.gameVersion) }}</span-gentle>
<span-gentle class="pl-1">
<date [date]="level.publishDate"></date>
</span-gentle>
<span-gentle *ngIf="level.publishDate != level.updateDate">,
last updated
<date [date]="level.updateDate"></date>
</span-gentle>
</div>
</div>

<level-statistics [level]="level" class="inline-block ml-1 mb-1"></level-statistics>
<level-statistics [level]="level" class="inline-block ml-1 mb-1"></level-statistics>

<div class="bg-backdrop rounded px-5 py-2.5 drop-shadow-lg whitespace-pre-wrap text-foreground">
<p>{{ level.description.length == 0 ? 'No description was provided for this level.' : level.description }}</p>
</div>
<div class="bg-backdrop rounded px-5 py-2.5 drop-shadow-lg whitespace-pre-wrap text-foreground">
<p>{{ level.description.length == 0 ? 'No description was provided for this level.' : level.description }}</p>
</div>
</div>
</div>
</div>
</page-header-block>
<page-header-block> <!-- controls row -->
<div class="flex gap-x-2.5 text-foreground">
<primary-button text="Play Now!" [icon]="faPlay" (click)="setAsOverride()" *ngIf="isOwnUserOnline"></primary-button>
<admin-link-button *ngIf="ownUser?.role == UserRoles.Admin" [routerLink]="'/admin/level/' + level?.levelId"></admin-link-button>
<secondary-button *ngIf="ownUser && (ownUser?.userId == level?.publisher?.userId || ownUser?.role == UserRoles.Admin)"
[routerLink]="'/level/' + level?.levelId + '/edit'"
class="w-36" text="Edit Level" [icon]="faPencil"></secondary-button>
</div>
<div class="flex gap-x-2.5 text-foreground">
<primary-button text="Play Now!" [icon]="faPlay" (click)="setAsOverride()"
*ngIf="isOwnUserOnline"></primary-button>
<admin-link-button *ngIf="ownUser?.role == UserRoles.Admin"
[routerLink]="'/admin/level/' + level?.levelId"></admin-link-button>
<secondary-button
*ngIf="ownUser && (ownUser?.userId == level?.publisher?.userId || ownUser?.role == UserRoles.Admin)"
[routerLink]="'/level/' + level?.levelId + '/edit'"
class="w-36" text="Edit Level" [icon]="faPencil"></secondary-button>
</div>
</page-header-block>

<page-header-block *ngIf="!level">
<div class="flex gap-3.5 animate-pulse">
<div class="inline h-44 w-44 bg-secondary rounded-full"></div>
<div>
<div class="inline-block h-8 w-80 bg-secondary rounded-full"></div>
<br>
<div class="inline-block h-4 w-48 bg-secondary rounded-full"></div>
<div class="flex gap-3.5 animate-pulse">
<div class="inline h-44 w-44 bg-secondary rounded-full"></div>
<div>
<div class="inline-block h-8 w-80 bg-secondary rounded-full"></div>
<br>
<div class="inline-block h-4 w-48 bg-secondary rounded-full"></div>

<div class="bg-backdrop rounded px-5 py-2.5 flex">
<div class="inline-block h-4 w-96 bg-secondary rounded-full m-1"></div>
<div class="inline-block h-4 w-48 bg-secondary rounded-full m-1"></div>
</div>
<div class="bg-backdrop rounded px-5 py-2.5 flex">
<div class="inline-block h-4 w-96 bg-secondary rounded-full m-1"></div>
<div class="inline-block h-4 w-48 bg-secondary rounded-full m-1"></div>
</div>
</div>
</div>
</div>
</page-header-block>

<div class="flex flex-row gap-2.5 max-md:flex-col pt-5">
<container class="w-full">
<div class="flex">
<h2 class="text-3xl font-bold flex-grow">Leaderboard</h2>
<form-dropdown *ngIf="level?.gameVersion !== 4" name="Score Type" [options]="scoreTypes" (change)="this.formChanged()" [(value)]="scoreType"></form-dropdown>
</div>
<divider></divider>
<div *ngIf="scores === undefined">
<p>Loading scores...</p>
</div>
<div *ngIf="scores !== undefined && scores!.length === 0" class="text-center">
<p class="font-bold text-2xl">No {{scoreType}}-player scores</p>
<p>
Nobody has beaten this level with {{scoreType}} player{{scoreType == '1' ? '' : 's'}} yet. Go for it!
</p>
</div>
<div *ngFor="let score of scores">
<div class="my-5 px-2.5">
<a [routerLink]="'/score/' + score.scoreId" class="flex items-center">
<div class="text-2xl">
<span *ngIf="score.rank == 1" class="text-rank-gold pr-2">#{{score.rank}}</span>
<span *ngIf="score.rank == 2" class="text-rank-silver pr-2">#{{score.rank}}</span>
<span *ngIf="score.rank == 3" class="text-rank-bronze pr-2">#{{score.rank}}</span>
<container class="w-full">
<div class="flex">
<h2 class="text-3xl font-bold flex-grow">Leaderboard</h2>
<form-dropdown *ngIf="level?.gameVersion !== 4" name="Score Type" [options]="scoreTypes"
(change)="this.formChanged()" [(value)]="scoreType"></form-dropdown>
</div>
<divider></divider>
<div *ngIf="scores === undefined">
<p>Loading scores...</p>
</div>
<div *ngIf="scores !== undefined && scores!.length === 0" class="text-center">
<p class="font-bold text-2xl">No {{ scoreType }}-player scores</p>
<p>
Nobody has beaten this level with {{ scoreType }} player{{ scoreType == '1' ? '' : 's' }} yet. Go for
it!
</p>
</div>
<div *ngFor="let score of scores">
<div class="my-5 px-2.5">
<a [routerLink]="'/score/' + score.scoreId" class="flex items-center">
<div class="text-2xl">
<span *ngIf="score.rank == 1" class="text-rank-gold pr-2">#{{ score.rank }}</span>
<span *ngIf="score.rank == 2" class="text-rank-silver pr-2">#{{ score.rank }}</span>
<span *ngIf="score.rank == 3" class="text-rank-bronze pr-2">#{{ score.rank }}</span>

<span *ngIf="score.rank !== undefined && score.rank > 3"
class="text-rank-other pr-2">#{{score.rank}}</span>
</div>
<span *ngIf="score.rank !== undefined && score.rank > 3"
class="text-rank-other pr-2">#{{ score.rank }}</span>
</div>

<div class="flex flex-col">
<span class="text-lg">{{score.score.toLocaleString(undefined)}} points</span>
<div class="flex flex-col">
<span class="text-lg">{{ score.score.toLocaleString(undefined) }} points</span>

<span class="text-sm">
<span class="text-sm">
Achieved by
<b><user-link [user]="score.players[0]"></user-link></b>
<date [date]="score.scoreSubmitted" class="ml-1"></date>
</span>
</div>
</a>
</div>
</div>
</div>
</a>
</div>
</div>

<div *ngIf="this.scores !== undefined && this.scores!.length % 10 == 0 && this.scores!.length !== 0">
<secondary-button text="Load more" (click)="loadMoreScores()"></secondary-button>
</div>
</container>
<container class="w-full">
<h2 class="text-3xl font-bold">Recent Activity</h2>
<divider></divider>
<div *ngIf="this.scores !== undefined && this.scores!.length % 10 == 0 && this.scores!.length !== 0">
<secondary-button text="Load more" (click)="loadMoreScores()"></secondary-button>
</div>
</container>
<container class="w-full">
<h2 class="text-3xl font-bold">Recent Activity</h2>
<divider></divider>

<div *ngIf="activity">
<div *ngFor="let event of activity.events">
<activity-event [event]="event" [page]="activity" [contextIsLevel]="true"></activity-event>
</div>
</div>
<div *ngIf="activity">
<div *ngFor="let event of activity.events">
<activity-event [event]="event" [page]="activity" [contextIsLevel]="true"></activity-event>
</div>
</div>

<div *ngIf="!activity">
<div *ngFor="let i of GenerateEmptyList(5)">
<activity-event></activity-event>
</div>
</div>
</container>
<div *ngIf="!activity">
<div *ngFor="let i of GenerateEmptyList(5)">
<activity-event></activity-event>
</div>
</div>
</container>
</div>

0 comments on commit 5c8070c

Please sign in to comment.