Skip to content

Commit

Permalink
Merge pull request #181 from theImmortalCoders/issue-146
Browse files Browse the repository at this point in the history
Issue 146
  • Loading branch information
pablitoo1 authored Nov 28, 2024
2 parents 6c2975e + 374f664 commit 141c948
Show file tree
Hide file tree
Showing 6 changed files with 370 additions and 125 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-lines */
import { CommonModule } from '@angular/common';
import {
AfterViewChecked,
Expand All @@ -18,22 +19,85 @@ import { Subscription } from 'rxjs';
import * as feather from 'feather-icons';
import { NotificationService } from 'app/shared/services/notification.service';
import { RecordedGameTableComponent } from '../../shared/recorded-game-table.component';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';

@Component({
selector: 'app-recorded-games',
standalone: true,
imports: [CommonModule, RecordedGameTableComponent],
imports: [CommonModule, RecordedGameTableComponent, ReactiveFormsModule],
template: `
<h1
class="text-xl xs:text-2xl sm:text-4xl font-bold text-mainOrange text-center 2xs:text-start">
My recorded games
</h1>
<hr class="w-full border-[1px] sm:border-2 border-mainOrange mb-4" />
<app-recorded-game-table
[recordedGamesData]="recordedGamesData"
(downloadEmitter)="downloadGameRecord($event)"
(deleteEmitter)="deleteGameRecord($event)"
class="w-full overflow-auto max-h-96 border-mainOrange border-2" />
<form
[formGroup]="filterForm"
(ngSubmit)="applyFilters()"
class="w-full flex-col space-y-4 text-mainOrange pb-6 font-mono">
<div class="w-full flex flex-row gap-x-6 gap-y-2 flex-wrap justify-start">
<div class="flex flex-col space-y-1 w-full xs:w-fit">
<label for="gameId">Game:</label>
<select
id="gameId"
formControlName="gameId"
class="custom-input uppercase">
@for (game of avalaibleGamesList; track game.id) {
<option [value]="game.id" class="uppercase">
{{ game.name }}
</option>
}
</select>
</div>
<div class="flex flex-col space-y-1 w-full xs:w-fit">
<label for="endDateFrom">Game end date from:</label>
<input
id="endDateFrom"
type="datetime-local"
formControlName="endDateFrom"
class="custom-input"
placeholder="Type endDateFrom" />
</div>
<div class="flex flex-col space-y-1 w-full xs:w-fit">
<label for="endDateTo">Game end date to:</label>
<input
id="endDateTo"
type="datetime-local"
formControlName="endDateTo"
class="custom-input"
placeholder="Type endDateTo" />
</div>
<div class="flex flex-col space-y-1 w-full xs:w-fit">
<label for="isEmptyRecord">Only empty records:</label>
<span class="h-1">&nbsp;</span>
<input
id="isEmptyRecord"
type="checkbox"
formControlName="isEmptyRecord"
class="accent-mainOrange h-5 pt-6"
placeholder="Type isEmptyRecord" />
</div>
</div>
<div class="w-full flex flex-row gap-x-6 flex-wrap items-end">
<button
type="submit"
class="flex flex-row h-fit w-full xs:w-60 items-center justify-center gap-x-2 font-bold bg-darkGray hover:bg-mainCreme text-mainCreme hover:text-darkGray border-2 border-mainCreme rounded-md px-2 py-1 ease-in-out duration-150 transition-all">
<i data-feather="search" class="size-4"> </i>
<span>APPLY FILTERS</span>
</button>
</div>
</form>
@if (recordedGamesData && recordedGamesData.length > 0) {
<app-recorded-game-table
[recordedGamesData]="recordedGamesData"
(downloadEmitter)="downloadGameRecord($event)"
(deleteEmitter)="deleteGameRecord($event)"
(sortByEmitter)="sortBy = $event; applyFilters()"
(sortDirectionEmitter)="sortDirection = $event; applyFilters()"
class="w-full overflow-auto max-h-96 border-mainOrange border-2" />
} @else {
<span class="w-full text-mainOrange">No records found.</span>
}
@if (errorMessage !== null) {
<div class="text-red-500 mt-6">
<p>{{ errorMessage }}</p>
Expand All @@ -58,47 +122,63 @@ export class RecordedGamesComponent
public recordedGamesData: IRecordedGameResponse[] | null = null;
public errorMessage: string | null = null;

public filterForm!: FormGroup;

public sortBy: 'Ended' | 'SizeMb' = 'Ended';
public sortDirection: 'Asc' | 'Desc' = 'Asc';

public constructor(private _fb: FormBuilder) {
this.filterForm = this._fb.group({
gameId: [1],
isEmptyRecord: [''],
endDateFrom: [''],
endDateTo: [''],
});
}

public ngOnInit(): void {
this._getGamesSubscription = this._gameEndpointsService
.getGames()
.subscribe({
next: response => {
this.avalaibleGamesList = response;
this.errorMessage = null;
this.getRecordedGames();
},
error: (error: string) => {
this.errorMessage = error;
},
});
this.recordedGamesData = null;
}

public ngAfterViewChecked(): void {
feather.replace(); //dodane, żeby feather-icons na nowo dodało się do DOM w pętli
}

public ngOnChanges(): void {
this.getRecordedGames();
this.applyFilters();
}

public getRecordedGames(): void {
this.recordedGamesData = [];
for (const game of this.avalaibleGamesList) {
this._getRecordedGamesSubscription = this._gameRecordEndpointsService
.getAllRecordedGames(game.id, this.userId)
.subscribe({
next: response => {
if (this.recordedGamesData !== null) {
this.recordedGamesData.push(...response);
this.errorMessage = null;
}
},
error: (error: string) => {
this.errorMessage = error;
},
});
}
public applyFilters(): void {
const filters = this.filterForm.value;
this._getRecordedGamesSubscription = this._gameRecordEndpointsService
.getAllRecordedGames(
filters.gameId,
this.userId,
filters.isEmptyRecord,
filters.endDateFrom,
filters.endDateTo,
this.sortDirection,
this.sortBy
)
.subscribe({
next: response => {
this.recordedGamesData = response;
this.errorMessage = null;
},
error: (error: string) => {
this.errorMessage = error;
},
});
}

public downloadGameRecord(recordedGameId: number): void {
Expand Down Expand Up @@ -129,7 +209,7 @@ export class RecordedGamesComponent
);
this.errorMessage = null;
this.refreshDataEmitter.emit(true);
this.getRecordedGames();
this.applyFilters();
},
error: (error: string) => {
this.errorMessage = error;
Expand Down
145 changes: 97 additions & 48 deletions src/app/dashboard/components/shared/recorded-game-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,91 @@ import { LoadingSpinnerComponent } from '../../../shared/components/common/loadi
@if (isLoadingNeeded) {
<app-loading-spinner />
} @else {
<div
class="flex flex-col min-w-[44rem] w-full justify-around space-y-0 font-mono">
@if (recordedGamesData && recordedGamesData.length > 0) {
<div
class="flex flex-row space-x-4 justify-between bg-mainGray text-mainOrange text-sm xs:text-base font-bold px-4 py-2">
<span class="flex justify-center w-[5%]">No.</span>
<span class="flex justify-center w-2/12">Game name</span>
<span class="flex justify-center w-3/12">Game start date</span>
<span class="flex justify-center w-3/12">Game end date</span>
<span class="flex justify-center w-1/12">Size</span>
<span class="flex justify-center w-1/12">Download</span>
<span class="flex justify-center w-1/12">Delete</span>
</div>
@for (recordedGame of recordedGamesData; track recordedGame.id) {
class="flex flex-col min-w-[44rem] w-full justify-around space-y-0 font-mono">
<div
class="flex flex-row space-x-4 justify-between px-4 py-2 text-mainCreme text-sm xs:text-base opacity-80 hover:opacity-100 {{
$even ? 'bg-lightGray' : 'bg-darkGray'
}}">
<span class="flex justify-center w-[5%]">{{ $index + 1 }}.</span>
<span class="flex justify-center w-2/12 uppercase">{{
recordedGame.gameName
}}</span>
<span class="flex justify-center w-3/12">{{
recordedGame.started | date: 'dd/MM/yyyy, HH:mm:ss'
}}</span>
<span class="flex justify-center w-3/12">{{
recordedGame.ended | date: 'dd/MM/yyyy, HH:mm:ss'
}}</span>
<span class="flex justify-center w-1/12 text-nowrap">{{
recordedGame.isEmptyRecord
? '-'
: recordedGame.sizeMb.toPrecision(2) + ' MB'
}}</span>
@if (recordedGame.isEmptyRecord) {
<span class="flex group justify-center w-1/12"> </span>
} @else {
class="flex flex-row space-x-4 justify-between bg-mainGray text-mainOrange text-sm xs:text-base font-bold px-4 py-2">
<span class="flex justify-center w-[5%]">No.</span>
<span class="flex justify-center w-2/12">Game name</span>
<span class="flex justify-center w-3/12">Game start date</span>
<div
class="flex flex-row gap-x-1 items-center justify-center w-3/12">
<button (click)="setSortingBy('Ended')">Game end date</button>
@if (sortBy === 'Ended') {
<span
class="ease-in-out duration-150 transition-all {{
sortDirection === 'Desc' ? 'rotate-180' : ''
}}">
<i data-feather="chevron-down" class="size-4 "></i>
</span>
} @else {
<span>
<i data-feather="minus" class="size-4 "></i>
</span>
}
</div>
<button
class="flex flex-row gap-x-1 items-center justify-center w-1/12">
<button (click)="setSortingBy('SizeMb')">Size</button>
@if (sortBy === 'SizeMb') {
<span
class="ease-in-out duration-150 transition-all {{
sortDirection === 'Desc' ? 'rotate-180' : ''
}}">
<i data-feather="chevron-down" class="size-4 "></i>
</span>
} @else {
<span>
<i data-feather="minus" class="size-4 "></i>
</span>
}
</button>
<span class="flex justify-center w-1/12">Download</span>
<span class="flex justify-center w-1/12">Delete</span>
</div>
@for (recordedGame of recordedGamesData; track recordedGame.id) {
<div
class="flex flex-row space-x-4 justify-between px-4 py-2 text-mainCreme text-sm xs:text-base opacity-80 hover:opacity-100 {{
$even ? 'bg-lightGray' : 'bg-darkGray'
}}">
<span class="flex justify-center w-[5%]">{{ $index + 1 }}.</span>
<span class="flex justify-center w-2/12 uppercase">{{
recordedGame.gameName
}}</span>
<span class="flex justify-center w-3/12">{{
recordedGame.started | date: 'dd/MM/yyyy, HH:mm:ss'
}}</span>
<span class="flex justify-center w-3/12">{{
recordedGame.ended | date: 'dd/MM/yyyy, HH:mm:ss'
}}</span>
<span class="flex justify-center w-1/12 text-nowrap">{{
recordedGame.isEmptyRecord
? '-'
: recordedGame.sizeMb.toPrecision(2) + ' MB'
}}</span>
@if (recordedGame.isEmptyRecord) {
<span class="flex group justify-center w-1/12"> </span>
} @else {
<button
class="flex group justify-center w-1/12"
(click)="downloadEmitter.emit(recordedGame.id)">
<i
data-feather="download"
class="text-mainCreme group-hover:text-green-500 size-4 xs:size-5"></i>
</button>
}
<button
class="flex group justify-center w-1/12"
(click)="downloadEmitter.emit(recordedGame.id)">
(click)="deleteEmitter.emit(recordedGame.id)">
<i
data-feather="download"
class="text-mainCreme group-hover:text-green-500 size-4 xs:size-5"></i>
data-feather="x-square"
class="text-mainCreme group-hover:text-red-500 size-4 xs:size-5"></i>
</button>
}
<button
class="flex group justify-center w-1/12"
(click)="deleteEmitter.emit(recordedGame.id)">
<i
data-feather="x-square"
class="text-mainCreme group-hover:text-red-500 size-4 xs:size-5"></i>
</button>
</div>
}
</div>
</div>
}
</div>
}
}
`,
})
Expand All @@ -80,13 +112,30 @@ export class RecordedGameTableComponent implements OnChanges {
| null = null;
@Output() public downloadEmitter = new EventEmitter<number>();
@Output() public deleteEmitter = new EventEmitter<number>();
@Output() public sortByEmitter = new EventEmitter<'Ended' | 'SizeMb'>();
@Output() public sortDirectionEmitter = new EventEmitter<'Asc' | 'Desc'>();

public isLoadingNeeded = true;

public sortBy: 'Ended' | 'SizeMb' = 'Ended';
public sortDirection: 'Asc' | 'Desc' = 'Asc';

public setSortingBy(value: 'Ended' | 'SizeMb'): void {
if (this.sortBy === value && this.sortDirection === 'Asc') {
this.sortDirection = 'Desc';
} else {
this.sortDirection = 'Asc';
}
this.sortBy = value;
this.sortByEmitter.emit(this.sortBy);
this.sortDirectionEmitter.emit(this.sortDirection);
}

public ngOnChanges(): void {
if (this.recordedGamesData === null) {
this.isLoadingNeeded = true;
} else {
this.isLoadingNeeded = false;
}
this.isLoadingNeeded = false;
}
}
Loading

0 comments on commit 141c948

Please sign in to comment.