From 72189cd6eba7e8ef1e921d1df1a0ba3e60ec585d Mon Sep 17 00:00:00 2001 From: filvanh Date: Wed, 2 Oct 2024 14:34:13 +0200 Subject: [PATCH 01/10] Omstrukturer mapper, filer og navngiving --- src/app/app.component.ts | 2 +- src/app/game/game-draw/game-draw.component.ts | 2 +- .../game-drawing-feedback.component.ts | 2 +- .../correct-guess/correct-guess.component.ts | 2 +- .../game-example-drawings.component.ts | 2 +- .../wrong-guess/wrong-guess.component.ts | 2 +- .../game-multiplayer/lobby/lobby.component.ts | 2 +- .../game-pick-difficulty.component.ts | 2 +- .../game/game-result/game-result.component.ts | 2 +- .../game-welcome/game-welcome.component.html} | 0 .../game-welcome/game-welcome.component.scss} | 2 +- .../game-welcome/game-welcome.component.ts} | 28 +++++++++---------- .../game-word-to-draw.component.ts | 2 +- src/app/game/game.component.html | 2 +- src/app/game/game.component.ts | 4 +-- .../idle-timeout/idle-timeout.component.html | 0 .../idle-timeout/idle-timeout.component.scss | 2 +- .../idle-timeout/idle-timeout.component.ts | 2 +- .../speech-bubble.component.html | 0 .../speech-bubble.component.scss | 2 +- .../speech-bubble/speech-bubble.component.ts | 0 src/app/routes.ts | 4 +-- src/app/splash/splash.component.ts | 2 +- 23 files changed, 34 insertions(+), 34 deletions(-) rename src/app/{welcome/welcome.component.html => game/game-welcome/game-welcome.component.html} (100%) rename src/app/{welcome/welcome.component.scss => game/game-welcome/game-welcome.component.scss} (92%) rename src/app/{welcome/welcome.component.ts => game/game-welcome/game-welcome.component.ts} (84%) rename src/app/game/{ => shared-components}/idle-timeout/idle-timeout.component.html (100%) rename src/app/game/{ => shared-components}/idle-timeout/idle-timeout.component.scss (92%) rename src/app/game/{ => shared-components}/idle-timeout/idle-timeout.component.ts (93%) rename src/app/game/{ => shared-components}/speech-bubble/speech-bubble.component.html (100%) rename src/app/game/{ => shared-components}/speech-bubble/speech-bubble.component.scss (94%) rename src/app/game/{ => shared-components}/speech-bubble/speech-bubble.component.ts (100%) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 755fd735..53398f9b 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -3,7 +3,7 @@ import { Subject } from 'rxjs'; import { Router } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; import { RouterOutlet } from '@angular/router'; -import { IdleTimeoutComponent } from './game/idle-timeout/idle-timeout.component'; +import { IdleTimeoutComponent } from './game/shared-components/idle-timeout/idle-timeout.component'; import { routeTransitionAnimations } from './route-transition-animations'; import { environment } from '../environments/environment'; import { GameStateService } from './game/services/game-state-service'; diff --git a/src/app/game/game-draw/game-draw.component.ts b/src/app/game/game-draw/game-draw.component.ts index f9fadb96..582a74b1 100644 --- a/src/app/game/game-draw/game-draw.component.ts +++ b/src/app/game/game-draw/game-draw.component.ts @@ -22,7 +22,7 @@ import { TranslationService } from '@/app/core/translation.service'; import { TranslatePipe } from '@/app/core/translation.pipe'; import { GameStateService } from '../services/game-state-service'; import { CustomColorsIO } from '@/app/shared/customColors'; -import { SpeechBubbleComponent } from '../speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../shared-components/speech-bubble/speech-bubble.component'; import { OAvatarComponent } from '@/assets/avatars/o-avatar/o-avatar.component'; import { IAvatarComponent } from '@/assets/avatars/i-avatar/i-avatar.component'; import { ViewChild } from '@angular/core'; diff --git a/src/app/game/game-intermediate-result/game-drawing-feedback/game-drawing-feedback.component.ts b/src/app/game/game-intermediate-result/game-drawing-feedback/game-drawing-feedback.component.ts index 94f5d311..3d8eca6f 100644 --- a/src/app/game/game-intermediate-result/game-drawing-feedback/game-drawing-feedback.component.ts +++ b/src/app/game/game-intermediate-result/game-drawing-feedback/game-drawing-feedback.component.ts @@ -1,5 +1,5 @@ import { TranslatePipe } from '@/app/core/translation.pipe'; -import { SpeechBubbleComponent } from '../../speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../../shared-components/speech-bubble/speech-bubble.component'; import { Component, OnInit } from '@angular/core'; import { ArrowAlignment, PointerSide } from '@/app/shared/models/interfaces'; import { CustomColorsIO } from '../../../shared/customColors'; diff --git a/src/app/game/game-intermediate-result/game-example-drawings/correct-guess/correct-guess.component.ts b/src/app/game/game-intermediate-result/game-example-drawings/correct-guess/correct-guess.component.ts index 2ef3a556..b9edf267 100644 --- a/src/app/game/game-intermediate-result/game-example-drawings/correct-guess/correct-guess.component.ts +++ b/src/app/game/game-intermediate-result/game-example-drawings/correct-guess/correct-guess.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { SpeechBubbleComponent } from '@/app/game/speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '@/app/game/shared-components/speech-bubble/speech-bubble.component'; import { OAvatarComponent } from '@/assets/avatars/o-avatar/o-avatar.component'; import { ArrowAlignment, PointerSide } from '@/app/shared/models/interfaces'; import { CustomColorsIO } from '@/app/shared/customColors'; diff --git a/src/app/game/game-intermediate-result/game-example-drawings/game-example-drawings.component.ts b/src/app/game/game-intermediate-result/game-example-drawings/game-example-drawings.component.ts index 15622316..c208f519 100644 --- a/src/app/game/game-intermediate-result/game-example-drawings/game-example-drawings.component.ts +++ b/src/app/game/game-intermediate-result/game-example-drawings/game-example-drawings.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { SpeechBubbleComponent } from '../../speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../../shared-components/speech-bubble/speech-bubble.component'; import { TranslatePipe } from '@/app/core/translation.pipe'; import { DrawingService } from '../../services/drawing.service'; import { OAvatarComponent } from '@/assets/avatars/o-avatar/o-avatar.component'; diff --git a/src/app/game/game-intermediate-result/game-example-drawings/wrong-guess/wrong-guess.component.ts b/src/app/game/game-intermediate-result/game-example-drawings/wrong-guess/wrong-guess.component.ts index 86e4c516..ec88a8e2 100644 --- a/src/app/game/game-intermediate-result/game-example-drawings/wrong-guess/wrong-guess.component.ts +++ b/src/app/game/game-intermediate-result/game-example-drawings/wrong-guess/wrong-guess.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { SpeechBubbleComponent } from '@/app/game/speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '@/app/game/shared-components/speech-bubble/speech-bubble.component'; import { OAvatarComponent } from '@/assets/avatars/o-avatar/o-avatar.component'; import { ArrowAlignment, Certainty, PointerSide } from '@/app/shared/models/interfaces'; import { CustomColorsIO } from '@/app/shared/customColors'; diff --git a/src/app/game/game-multiplayer/lobby/lobby.component.ts b/src/app/game/game-multiplayer/lobby/lobby.component.ts index d717167d..53cb173e 100644 --- a/src/app/game/game-multiplayer/lobby/lobby.component.ts +++ b/src/app/game/game-multiplayer/lobby/lobby.component.ts @@ -8,7 +8,7 @@ import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { TranslationService } from '@/app/core/translation.service'; import { TranslatePipe } from '@/app/core/translation.pipe'; import { GameStateService } from '../../services/game-state-service'; -import { SpeechBubbleComponent } from '../../speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../../shared-components/speech-bubble/speech-bubble.component'; import { CustomColorsIO } from '@/app/shared/customColors'; import { PointerSide, ArrowAlignment } from '@/app/shared/models/interfaces'; import { IAvatarComponent } from '@/assets/avatars/i-avatar/i-avatar.component'; diff --git a/src/app/game/game-pick-difficulty/game-pick-difficulty.component.ts b/src/app/game/game-pick-difficulty/game-pick-difficulty.component.ts index 657f0979..c53b8547 100644 --- a/src/app/game/game-pick-difficulty/game-pick-difficulty.component.ts +++ b/src/app/game/game-pick-difficulty/game-pick-difficulty.component.ts @@ -8,7 +8,7 @@ import { TranslationService } from '@/app/core/translation.service'; import { TranslatePipe } from '@/app/core/translation.pipe'; import { GameLevelConfig, GAMESTATE } from '@/app/shared/models/interfaces'; import { GameStateService } from '../services/game-state-service'; -import { SpeechBubbleComponent } from '../../game/speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../shared-components/speech-bubble/speech-bubble.component'; import { CustomColorsIO } from '../../shared/customColors'; import { ArrowAlignment, PointerSide } from '@/app/shared/models/interfaces'; import { trigger, state, style, animate, transition } from '@angular/animations'; diff --git a/src/app/game/game-result/game-result.component.ts b/src/app/game/game-result/game-result.component.ts index 407be41b..c82f22c0 100644 --- a/src/app/game/game-result/game-result.component.ts +++ b/src/app/game/game-result/game-result.component.ts @@ -18,7 +18,7 @@ import { // ... } from '@angular/animations'; import { HighscoreData } from '@/app/shared/models/backend-interfaces'; -import { SpeechBubbleComponent } from '../speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../shared-components/speech-bubble/speech-bubble.component'; import { CustomColorsIO } from '@/app/shared/customColors'; import { MatIcon } from '@angular/material/icon'; import { GameStateService } from '../services/game-state-service'; diff --git a/src/app/welcome/welcome.component.html b/src/app/game/game-welcome/game-welcome.component.html similarity index 100% rename from src/app/welcome/welcome.component.html rename to src/app/game/game-welcome/game-welcome.component.html diff --git a/src/app/welcome/welcome.component.scss b/src/app/game/game-welcome/game-welcome.component.scss similarity index 92% rename from src/app/welcome/welcome.component.scss rename to src/app/game/game-welcome/game-welcome.component.scss index 94952e14..93b24308 100644 --- a/src/app/welcome/welcome.component.scss +++ b/src/app/game/game-welcome/game-welcome.component.scss @@ -1,4 +1,4 @@ -@import '../../variables.scss'; +@import '../../../variables.scss'; .container { position: relative; diff --git a/src/app/welcome/welcome.component.ts b/src/app/game/game-welcome/game-welcome.component.ts similarity index 84% rename from src/app/welcome/welcome.component.ts rename to src/app/game/game-welcome/game-welcome.component.ts index 8f09e075..63536617 100644 --- a/src/app/welcome/welcome.component.ts +++ b/src/app/game/game-welcome/game-welcome.component.ts @@ -1,27 +1,27 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; -import { MultiplayerService } from '../game/services/multiplayer.service'; -import { DrawingService } from '../game/services/drawing.service'; +import { MultiplayerService } from '../services/multiplayer.service'; +import { DrawingService } from '../services/drawing.service'; import { Router, RouterLink, RouterLinkActive } from '@angular/router'; import { MatIcon } from '@angular/material/icon'; import { MatButton } from '@angular/material/button'; -import { TranslationService } from '../core/translation.service'; -import { TranslatePipe } from '../core/translation.pipe'; +import { TranslationService } from '../../core/translation.service'; +import { TranslatePipe } from '../../core/translation.pipe'; import { Observable, Subject, takeUntil } from 'rxjs'; import { CommonModule } from '@angular/common'; -import { GAMESTATE } from '../shared/models/interfaces'; -import { GameStateService } from '../game/services/game-state-service'; -import { SupportedLanguages } from '../shared/models/interfaces'; +import { GAMESTATE } from '../../shared/models/interfaces'; +import { GameStateService } from '../services/game-state-service'; +import { SupportedLanguages } from '../../shared/models/interfaces'; import { ArrowAlignment, PointerSide } from '@/app/shared/models/interfaces'; import { trigger, state, style, animate, transition } from '@angular/animations'; -import { SpeechBubbleComponent } from '../game/speech-bubble/speech-bubble.component'; -import { CustomColorsIO } from '../shared/customColors'; -import { CustomButtonComponent } from '../game/shared-components/custom-button/custom-button.component'; +import { SpeechBubbleComponent } from '../shared-components/speech-bubble/speech-bubble.component'; +import { CustomColorsIO } from '../../shared/customColors'; +import { CustomButtonComponent } from '../shared-components/custom-button/custom-button.component'; import { ButtonStyleClass } from '@/app/shared/buttonStyles'; @Component({ - selector: 'app-welcome', - templateUrl: './welcome.component.html', - styleUrls: ['./welcome.component.scss'], + selector: 'app-game-welcome', + templateUrl: './game-welcome.component.html', + styleUrls: ['./game-welcome.component.scss'], standalone: true, imports: [ RouterLink, @@ -53,7 +53,7 @@ import { ButtonStyleClass } from '@/app/shared/buttonStyles'; ]), ], }) -export class WelcomeComponent implements OnInit, OnDestroy { +export class GameWelcomeComponent implements OnInit, OnDestroy { currentLang$: Observable; private destroy$ = new Subject(); private animationTimeouts: NodeJS.Timeout[] = []; diff --git a/src/app/game/game-word-to-draw/game-word-to-draw.component.ts b/src/app/game/game-word-to-draw/game-word-to-draw.component.ts index 1332bd51..44cfb7d4 100644 --- a/src/app/game/game-word-to-draw/game-word-to-draw.component.ts +++ b/src/app/game/game-word-to-draw/game-word-to-draw.component.ts @@ -17,7 +17,7 @@ import { GameStateService } from '../services/game-state-service'; import { ExampleDrawingService } from '../services/example-drawing.service'; import { Router } from '@angular/router'; import { IAvatarComponent } from '@/assets/avatars/i-avatar/i-avatar.component'; -import { SpeechBubbleComponent } from '../speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../shared-components/speech-bubble/speech-bubble.component'; import { CustomColorsIO } from '@/app/shared/customColors'; import { PointerSide, ArrowAlignment } from '@/app/shared/models/interfaces'; import { CustomButtonComponent } from '../shared-components/custom-button/custom-button.component'; diff --git a/src/app/game/game.component.html b/src/app/game/game.component.html index 5c37b838..78abe02b 100644 --- a/src/app/game/game.component.html +++ b/src/app/game/game.component.html @@ -16,6 +16,6 @@ } @case (GAMESTATE.lobby) {
- +
} } diff --git a/src/app/game/game.component.ts b/src/app/game/game.component.ts index 40f1e20b..46297cc8 100644 --- a/src/app/game/game.component.ts +++ b/src/app/game/game.component.ts @@ -9,7 +9,7 @@ import { GameInfoComponent } from './game-info/game-info.component'; import { GamePickDifficultyComponent } from './game-pick-difficulty/game-pick-difficulty.component'; import { GameStateService } from './services/game-state-service'; import { LobbyComponent } from './game-multiplayer/lobby/lobby.component'; -import { WelcomeComponent } from '../welcome/welcome.component'; +import { GameWelcomeComponent } from '../game/game-welcome/game-welcome.component'; @Component({ selector: 'app-game', @@ -49,7 +49,7 @@ import { WelcomeComponent } from '../welcome/welcome.component'; GameResultComponent, GameWordToDrawComponent, LobbyComponent, - WelcomeComponent, + GameWelcomeComponent, ], }) export class GameComponent implements OnInit { diff --git a/src/app/game/idle-timeout/idle-timeout.component.html b/src/app/game/shared-components/idle-timeout/idle-timeout.component.html similarity index 100% rename from src/app/game/idle-timeout/idle-timeout.component.html rename to src/app/game/shared-components/idle-timeout/idle-timeout.component.html diff --git a/src/app/game/idle-timeout/idle-timeout.component.scss b/src/app/game/shared-components/idle-timeout/idle-timeout.component.scss similarity index 92% rename from src/app/game/idle-timeout/idle-timeout.component.scss rename to src/app/game/shared-components/idle-timeout/idle-timeout.component.scss index ab1ff365..33d41131 100644 --- a/src/app/game/idle-timeout/idle-timeout.component.scss +++ b/src/app/game/shared-components/idle-timeout/idle-timeout.component.scss @@ -1,4 +1,4 @@ -@import '../../../variables.scss'; +@import '../../../../variables.scss'; .cdk-overlay-backdrop.cdk-overlay-dark-backdrop.cdk-overlay-backdrop-showing { background: rgba(20, 33, 61, 0.8); diff --git a/src/app/game/idle-timeout/idle-timeout.component.ts b/src/app/game/shared-components/idle-timeout/idle-timeout.component.ts similarity index 93% rename from src/app/game/idle-timeout/idle-timeout.component.ts rename to src/app/game/shared-components/idle-timeout/idle-timeout.component.ts index 38c8cd60..20e0b3da 100644 --- a/src/app/game/idle-timeout/idle-timeout.component.ts +++ b/src/app/game/shared-components/idle-timeout/idle-timeout.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { MatDialogRef, MatDialogContent, MatDialogActions } from '@angular/material/dialog'; import { ViewEncapsulation } from '@angular/core'; -import { routes } from '../../shared/models/routes'; +import { routes } from '../../../shared/models/routes'; import { MatIcon } from '@angular/material/icon'; import { MatButton } from '@angular/material/button'; import { CdkScrollable } from '@angular/cdk/scrolling'; diff --git a/src/app/game/speech-bubble/speech-bubble.component.html b/src/app/game/shared-components/speech-bubble/speech-bubble.component.html similarity index 100% rename from src/app/game/speech-bubble/speech-bubble.component.html rename to src/app/game/shared-components/speech-bubble/speech-bubble.component.html diff --git a/src/app/game/speech-bubble/speech-bubble.component.scss b/src/app/game/shared-components/speech-bubble/speech-bubble.component.scss similarity index 94% rename from src/app/game/speech-bubble/speech-bubble.component.scss rename to src/app/game/shared-components/speech-bubble/speech-bubble.component.scss index 1ae092bb..c7a5aa27 100644 --- a/src/app/game/speech-bubble/speech-bubble.component.scss +++ b/src/app/game/shared-components/speech-bubble/speech-bubble.component.scss @@ -1,4 +1,4 @@ -@import '../../../variables.scss'; +@import '../../../../variables.scss'; * { text-align: center; diff --git a/src/app/game/speech-bubble/speech-bubble.component.ts b/src/app/game/shared-components/speech-bubble/speech-bubble.component.ts similarity index 100% rename from src/app/game/speech-bubble/speech-bubble.component.ts rename to src/app/game/shared-components/speech-bubble/speech-bubble.component.ts diff --git a/src/app/routes.ts b/src/app/routes.ts index eb8285d2..3f630b50 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -1,6 +1,6 @@ import { Routes } from '@angular/router'; import { SplashComponent } from './splash/splash.component'; -import { WelcomeComponent } from './welcome/welcome.component'; +import { GameWelcomeComponent } from './game/game-welcome/game-welcome.component'; import { GameComponent } from './game/game.component'; import { routes as r } from './shared/models/routes'; import { GameResultComponent } from './game/game-result/game-result.component'; @@ -18,7 +18,7 @@ export const routes: Routes = [ }, { path: r.WELCOME, - component: WelcomeComponent, + component: GameWelcomeComponent, data: { animationState: 'welcome' }, }, { diff --git a/src/app/splash/splash.component.ts b/src/app/splash/splash.component.ts index d54cdd2d..134b9427 100644 --- a/src/app/splash/splash.component.ts +++ b/src/app/splash/splash.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { CommonModule } from '@angular/common'; import { HttpClient } from '@angular/common/http'; -import { SpeechBubbleComponent } from '../game/speech-bubble/speech-bubble.component'; +import { SpeechBubbleComponent } from '../game/shared-components/speech-bubble/speech-bubble.component'; import { CustomColorsIO } from '../shared/customColors'; import { ArrowAlignment, PointerSide } from '../shared/models/interfaces'; import { trigger, state, style, animate, transition } from '@angular/animations'; From e49622f1d4956906c453c8ed3b2e60f26c188738 Mon Sep 17 00:00:00 2001 From: ellenyuX Date: Fri, 4 Oct 2024 09:46:28 +0200 Subject: [PATCH 02/10] added components for showing statistics --- .../info-dialog/info-dialog.component.ts | 8 +- src/app/admin/info/info.component.html | 2 + src/app/admin/info/info.component.ts | 6 +- src/app/admin/login.service.ts | 18 +++ src/app/admin/score/score.component.html | 46 +++++++ src/app/admin/score/score.component.scss | 114 +++++++++++++++++ src/app/admin/score/score.component.ts | 121 ++++++++++++++++++ src/app/admin/select/select.component.html | 11 ++ src/app/admin/select/select.component.scss | 43 +++++++ src/app/admin/select/select.component.ts | 57 +++++++++ src/app/admin/toggle/toggle.component.html | 10 ++ src/app/admin/toggle/toggle.component.scss | 35 +++++ src/app/admin/toggle/toggle.component.ts | 30 +++++ src/app/shared/models/endpoints.ts | 5 +- 14 files changed, 503 insertions(+), 3 deletions(-) create mode 100644 src/app/admin/score/score.component.html create mode 100644 src/app/admin/score/score.component.scss create mode 100644 src/app/admin/score/score.component.ts create mode 100644 src/app/admin/select/select.component.html create mode 100644 src/app/admin/select/select.component.scss create mode 100644 src/app/admin/select/select.component.ts create mode 100644 src/app/admin/toggle/toggle.component.html create mode 100644 src/app/admin/toggle/toggle.component.scss create mode 100644 src/app/admin/toggle/toggle.component.ts diff --git a/src/app/admin/info-dialog/info-dialog.component.ts b/src/app/admin/info-dialog/info-dialog.component.ts index fd320b67..8042bcb8 100644 --- a/src/app/admin/info-dialog/info-dialog.component.ts +++ b/src/app/admin/info-dialog/info-dialog.component.ts @@ -3,6 +3,7 @@ import { MatDialog } from '@angular/material/dialog'; import { DialogTemplateComponent } from './../dialog-template/dialog-template.component'; import { ErrorLogDialogComponent } from '../error-dialog/error-dialog.component'; import { LogData } from '@/app/shared/models/backend-interfaces'; +import { ScoreComponent } from '../score/score.component'; @Component({ selector: 'app-info-dialog', @@ -24,9 +25,14 @@ export class InfoDialogComponent { } openErrorLog(logDataArray: LogData[]) { - this.dialog.open(ErrorLogDialogComponent, { data: logDataArray, }); } + + openStatistics() { + this.dialog.open(ScoreComponent, { + data: String, + }); + } } diff --git a/src/app/admin/info/info.component.html b/src/app/admin/info/info.component.html index 9efd216f..e46d1e75 100644 --- a/src/app/admin/info/info.component.html +++ b/src/app/admin/info/info.component.html @@ -5,6 +5,8 @@

Advarsel!

+ +

diff --git a/src/app/admin/info/info.component.ts b/src/app/admin/info/info.component.ts index 6fcb496c..10d2e7ed 100644 --- a/src/app/admin/info/info.component.ts +++ b/src/app/admin/info/info.component.ts @@ -32,7 +32,7 @@ export class InfoComponent { private _snackBar: MatSnackBar, private _dialog: InfoDialogComponent, private pairing: PairingService, - private loggingService: LoggingService + private loggingService: LoggingService, ) {} revertDataset() { @@ -162,6 +162,10 @@ export class InfoComponent { ); } + getStatistics() { + this._dialog.openStatistics(); + } + getLogger() { this.loginService.getLogger().subscribe( (res: LogData[]) => { diff --git a/src/app/admin/login.service.ts b/src/app/admin/login.service.ts index 005450f2..740d21eb 100644 --- a/src/app/admin/login.service.ts +++ b/src/app/admin/login.service.ts @@ -102,4 +102,22 @@ export class LoginService { } ); } + + getStatisticsPerMonth(month: string, year: string): Observable { + return this.http.get( + `${endpoints.TEKNISKBACKEND}/${endpoints.ADMIN}/${endpoints.GETSTATISTICSMONTH}?month=${month}&year=${year}`, + { + withCredentials: true, + } + ); + } + + getStatisticsPerYear(year: string): Observable { + return this.http.get( + `${endpoints.TEKNISKBACKEND}/${endpoints.ADMIN}/${endpoints.GETSTATISTICSYEAR}?year=${year}`, + { + withCredentials: true, + } + ); + } } \ No newline at end of file diff --git a/src/app/admin/score/score.component.html b/src/app/admin/score/score.component.html new file mode 100644 index 00000000..e4c86eca --- /dev/null +++ b/src/app/admin/score/score.component.html @@ -0,0 +1,46 @@ +
+
+ + + +
+ + @if(selected === "month") { +

Velg måned og år

+ + Måned og år + + MM/YYYY + + + + + } + + @else { + + } +
+ + + + + + @if (dataFetched()) { +
+
+ @if (selected == "month") { +

Statistikk for {{ display_month }} {{ year }}

+ } + @else { +

Statistikk for {{ selectedYear }}

+ } +

Totalt antall spill: {{ scoreCount }}

+
+ } + + + +
+
diff --git a/src/app/admin/score/score.component.scss b/src/app/admin/score/score.component.scss new file mode 100644 index 00000000..bf6443bb --- /dev/null +++ b/src/app/admin/score/score.component.scss @@ -0,0 +1,114 @@ +.statistics { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + } + + .statistics-content { + background: #fff; + padding: 2rem; + border-radius: 10px; + width: 400px; + text-align: center; + } + + button { + margin-top: 1rem; + padding: 0.5rem 1rem; + font-size: 1rem; + } + + .confirm { + background-color: #e74c3c; + color: white; + } + + + .close-btn { + background-color: #e74c3c; + color: white; + } + + + .example-picker .mat-calendar-period-button { + pointer-events: none; + } + + .example-picker .mat-calendar-arrow { + display: none; + } + + .statistics-content { + padding: 20px; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + } + + h2 { + font-size: 1.5rem; + margin-bottom: 20px; + color: #333; + } + + .form-section { + width: 100%; + margin-bottom: 20px; + display: flex; + flex-direction: column; + align-items: center; + } + + mat-form-field { + width: 100%; + max-width: 300px; + margin: 0 auto; + } + + .confirm-btn { + background-color: #3f51b5; + color: white; + margin-top: 15px; + padding: 10px 20px; + border-radius: 5px; + font-size: 1rem; + } + + .confirm-btn:hover { + background-color: #2c387e; + } + + .statistics-result { + margin-top: 20px; + padding: 15px; + background-color: #f5f5f5; + border-radius: 10px; + width: 100%; + max-width: 350px; + text-align: center; + } + + p { + font-size: 1.2rem; + color: #555; + } + + .close-btn { + background-color: #f44336; + color: white; + margin-top: 20px; + padding: 10px 20px; + border-radius: 5px; + } + + .close-btn:hover { + background-color: #d32f2f; + } + \ No newline at end of file diff --git a/src/app/admin/score/score.component.ts b/src/app/admin/score/score.component.ts new file mode 100644 index 00000000..d963fb26 --- /dev/null +++ b/src/app/admin/score/score.component.ts @@ -0,0 +1,121 @@ +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Component, Inject, signal, ViewEncapsulation } from '@angular/core'; +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { provideMomentDateAdapter } from '@angular/material-moment-adapter'; +import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { ToggleComponent } from '../toggle/toggle.component'; +import * as _moment from 'moment'; +// tslint:disable-next-line:no-duplicate-imports +import { default as _rollupMoment, Moment } from 'moment'; +import { MatInputModule } from '@angular/material/input'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { LoginService } from '../login.service'; +import { SelectComponent } from '../select/select.component'; + +const moment = _rollupMoment || _moment; +export const MY_FORMATS = { + parse: { + dateInput: 'MM/YYYY', + }, + display: { + dateInput: 'MM/YYYY', + monthYearLabel: 'MMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY', + }, +}; + +@Component({ + selector: 'app-score', + templateUrl: './score.component.html', + styleUrls: ['./score.component.scss'], + providers: [ + provideMomentDateAdapter(MY_FORMATS), + ], + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + FormsModule, + ReactiveFormsModule, + MatButtonToggleModule, + ToggleComponent, + SelectComponent + ], +}) + +export class ScoreComponent { + scoreCount: number | null = null; + date = new FormControl(); + dataFetched = signal(false); + display_month: string = ""; + month: string = ""; + year: string = ""; + selected: string = "month"; + selectedYear: string = ""; + + constructor( + public dialogRef: MatDialogRef, + private loginService: LoginService, + @Inject(MAT_DIALOG_DATA) public data: string) { } + + + setMonthAndYear2(normalizedMonthAndYear: Moment, datepicker: MatDatepicker) { + const ctrlValue = this.date.value ?? moment(); + ctrlValue.month(normalizedMonthAndYear.month()); + ctrlValue.year(normalizedMonthAndYear.year()); + this.date.setValue(ctrlValue); + + datepicker.close(); + } + + confirmSelection() { + if (this.selected === "month") { + const ctrlValue = this.date.value; + this.month = ctrlValue.format("MM"); + this.display_month = ctrlValue.format("MMMM"); + this.year = ctrlValue.format('YYYY'); + + this.loginService.getStatisticsPerMonth(this.month, this.year).subscribe({ + next: (res) => { + this.dataFetched.set(true); + this.scoreCount = res; + + }, + error: (err) => { + console.error('Failed to fetch statistics', err); + } + }); + } else { + this.loginService.getStatisticsPerYear(this.selectedYear).subscribe({ + next: (res) => { + this.dataFetched.set(true); + this.scoreCount = res; + + }, + error: (err) => { + console.error('Failed to fetch statistics', err); + } + }); + } + } + + closeStatistics(): void { + this.dialogRef.close(); + } + + onToggleChanged(value: string) { + this.selected = value; + this.dataFetched.set(false); + + } + + onYearSelected(year: string) { + this.selectedYear = year; + } + + +} diff --git a/src/app/admin/select/select.component.html b/src/app/admin/select/select.component.html new file mode 100644 index 00000000..2c7e004c --- /dev/null +++ b/src/app/admin/select/select.component.html @@ -0,0 +1,11 @@ +
+

Velg år

+ + År + + @for (year of years; track year) { + {{year.value}} + } + + +
diff --git a/src/app/admin/select/select.component.scss b/src/app/admin/select/select.component.scss new file mode 100644 index 00000000..e9fefac9 --- /dev/null +++ b/src/app/admin/select/select.component.scss @@ -0,0 +1,43 @@ +.year-selection-container { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 20px; + } + + h4 { + font-size: 1.4rem; + margin-bottom: 15px; + color: #333; + } + + .year-selection-field { + width: 100%; + max-width: 300px; + } + + mat-form-field { + width: 100%; + margin: 0 auto; + } + + mat-select { + width: 100%; + background-color: #fff; + } + + mat-option { + font-size: 1rem; + } + + .mat-select-panel { + max-height: 200px; /* Set a limit for dropdown height */ + } + + h2 { + font-size: 1.5rem; + margin-bottom: 20px; + color: #333; + } + \ No newline at end of file diff --git a/src/app/admin/select/select.component.ts b/src/app/admin/select/select.component.ts new file mode 100644 index 00000000..4ca345bd --- /dev/null +++ b/src/app/admin/select/select.component.ts @@ -0,0 +1,57 @@ +import {Component, EventEmitter, OnInit, Output} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {MatInputModule} from '@angular/material/input'; +import {MatSelectModule} from '@angular/material/select'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import { HttpClient } from '@angular/common/http'; +import { endpoints } from '../../shared/models/endpoints'; +import { Observable } from 'rxjs'; + +interface Year { + value: string; +} + +/** + * @title Basic select + */ +@Component({ + selector: 'select-component', + templateUrl: 'select.component.html', + standalone: true, + imports: [MatFormFieldModule, MatSelectModule, MatInputModule, FormsModule], +}) +export class SelectComponent implements OnInit { + constructor(private http: HttpClient) {} + years: Year[] = []; + selectedValue: string = ""; + + @Output() valueSelected: EventEmitter = new EventEmitter(); + + ngOnInit(): void { + this.getAvailableYears().subscribe({ + next: (yearList) => { + this.years = yearList.map(year => ({ + value: year.toString() + })); + console.log(this.years) + }, + error: (err) => { + console.error('Failed to get available years', err); + } + }); + } + + onSelectionChange() { + this.valueSelected.emit(this.selectedValue); + } + + getAvailableYears(): Observable { + return this.http.get( + `${endpoints.TEKNISKBACKEND}/${endpoints.GETYEARS}`, + {} + + ); + } + + +} diff --git a/src/app/admin/toggle/toggle.component.html b/src/app/admin/toggle/toggle.component.html new file mode 100644 index 00000000..60f4312f --- /dev/null +++ b/src/app/admin/toggle/toggle.component.html @@ -0,0 +1,10 @@ +
+ + Per måned + Per år + +
diff --git a/src/app/admin/toggle/toggle.component.scss b/src/app/admin/toggle/toggle.component.scss new file mode 100644 index 00000000..fa68806f --- /dev/null +++ b/src/app/admin/toggle/toggle.component.scss @@ -0,0 +1,35 @@ +.toggle-container { + display: flex; + justify-content: center; + padding: 20px; + margin-bottom: 20px; +} + +mat-button-toggle-group { + display: flex; + gap: 10px; /* Adds space between the toggle buttons */ +} + +mat-button-toggle { + background-color: #f5f5f5; + color: #333; + padding: 8px 16px; + font-size: 1rem; + border-radius: 5px; + transition: background-color 0.3s ease, color 0.3s ease; + border: 1px solid #ccc; +} + +mat-button-toggle:hover { + background-color: #e0e0e0; +} + +mat-button-toggle.mat-button-toggle-checked { + background-color: #1976d2; /* Active background */ + color: white; /* Active text color */ + border-color: #1976d2; /* Active border color */ +} + +.mat-button-toggle-group-appearance-legacy .mat-button-toggle { + margin: 0; +} diff --git a/src/app/admin/toggle/toggle.component.ts b/src/app/admin/toggle/toggle.component.ts new file mode 100644 index 00000000..b1cff035 --- /dev/null +++ b/src/app/admin/toggle/toggle.component.ts @@ -0,0 +1,30 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import {MatButtonToggleModule} from '@angular/material/button-toggle'; +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; + + +@Component({ + selector: 'app-toggle', + templateUrl: './toggle.component.html', + styleUrls: ['./toggle.component.scss'], + imports: [MatButtonToggleModule, FormsModule, ReactiveFormsModule], + standalone: true +}) +export class ToggleComponent implements OnInit { + @Output() toggleChanged = new EventEmitter(); + + toggleControl = new FormControl('month'); + + fontStyleControl = new FormControl(''); + + ngOnInit(): void { + this.toggleControl.valueChanges.subscribe((value) => { + const safeValue = value ?? 'month'; + console.log('Toggle changed:', value); + this.toggleChanged.emit(safeValue); + + }); + } + + } + diff --git a/src/app/shared/models/endpoints.ts b/src/app/shared/models/endpoints.ts index 3de0fcf2..02aa7d77 100644 --- a/src/app/shared/models/endpoints.ts +++ b/src/app/shared/models/endpoints.ts @@ -16,5 +16,8 @@ export const endpoints = { GETSTATUS: 'status', LOGOUT: 'logout', GETEXAMPLEDRAWINGS: 'getExampleDrawings', - LOGGER: 'logging' + LOGGER: 'logging', + GETSTATISTICSMONTH: 'getStatisticsPerMonth', + GETSTATISTICSYEAR: 'getStatisticsPerYear', + GETYEARS: 'getAvailableYears' }; From e60864702844a5eb9921abb2e9772f1449bdeba1 Mon Sep 17 00:00:00 2001 From: ivaj Date: Fri, 4 Oct 2024 15:15:14 +0200 Subject: [PATCH 03/10] Set up docker --- .dockerignore | 15 +++++++++++++ Dockerfile | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ nginx.conf | 16 ++++++++++++++ package.json | 2 +- 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..9b495245 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +Dockerfile* +docker-compose* +.dockerignore +.git +.gitignore +README.md +LICENSE +.vscode +Makefile +helm-charts +.env +.editorconfig +.idea +coverage* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a6532da9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,60 @@ +FROM node:18 AS base +WORKDIR /app + +# Copy package.json and bun.lockb +COPY package.json . +COPY bun.lockb . + +# Install Bun +RUN curl -fsSL https://bun.sh/install | bash + +# Add Bun to PATH +ENV BUN_INSTALL="/root/.bun" +ENV PATH="$BUN_INSTALL/bin:$PATH" + +# Install dependencies using Bun +RUN bun install --frozen-lockfile +RUN npm install -g @angular/cli +RUN bun install + +# --- DEVELOPMENT STAGE --- + +FROM base AS development +ENV NODE_ENV=development + +COPY . /app + +EXPOSE 4200 + +# Run the app in development mode using ng serve +CMD ["bun", "run", "start"] + +# --- BUILD STAGE --- +FROM base AS build + +# Copy all files for the build +COPY . /app + +RUN ng build --configuration ComputasProd + +RUN apt update && apt install -y nginx && \ + rm -rf /var/lib/apt/lists/* + +# --- PRODUCTION STAGE --- +FROM nginx:alpine AS production +ENV NODE_ENV=production + +# Copy the source code for building the production build +COPY . /app + +# Copy built files from the build stage to the Nginx html directory +COPY --from=build /app/dist/tekniskmuseum /usr/share/nginx/html + +# Copy the custom Nginx configuration +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Expose the Nginx port +EXPOSE 80 + +# Start Nginx +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 00000000..343b0d6b --- /dev/null +++ b/nginx.conf @@ -0,0 +1,16 @@ +server { + listen 80; + + server_name localhost; + + root /usr/share/nginx/html; + + location / { + try_files $uri $uri/ /index.html; + } + + location /assets/ { + + try_files $uri $uri/ /index.html; + } +} diff --git a/package.json b/package.json index d0d4d93a..aff0ce39 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "version": "0.0.0", "scripts": { "prettier": "prettier --end-of-line=crlf --write src/**/*.ts", - "start": "ng serve", + "start": "ng serve --host 0.0.0.0", "build": "ng build", "build:ci": "ng build --configuration production", "build:computas": "ng build --configuration computas", From a0274c0f61b6e5a46656ee9a58af05f37d7db5d7 Mon Sep 17 00:00:00 2001 From: Tobias Hermansen Date: Mon, 7 Oct 2024 12:09:46 +0200 Subject: [PATCH 04/10] create graph component to display usage stats --- package.json | 2 + src/app/admin/graph/graph.component.html | 3 + src/app/admin/graph/graph.component.scss | 4 ++ src/app/admin/graph/graph.component.ts | 66 +++++++++++++++++++ .../admin/info-page/info-page.component.html | 2 + .../admin/info-page/info-page.component.scss | 1 + .../admin/info-page/info-page.component.ts | 3 +- 7 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/app/admin/graph/graph.component.html create mode 100644 src/app/admin/graph/graph.component.scss create mode 100644 src/app/admin/graph/graph.component.ts diff --git a/package.json b/package.json index d0d4d93a..64655d3f 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "@angular/platform-browser-dynamic": "^18.0.2", "@angular/router": "^18.0.2", "@angular/service-worker": "^18.0.2", + "@canvasjs/angular-charts": "^1.2.0", + "@canvasjs/charts": "^3.10.10", "canvas-confetti": "^1.9.3", "howler": "^2.2.4", "rxjs": "~7.8.1", diff --git a/src/app/admin/graph/graph.component.html b/src/app/admin/graph/graph.component.html new file mode 100644 index 00000000..ce0404fa --- /dev/null +++ b/src/app/admin/graph/graph.component.html @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/src/app/admin/graph/graph.component.scss b/src/app/admin/graph/graph.component.scss new file mode 100644 index 00000000..a7ba0124 --- /dev/null +++ b/src/app/admin/graph/graph.component.scss @@ -0,0 +1,4 @@ +.canvasjs-chart-credit +{ + display: none !important; +} \ No newline at end of file diff --git a/src/app/admin/graph/graph.component.ts b/src/app/admin/graph/graph.component.ts new file mode 100644 index 00000000..10456e43 --- /dev/null +++ b/src/app/admin/graph/graph.component.ts @@ -0,0 +1,66 @@ +/* app.component.ts */ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { CommonModule } from '@angular/common'; +import { CanvasJSAngularChartsModule } from '@canvasjs/angular-charts'; + +@Component({ + selector: 'graph-component', + standalone: true, + imports: [RouterOutlet, CommonModule, CanvasJSAngularChartsModule], + templateUrl: './graph.component.html', + styleUrl: './graph.component.scss', +}) +export class GraphComponent { + chartOptions = { + animationEnabled: true, + theme: "light2", + title: { + text: "Antall spilte spill" + }, + axisX: { + valueFormatString: "MMM", + intervalType: "month", + interval: 1 + }, + axisY: { + title: "Antall spilte spill", + suffix: "" + }, + toolTip: { + shared: true + }, + legend: { + cursor: "pointer", + itemclick: function(e: any){ + if (typeof(e.dataSeries.visible) === "undefined" || e.dataSeries.visible) { + e.dataSeries.visible = false; + } else{ + e.dataSeries.visible = true; + } + e.chart.render(); + } + }, + data: [ + { + type: "line", + name: "Maximum", + showInLegend: true, + yValueFormatString: "#,###°F", + dataPoints: [ + { x: new Date(2021, 0, 1), y: 40 }, + { x: new Date(2021, 1, 1), y: 42 }, + { x: new Date(2021, 2, 1), y: 50 }, + { x: new Date(2021, 3, 1), y: 62 }, + { x: new Date(2021, 4, 1), y: 72 }, + { x: new Date(2021, 5, 1), y: 80 }, + { x: new Date(2021, 6, 1), y: 85 }, + { x: new Date(2021, 7, 1), y: 84 }, + { x: new Date(2021, 8, 1), y: 76 }, + { x: new Date(2021, 9, 1), y: 64 }, + { x: new Date(2021, 10, 1), y: 54 }, + { x: new Date(2021, 11, 1), y: 44 } + ] + }] + } +} \ No newline at end of file diff --git a/src/app/admin/info-page/info-page.component.html b/src/app/admin/info-page/info-page.component.html index c293ba8d..7c644366 100644 --- a/src/app/admin/info-page/info-page.component.html +++ b/src/app/admin/info-page/info-page.component.html @@ -8,6 +8,8 @@

Administrative handlinger

+ +

diff --git a/src/app/admin/info-page/info-page.component.scss b/src/app/admin/info-page/info-page.component.scss index c928b4db..71216734 100644 --- a/src/app/admin/info-page/info-page.component.scss +++ b/src/app/admin/info-page/info-page.component.scss @@ -112,3 +112,4 @@ br { p + p { margin-top: 0.5rem; } + diff --git a/src/app/admin/info-page/info-page.component.ts b/src/app/admin/info-page/info-page.component.ts index 4ddbdca8..41e4c156 100644 --- a/src/app/admin/info-page/info-page.component.ts +++ b/src/app/admin/info-page/info-page.component.ts @@ -7,13 +7,14 @@ import { PairingService } from '../../game/services/pairing.service'; import { MatButton } from '@angular/material/button'; import { LogData, StatusData } from '@/app/shared/models/backend-interfaces'; import { LoggingService } from '../../game/services/logging.service'; +import { GraphComponent } from '../graph/graph.component'; @Component({ selector: 'app-info', templateUrl: './info-page.component.html', styleUrls: ['./info-page.component.scss'], standalone: true, - imports: [MatButton], + imports: [MatButton, GraphComponent], }) export class InfoPageComponent { datasetString = 'Nullstill treningssett til originalen'; From 1441bf1179bd155a7d18abaec35dabe09fe96f44 Mon Sep 17 00:00:00 2001 From: ellenyuX Date: Mon, 7 Oct 2024 12:11:16 +0200 Subject: [PATCH 05/10] added components for displaying statistics --- .../info-dialog/info-dialog.component.ts | 4 +- .../select-month/select-month.component.html | 13 +++ .../select-month/select-month.component.scss | 21 +++++ .../select-month/select-month.component.ts | 84 +++++++++++++++++++ .../select-year.component.html} | 0 .../select-year.component.scss} | 0 .../select-year.component.ts} | 7 +- .../statistics.component.html} | 13 +-- .../statistics.component.scss} | 9 -- .../statistics.component.ts} | 50 +++-------- src/app/admin/toggle/toggle.component.ts | 3 +- 11 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 src/app/admin/select-month/select-month.component.html create mode 100644 src/app/admin/select-month/select-month.component.scss create mode 100644 src/app/admin/select-month/select-month.component.ts rename src/app/admin/{select/select.component.html => select-year/select-year.component.html} (100%) rename src/app/admin/{select/select.component.scss => select-year/select-year.component.scss} (100%) rename src/app/admin/{select/select.component.ts => select-year/select-year.component.ts} (89%) rename src/app/admin/{score/score.component.html => statistics/statistics.component.html} (64%) rename src/app/admin/{score/score.component.scss => statistics/statistics.component.scss} (92%) rename src/app/admin/{score/score.component.ts => statistics/statistics.component.ts} (63%) diff --git a/src/app/admin/info-dialog/info-dialog.component.ts b/src/app/admin/info-dialog/info-dialog.component.ts index 8042bcb8..1a3a4a15 100644 --- a/src/app/admin/info-dialog/info-dialog.component.ts +++ b/src/app/admin/info-dialog/info-dialog.component.ts @@ -3,7 +3,7 @@ import { MatDialog } from '@angular/material/dialog'; import { DialogTemplateComponent } from './../dialog-template/dialog-template.component'; import { ErrorLogDialogComponent } from '../error-dialog/error-dialog.component'; import { LogData } from '@/app/shared/models/backend-interfaces'; -import { ScoreComponent } from '../score/score.component'; +import { StatisticsComponent } from '../statistics/statistics.component'; @Component({ selector: 'app-info-dialog', @@ -31,7 +31,7 @@ export class InfoDialogComponent { } openStatistics() { - this.dialog.open(ScoreComponent, { + this.dialog.open(StatisticsComponent, { data: String, }); } diff --git a/src/app/admin/select-month/select-month.component.html b/src/app/admin/select-month/select-month.component.html new file mode 100644 index 00000000..32bcc41b --- /dev/null +++ b/src/app/admin/select-month/select-month.component.html @@ -0,0 +1,13 @@ + +
+

Velg måned og år

+ + Måned og år + + MM/YYYY + + + + +
\ No newline at end of file diff --git a/src/app/admin/select-month/select-month.component.scss b/src/app/admin/select-month/select-month.component.scss new file mode 100644 index 00000000..6d7116ad --- /dev/null +++ b/src/app/admin/select-month/select-month.component.scss @@ -0,0 +1,21 @@ +.example-picker .mat-calendar-period-button { + pointer-events: none; +} + +.example-picker .mat-calendar-arrow { + display: none; +} + +mat-form-field { + width: 100%; + max-width: 300px; + margin: 0 auto; +} + +.form-section { + width: 100%; + margin-bottom: 20px; + display: flex; + flex-direction: column; + align-items: center; +} \ No newline at end of file diff --git a/src/app/admin/select-month/select-month.component.ts b/src/app/admin/select-month/select-month.component.ts new file mode 100644 index 00000000..53c50d57 --- /dev/null +++ b/src/app/admin/select-month/select-month.component.ts @@ -0,0 +1,84 @@ +import { Component, EventEmitter, Inject, OnInit, Output, signal, ViewEncapsulation } from "@angular/core"; +import { FormControl, FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { MatDatepicker, MatDatepickerModule } from "@angular/material/datepicker"; +import { provideMomentDateAdapter } from '@angular/material-moment-adapter'; +import * as _moment from 'moment'; +import { default as _rollupMoment, Moment } from 'moment'; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatInputModule } from "@angular/material/input"; +import { MAT_DIALOG_DATA } from "@angular/material/dialog"; + +const moment = _rollupMoment || _moment; +export const MY_FORMATS = { + parse: { + dateInput: 'MM/YYYY', + }, + display: { + dateInput: 'MM/YYYY', + monthYearLabel: 'MMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY', + }, +}; + +@Component({ + selector: 'select-month-component', + templateUrl: './select-month.component.html', + styleUrls: ['./select-month.component.scss'], + providers: [ + provideMomentDateAdapter(MY_FORMATS), + ], + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + FormsModule, + ReactiveFormsModule, + ], +}) + +export class SelectMonthComponent implements OnInit { + scoreCount: number | null = null; + date = new FormControl(); + dataFetched = signal(false); + display_month: string = ""; + month: string = ""; + year: string = ""; + selected: string = "month"; + selectedYear: string = ""; + + @Output() valueSelected: EventEmitter = new EventEmitter(); + + constructor( + // public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: string) { } + + ngOnInit(): void { + this.date.valueChanges.subscribe(selectedDate => { + this.handleDateChange(); + }) + } + + setMonthAndYear(normalizedMonthAndYear: Moment, datepicker: MatDatepicker) { + const ctrlValue = this.date.value ?? moment(); + ctrlValue.month(normalizedMonthAndYear.month()); + ctrlValue.year(normalizedMonthAndYear.year()); + this.date.setValue(ctrlValue); + + datepicker.close(); + } + + handleDateChange() { + const ctrlValue = this.date.value; + this.month = ctrlValue.format("MM"); + this.display_month = ctrlValue.format("MMMM"); + this.year = ctrlValue.format('YYYY'); + + this.valueSelected.emit([this.month, this.display_month, this.year]); + + console.log(this.month, this.year) + } + +} \ No newline at end of file diff --git a/src/app/admin/select/select.component.html b/src/app/admin/select-year/select-year.component.html similarity index 100% rename from src/app/admin/select/select.component.html rename to src/app/admin/select-year/select-year.component.html diff --git a/src/app/admin/select/select.component.scss b/src/app/admin/select-year/select-year.component.scss similarity index 100% rename from src/app/admin/select/select.component.scss rename to src/app/admin/select-year/select-year.component.scss diff --git a/src/app/admin/select/select.component.ts b/src/app/admin/select-year/select-year.component.ts similarity index 89% rename from src/app/admin/select/select.component.ts rename to src/app/admin/select-year/select-year.component.ts index 4ca345bd..e3c5fefd 100644 --- a/src/app/admin/select/select.component.ts +++ b/src/app/admin/select-year/select-year.component.ts @@ -15,12 +15,12 @@ interface Year { * @title Basic select */ @Component({ - selector: 'select-component', - templateUrl: 'select.component.html', + selector: 'select-year-component', + templateUrl: 'select-year.component.html', standalone: true, imports: [MatFormFieldModule, MatSelectModule, MatInputModule, FormsModule], }) -export class SelectComponent implements OnInit { +export class SelectYearComponent implements OnInit { constructor(private http: HttpClient) {} years: Year[] = []; selectedValue: string = ""; @@ -33,7 +33,6 @@ export class SelectComponent implements OnInit { this.years = yearList.map(year => ({ value: year.toString() })); - console.log(this.years) }, error: (err) => { console.error('Failed to get available years', err); diff --git a/src/app/admin/score/score.component.html b/src/app/admin/statistics/statistics.component.html similarity index 64% rename from src/app/admin/score/score.component.html rename to src/app/admin/statistics/statistics.component.html index e4c86eca..fbe00e38 100644 --- a/src/app/admin/score/score.component.html +++ b/src/app/admin/statistics/statistics.component.html @@ -6,20 +6,11 @@
@if(selected === "month") { -

Velg måned og år

- - Måned og år - - MM/YYYY - - - - + } @else { - + }
diff --git a/src/app/admin/score/score.component.scss b/src/app/admin/statistics/statistics.component.scss similarity index 92% rename from src/app/admin/score/score.component.scss rename to src/app/admin/statistics/statistics.component.scss index bf6443bb..64d9f5ae 100644 --- a/src/app/admin/score/score.component.scss +++ b/src/app/admin/statistics/statistics.component.scss @@ -35,15 +35,6 @@ color: white; } - - .example-picker .mat-calendar-period-button { - pointer-events: none; - } - - .example-picker .mat-calendar-arrow { - display: none; - } - .statistics-content { padding: 20px; display: flex; diff --git a/src/app/admin/score/score.component.ts b/src/app/admin/statistics/statistics.component.ts similarity index 63% rename from src/app/admin/score/score.component.ts rename to src/app/admin/statistics/statistics.component.ts index d963fb26..733bbdb2 100644 --- a/src/app/admin/score/score.component.ts +++ b/src/app/admin/statistics/statistics.component.ts @@ -1,17 +1,13 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Component, Inject, signal, ViewEncapsulation } from '@angular/core'; -import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { provideMomentDateAdapter } from '@angular/material-moment-adapter'; -import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { ToggleComponent } from '../toggle/toggle.component'; +import { SelectMonthComponent } from '../select-month/select-month.component'; import * as _moment from 'moment'; // tslint:disable-next-line:no-duplicate-imports import { default as _rollupMoment, Moment } from 'moment'; -import { MatInputModule } from '@angular/material/input'; -import { MatFormFieldModule } from '@angular/material/form-field'; import { LoginService } from '../login.service'; -import { SelectComponent } from '../select/select.component'; +import { SelectYearComponent } from '../select-year/select-year.component'; const moment = _rollupMoment || _moment; export const MY_FORMATS = { @@ -28,28 +24,20 @@ export const MY_FORMATS = { @Component({ selector: 'app-score', - templateUrl: './score.component.html', - styleUrls: ['./score.component.scss'], - providers: [ - provideMomentDateAdapter(MY_FORMATS), - ], + templateUrl: './statistics.component.html', + styleUrls: ['./statistics.component.scss'], encapsulation: ViewEncapsulation.None, standalone: true, imports: [ - MatFormFieldModule, - MatInputModule, - MatDatepickerModule, - FormsModule, - ReactiveFormsModule, MatButtonToggleModule, ToggleComponent, - SelectComponent + SelectYearComponent, + SelectMonthComponent ], }) -export class ScoreComponent { +export class StatisticsComponent { scoreCount: number | null = null; - date = new FormControl(); dataFetched = signal(false); display_month: string = ""; month: string = ""; @@ -58,27 +46,12 @@ export class ScoreComponent { selectedYear: string = ""; constructor( - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, private loginService: LoginService, @Inject(MAT_DIALOG_DATA) public data: string) { } - - setMonthAndYear2(normalizedMonthAndYear: Moment, datepicker: MatDatepicker) { - const ctrlValue = this.date.value ?? moment(); - ctrlValue.month(normalizedMonthAndYear.month()); - ctrlValue.year(normalizedMonthAndYear.year()); - this.date.setValue(ctrlValue); - - datepicker.close(); - } - confirmSelection() { if (this.selected === "month") { - const ctrlValue = this.date.value; - this.month = ctrlValue.format("MM"); - this.display_month = ctrlValue.format("MMMM"); - this.year = ctrlValue.format('YYYY'); - this.loginService.getStatisticsPerMonth(this.month, this.year).subscribe({ next: (res) => { this.dataFetched.set(true); @@ -110,12 +83,15 @@ export class ScoreComponent { onToggleChanged(value: string) { this.selected = value; this.dataFetched.set(false); - } onYearSelected(year: string) { this.selectedYear = year; } - + onMonthSelected(date: string[]) { + this.month = date[0]; + this.display_month = date[1] + this.year = date[2]; + } } diff --git a/src/app/admin/toggle/toggle.component.ts b/src/app/admin/toggle/toggle.component.ts index b1cff035..c83e4b89 100644 --- a/src/app/admin/toggle/toggle.component.ts +++ b/src/app/admin/toggle/toggle.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; import {MatButtonToggleModule} from '@angular/material/button-toggle'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -20,7 +20,6 @@ export class ToggleComponent implements OnInit { ngOnInit(): void { this.toggleControl.valueChanges.subscribe((value) => { const safeValue = value ?? 'month'; - console.log('Toggle changed:', value); this.toggleChanged.emit(safeValue); }); From 712565e248cb4fbcb5b3f72f0417359a3867602c Mon Sep 17 00:00:00 2001 From: ellenyuX Date: Tue, 8 Oct 2024 10:07:42 +0200 Subject: [PATCH 06/10] conneced graph to data from backend --- package.json | 3 + src/app/admin/graph/graph.component.html | 6 +- src/app/admin/graph/graph.component.scss | 25 ++- src/app/admin/graph/graph.component.ts | 145 +++++++++++------- .../admin/info-page/info-page.component.html | 2 - .../statistics/statistics.component.html | 3 + .../statistics/statistics.component.scss | 12 +- .../admin/statistics/statistics.component.ts | 4 +- src/app/shared/models/endpoints.ts | 3 +- 9 files changed, 125 insertions(+), 78 deletions(-) diff --git a/package.json b/package.json index 64655d3f..d62074ff 100644 --- a/package.json +++ b/package.json @@ -22,14 +22,17 @@ "@angular/forms": "^18.0.2", "@angular/localize": "^18.0.4", "@angular/material": "^18.0.2", + "@angular/material-moment-adapter": "^18.2.7", "@angular/platform-browser": "^18.0.2", "@angular/platform-browser-dynamic": "^18.0.2", "@angular/router": "^18.0.2", "@angular/service-worker": "^18.0.2", "@canvasjs/angular-charts": "^1.2.0", "@canvasjs/charts": "^3.10.10", + "angular-moment": "^1.3.0", "canvas-confetti": "^1.9.3", "howler": "^2.2.4", + "moment": "^2.30.1", "rxjs": "~7.8.1", "socket.io-client": "^4.7.5", "tslib": "^2.6.3", diff --git a/src/app/admin/graph/graph.component.html b/src/app/admin/graph/graph.component.html index ce0404fa..82095212 100644 --- a/src/app/admin/graph/graph.component.html +++ b/src/app/admin/graph/graph.component.html @@ -1,3 +1,5 @@ -
- +
+ @if (render) { + + }
\ No newline at end of file diff --git a/src/app/admin/graph/graph.component.scss b/src/app/admin/graph/graph.component.scss index a7ba0124..ab9cbe90 100644 --- a/src/app/admin/graph/graph.component.scss +++ b/src/app/admin/graph/graph.component.scss @@ -1,4 +1,21 @@ -.canvasjs-chart-credit -{ - display: none !important; -} \ No newline at end of file +.chart-container { + justify-content: center; /* Center horizontally */ + align-items: center; /* Center vertically */ + margin: 20px 0; /* Add some vertical margin */ + width: 100%; /* Full width */ + display: flex; +} + +.canvasjs-chart { + width: 90%; /* Default to 60% width */ + height: 100px; /* Set height */ + position: relative; +} + +@media (max-width: 768px) { + .canvasjs-chart { + width: 90%; /* Increase width on smaller screens */ + } +} + +.canvasjs-chart-container>canvas:first-of-type { position: relative !important; } diff --git a/src/app/admin/graph/graph.component.ts b/src/app/admin/graph/graph.component.ts index 10456e43..cb461102 100644 --- a/src/app/admin/graph/graph.component.ts +++ b/src/app/admin/graph/graph.component.ts @@ -1,66 +1,95 @@ -/* app.component.ts */ -import { Component } from '@angular/core'; +import { Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { CanvasJSAngularChartsModule } from '@canvasjs/angular-charts'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { endpoints } from '@/app/shared/models/endpoints'; import { RouterOutlet } from '@angular/router'; import { CommonModule } from '@angular/common'; -import { CanvasJSAngularChartsModule } from '@canvasjs/angular-charts'; - + @Component({ selector: 'graph-component', standalone: true, imports: [RouterOutlet, CommonModule, CanvasJSAngularChartsModule], templateUrl: './graph.component.html', - styleUrl: './graph.component.scss', + styleUrls: ['./graph.component.scss'], }) -export class GraphComponent { - chartOptions = { - animationEnabled: true, - theme: "light2", - title: { - text: "Antall spilte spill" - }, - axisX: { - valueFormatString: "MMM", - intervalType: "month", - interval: 1 - }, - axisY: { - title: "Antall spilte spill", - suffix: "" - }, - toolTip: { - shared: true - }, - legend: { - cursor: "pointer", - itemclick: function(e: any){ - if (typeof(e.dataSeries.visible) === "undefined" || e.dataSeries.visible) { - e.dataSeries.visible = false; - } else{ - e.dataSeries.visible = true; - } - e.chart.render(); - } - }, - data: [ - { - type: "line", - name: "Maximum", - showInLegend: true, - yValueFormatString: "#,###°F", - dataPoints: [ - { x: new Date(2021, 0, 1), y: 40 }, - { x: new Date(2021, 1, 1), y: 42 }, - { x: new Date(2021, 2, 1), y: 50 }, - { x: new Date(2021, 3, 1), y: 62 }, - { x: new Date(2021, 4, 1), y: 72 }, - { x: new Date(2021, 5, 1), y: 80 }, - { x: new Date(2021, 6, 1), y: 85 }, - { x: new Date(2021, 7, 1), y: 84 }, - { x: new Date(2021, 8, 1), y: 76 }, - { x: new Date(2021, 9, 1), y: 64 }, - { x: new Date(2021, 10, 1), y: 54 }, - { x: new Date(2021, 11, 1), y: 44 } - ] - }] - } -} \ No newline at end of file +export class GraphComponent implements OnChanges, OnDestroy { + @Input() year: string = ''; + data: any; + render: boolean = false; + chartOptions: any = { + animationEnabled: true, + theme: "light2", + title: { + text: "Antall spilte spill" + }, + axisX: { + valueFormatString: "MMM", + intervalType: "month", + interval: 1 + }, + axisY: { + title: "Antall spilte spill", + suffix: "" + }, + toolTip: { + shared: true + }, + legend: { + cursor: "pointer", + itemclick: function (e: any) { + e.dataSeries.visible = typeof e.dataSeries.visible === "undefined" || e.dataSeries.visible ? false : true; + } + }, + data: [{ + type: "line", + name: "Antall spill", + showInLegend: true, + dataPoints: [] // Initialize with empty dataPoints + }] + }; + + constructor(private http: HttpClient) {} + + ngOnChanges() { + // Triggered when the input property `year` changes + if (this.year) { + this.getDataList().subscribe({ + next: (res) => { + this.data = res; + this.updateChartData(); + this.render = true; + }, + error: (err) => { + console.error('Failed to get data from backend', err); + } + }); + } + } + + updateChartData() { + const dataPoints = Object.entries(this.data).map(([month, scoreCount]) => ({ + x: new Date(+this.year, Number(month) - 1, 1), // Month is zero-based in JavaScript dates + y: scoreCount + })); + + // Update chart options with new dataPoints + this.chartOptions.data[0].dataPoints = dataPoints; + + console.log('Updated Chart Options:', this.chartOptions.data[0].dataPoints); + + } + + getDataList(): Observable { + // Fetch data based on the selected year + return this.http.get( + `${endpoints.TEKNISKBACKEND}/${endpoints.ADMIN}/${endpoints.GETSCORESPERMONTH}?year=${this.year}` + ); + } + + ngOnDestroy(): void { + this.render = false; + } + + +} diff --git a/src/app/admin/info-page/info-page.component.html b/src/app/admin/info-page/info-page.component.html index ba8e6fbc..6d62c593 100644 --- a/src/app/admin/info-page/info-page.component.html +++ b/src/app/admin/info-page/info-page.component.html @@ -10,8 +10,6 @@

Administrative handlinger

- -

diff --git a/src/app/admin/statistics/statistics.component.html b/src/app/admin/statistics/statistics.component.html index fbe00e38..3722a610 100644 --- a/src/app/admin/statistics/statistics.component.html +++ b/src/app/admin/statistics/statistics.component.html @@ -28,6 +28,9 @@

Statistikk for {{ display_month }} {{ year }}

Statistikk for {{ selectedYear }}

}

Totalt antall spill: {{ scoreCount }}

+ + + } diff --git a/src/app/admin/statistics/statistics.component.scss b/src/app/admin/statistics/statistics.component.scss index 64d9f5ae..df8bc84a 100644 --- a/src/app/admin/statistics/statistics.component.scss +++ b/src/app/admin/statistics/statistics.component.scss @@ -14,7 +14,7 @@ background: #fff; padding: 2rem; border-radius: 10px; - width: 400px; + width: 50%; text-align: center; } @@ -35,14 +35,6 @@ color: white; } - .statistics-content { - padding: 20px; - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - } - h2 { font-size: 1.5rem; margin-bottom: 20px; @@ -82,7 +74,7 @@ background-color: #f5f5f5; border-radius: 10px; width: 100%; - max-width: 350px; + max-width: 100%; text-align: center; } diff --git a/src/app/admin/statistics/statistics.component.ts b/src/app/admin/statistics/statistics.component.ts index 733bbdb2..cec9426c 100644 --- a/src/app/admin/statistics/statistics.component.ts +++ b/src/app/admin/statistics/statistics.component.ts @@ -3,6 +3,7 @@ import { Component, Inject, signal, ViewEncapsulation } from '@angular/core'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { ToggleComponent } from '../toggle/toggle.component'; import { SelectMonthComponent } from '../select-month/select-month.component'; +import { GraphComponent } from '../graph/graph.component'; import * as _moment from 'moment'; // tslint:disable-next-line:no-duplicate-imports import { default as _rollupMoment, Moment } from 'moment'; @@ -32,7 +33,8 @@ export const MY_FORMATS = { MatButtonToggleModule, ToggleComponent, SelectYearComponent, - SelectMonthComponent + SelectMonthComponent, + GraphComponent ], }) diff --git a/src/app/shared/models/endpoints.ts b/src/app/shared/models/endpoints.ts index 02aa7d77..fd634cdc 100644 --- a/src/app/shared/models/endpoints.ts +++ b/src/app/shared/models/endpoints.ts @@ -19,5 +19,6 @@ export const endpoints = { LOGGER: 'logging', GETSTATISTICSMONTH: 'getStatisticsPerMonth', GETSTATISTICSYEAR: 'getStatisticsPerYear', - GETYEARS: 'getAvailableYears' + GETYEARS: 'getAvailableYears', + GETSCORESPERMONTH: 'getScoresPerMonth' }; From 6d5b7aba25d94265ecf2705a7c9c9eb7af606e27 Mon Sep 17 00:00:00 2001 From: ellenyuX Date: Tue, 8 Oct 2024 12:03:13 +0200 Subject: [PATCH 07/10] fix some small changes --- src/app/admin/graph/graph.component.html | 2 +- src/app/admin/graph/graph.component.scss | 3 ++- src/app/admin/graph/graph.component.ts | 14 +++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/app/admin/graph/graph.component.html b/src/app/admin/graph/graph.component.html index 82095212..239da0e6 100644 --- a/src/app/admin/graph/graph.component.html +++ b/src/app/admin/graph/graph.component.html @@ -1,5 +1,5 @@
@if (render) { - + }
\ No newline at end of file diff --git a/src/app/admin/graph/graph.component.scss b/src/app/admin/graph/graph.component.scss index ab9cbe90..406c9c34 100644 --- a/src/app/admin/graph/graph.component.scss +++ b/src/app/admin/graph/graph.component.scss @@ -4,6 +4,7 @@ margin: 20px 0; /* Add some vertical margin */ width: 100%; /* Full width */ display: flex; + height: 500px; } .canvasjs-chart { @@ -18,4 +19,4 @@ } } -.canvasjs-chart-container>canvas:first-of-type { position: relative !important; } +.canvasjs-chart>canvas:first-of-type { position: relative !important; } diff --git a/src/app/admin/graph/graph.component.ts b/src/app/admin/graph/graph.component.ts index cb461102..d2719f6a 100644 --- a/src/app/admin/graph/graph.component.ts +++ b/src/app/admin/graph/graph.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnDestroy, Renderer2 } from '@angular/core'; import { CanvasJSAngularChartsModule } from '@canvasjs/angular-charts'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @@ -13,7 +13,7 @@ import { CommonModule } from '@angular/common'; templateUrl: './graph.component.html', styleUrls: ['./graph.component.scss'], }) -export class GraphComponent implements OnChanges, OnDestroy { +export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { @Input() year: string = ''; data: any; render: boolean = false; @@ -49,7 +49,7 @@ export class GraphComponent implements OnChanges, OnDestroy { }] }; - constructor(private http: HttpClient) {} + constructor(private http: HttpClient, private el: ElementRef, private renderer: Renderer2) {} ngOnChanges() { // Triggered when the input property `year` changes @@ -91,5 +91,13 @@ export class GraphComponent implements OnChanges, OnDestroy { this.render = false; } + ngAfterViewInit(): void { + const canvasChart = this.el.nativeElement.querySelector('canvasjs-chart'); + if (canvasChart) { + this.renderer.setStyle(canvasChart, 'width', '100%'); + this.renderer.setStyle(canvasChart, 'height', '400px'); + } + } + } From d81741a71c6c39680923f7640267e2046ca99ccd Mon Sep 17 00:00:00 2001 From: ellenyuX Date: Tue, 8 Oct 2024 12:04:49 +0200 Subject: [PATCH 08/10] more changes --- src/app/admin/graph/graph.component.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/app/admin/graph/graph.component.ts b/src/app/admin/graph/graph.component.ts index d2719f6a..30ff86f5 100644 --- a/src/app/admin/graph/graph.component.ts +++ b/src/app/admin/graph/graph.component.ts @@ -45,14 +45,13 @@ export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { type: "line", name: "Antall spill", showInLegend: true, - dataPoints: [] // Initialize with empty dataPoints + dataPoints: [] }] }; constructor(private http: HttpClient, private el: ElementRef, private renderer: Renderer2) {} ngOnChanges() { - // Triggered when the input property `year` changes if (this.year) { this.getDataList().subscribe({ next: (res) => { @@ -69,19 +68,15 @@ export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { updateChartData() { const dataPoints = Object.entries(this.data).map(([month, scoreCount]) => ({ - x: new Date(+this.year, Number(month) - 1, 1), // Month is zero-based in JavaScript dates + x: new Date(+this.year, Number(month) - 1, 1), y: scoreCount })); - // Update chart options with new dataPoints this.chartOptions.data[0].dataPoints = dataPoints; - - console.log('Updated Chart Options:', this.chartOptions.data[0].dataPoints); } getDataList(): Observable { - // Fetch data based on the selected year return this.http.get( `${endpoints.TEKNISKBACKEND}/${endpoints.ADMIN}/${endpoints.GETSCORESPERMONTH}?year=${this.year}` ); From 34a955a29578dfa1f6dc1dc471d390ac0e71b1f8 Mon Sep 17 00:00:00 2001 From: ellenyuX Date: Wed, 9 Oct 2024 09:21:39 +0200 Subject: [PATCH 09/10] linting changes --- src/app/admin/graph/graph.component.ts | 47 ++++++++++++------- .../select-month/select-month.component.ts | 16 +++---- .../select-year/select-year.component.ts | 4 +- .../statistics/statistics.component.html | 11 +++-- .../admin/statistics/statistics.component.ts | 29 ++++-------- 5 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/app/admin/graph/graph.component.ts b/src/app/admin/graph/graph.component.ts index 30ff86f5..0ae0fbbd 100644 --- a/src/app/admin/graph/graph.component.ts +++ b/src/app/admin/graph/graph.component.ts @@ -6,22 +6,29 @@ import { endpoints } from '@/app/shared/models/endpoints'; import { RouterOutlet } from '@angular/router'; import { CommonModule } from '@angular/common'; +interface DataPoint { + x: Date; + y: number; +} + +type ScoresPerMonthResponse = Record; + @Component({ - selector: 'graph-component', + selector: 'app-graph-component', standalone: true, imports: [RouterOutlet, CommonModule, CanvasJSAngularChartsModule], templateUrl: './graph.component.html', styleUrls: ['./graph.component.scss'], }) export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { - @Input() year: string = ''; - data: any; - render: boolean = false; - chartOptions: any = { + @Input() year = ''; + dataList: Record = {}; + render = false; + chartOptions = { animationEnabled: true, theme: "light2", title: { - text: "Antall spilte spill" + text: "Statistikk for året " }, axisX: { valueFormatString: "MMM", @@ -37,7 +44,7 @@ export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { }, legend: { cursor: "pointer", - itemclick: function (e: any) { + itemclick: function (e: { dataSeries: { visible: boolean; }; }) { e.dataSeries.visible = typeof e.dataSeries.visible === "undefined" || e.dataSeries.visible ? false : true; } }, @@ -45,7 +52,7 @@ export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { type: "line", name: "Antall spill", showInLegend: true, - dataPoints: [] + dataPoints: [] as DataPoint[] }] }; @@ -55,7 +62,7 @@ export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { if (this.year) { this.getDataList().subscribe({ next: (res) => { - this.data = res; + this.dataList = res; this.updateChartData(); this.render = true; }, @@ -67,23 +74,28 @@ export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { } updateChartData() { - const dataPoints = Object.entries(this.data).map(([month, scoreCount]) => ({ - x: new Date(+this.year, Number(month) - 1, 1), - y: scoreCount - })); + const dataPoints: DataPoint[] = Object.entries(this.dataList).map(([month, scoreCount]) => ({ + x: new Date(+this.year, Number(month) - 1, 1), + y: Number(scoreCount) + })); this.chartOptions.data[0].dataPoints = dataPoints; + this.chartOptions.title.text += this.year; + } - getDataList(): Observable { - return this.http.get( - `${endpoints.TEKNISKBACKEND}/${endpoints.ADMIN}/${endpoints.GETSCORESPERMONTH}?year=${this.year}` + getDataList(): Observable { + return this.http.get( + `${endpoints.TEKNISKBACKEND}/${endpoints.ADMIN}/${endpoints.GETSCORESPERMONTH}?year=${this.year}`, + { + withCredentials: true, + } ); } ngOnDestroy(): void { - this.render = false; + this.render = false; } ngAfterViewInit(): void { @@ -94,5 +106,4 @@ export class GraphComponent implements OnChanges, OnDestroy, AfterViewInit { } } - } diff --git a/src/app/admin/select-month/select-month.component.ts b/src/app/admin/select-month/select-month.component.ts index 53c50d57..8cfff638 100644 --- a/src/app/admin/select-month/select-month.component.ts +++ b/src/app/admin/select-month/select-month.component.ts @@ -22,7 +22,7 @@ export const MY_FORMATS = { }; @Component({ - selector: 'select-month-component', + selector: 'app-select-month-component', templateUrl: './select-month.component.html', styleUrls: ['./select-month.component.scss'], providers: [ @@ -43,20 +43,19 @@ export class SelectMonthComponent implements OnInit { scoreCount: number | null = null; date = new FormControl(); dataFetched = signal(false); - display_month: string = ""; - month: string = ""; - year: string = ""; - selected: string = "month"; - selectedYear: string = ""; + display_month = ""; + month = ""; + year = ""; + selected = "month"; + selectedYear = ""; @Output() valueSelected: EventEmitter = new EventEmitter(); constructor( - // public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: string) { } ngOnInit(): void { - this.date.valueChanges.subscribe(selectedDate => { + this.date.valueChanges.subscribe(() => { this.handleDateChange(); }) } @@ -78,7 +77,6 @@ export class SelectMonthComponent implements OnInit { this.valueSelected.emit([this.month, this.display_month, this.year]); - console.log(this.month, this.year) } } \ No newline at end of file diff --git a/src/app/admin/select-year/select-year.component.ts b/src/app/admin/select-year/select-year.component.ts index e3c5fefd..18785761 100644 --- a/src/app/admin/select-year/select-year.component.ts +++ b/src/app/admin/select-year/select-year.component.ts @@ -15,7 +15,7 @@ interface Year { * @title Basic select */ @Component({ - selector: 'select-year-component', + selector: 'app-select-year-component', templateUrl: 'select-year.component.html', standalone: true, imports: [MatFormFieldModule, MatSelectModule, MatInputModule, FormsModule], @@ -23,7 +23,7 @@ interface Year { export class SelectYearComponent implements OnInit { constructor(private http: HttpClient) {} years: Year[] = []; - selectedValue: string = ""; + selectedValue = ""; @Output() valueSelected: EventEmitter = new EventEmitter(); diff --git a/src/app/admin/statistics/statistics.component.html b/src/app/admin/statistics/statistics.component.html index 3722a610..b603e64c 100644 --- a/src/app/admin/statistics/statistics.component.html +++ b/src/app/admin/statistics/statistics.component.html @@ -6,11 +6,11 @@
@if(selected === "month") { - + } @else { - + }
@@ -21,15 +21,18 @@ @if (dataFetched()) {

- @if (selected == "month") { + @if (selected === "month") {

Statistikk for {{ display_month }} {{ year }}

} @else {

Statistikk for {{ selectedYear }}

}

Totalt antall spill: {{ scoreCount }}

+

- + @if (selected === "year") { + + }
} diff --git a/src/app/admin/statistics/statistics.component.ts b/src/app/admin/statistics/statistics.component.ts index cec9426c..ffb26d03 100644 --- a/src/app/admin/statistics/statistics.component.ts +++ b/src/app/admin/statistics/statistics.component.ts @@ -4,25 +4,11 @@ import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { ToggleComponent } from '../toggle/toggle.component'; import { SelectMonthComponent } from '../select-month/select-month.component'; import { GraphComponent } from '../graph/graph.component'; -import * as _moment from 'moment'; -// tslint:disable-next-line:no-duplicate-imports -import { default as _rollupMoment, Moment } from 'moment'; +// import * as _moment from 'moment'; +// import { default as _rollupMoment } from 'moment'; import { LoginService } from '../login.service'; import { SelectYearComponent } from '../select-year/select-year.component'; -const moment = _rollupMoment || _moment; -export const MY_FORMATS = { - parse: { - dateInput: 'MM/YYYY', - }, - display: { - dateInput: 'MM/YYYY', - monthYearLabel: 'MMM YYYY', - dateA11yLabel: 'LL', - monthYearA11yLabel: 'MMMM YYYY', - }, -}; - @Component({ selector: 'app-score', templateUrl: './statistics.component.html', @@ -41,11 +27,11 @@ export const MY_FORMATS = { export class StatisticsComponent { scoreCount: number | null = null; dataFetched = signal(false); - display_month: string = ""; - month: string = ""; - year: string = ""; - selected: string = "month"; - selectedYear: string = ""; + display_month = ""; + month = ""; + year= ""; + selected = "month"; + selectedYear = ""; constructor( public dialogRef: MatDialogRef, @@ -92,6 +78,7 @@ export class StatisticsComponent { } onMonthSelected(date: string[]) { + this.dataFetched.set(false); this.month = date[0]; this.display_month = date[1] this.year = date[2]; From 0cc24c7391a62f076bbc5390dc7caba62ab01873 Mon Sep 17 00:00:00 2001 From: ellenyuX Date: Fri, 11 Oct 2024 09:38:29 +0200 Subject: [PATCH 10/10] linting and making the dialog go away when you click outside of the box. and also not overflow. rip --- .../error-dialog/error-dialog.component.html | 2 +- .../error-dialog/error-dialog.component.ts | 4 -- .../info-dialog/info-dialog.component.ts | 4 +- .../admin/info-page/info-page.component.ts | 20 +++++---- .../statistics/statistics.component.html | 11 +++-- .../statistics/statistics.component.scss | 44 +++++++++++++------ .../admin/statistics/statistics.component.ts | 19 +++++--- 7 files changed, 65 insertions(+), 39 deletions(-) diff --git a/src/app/admin/error-dialog/error-dialog.component.html b/src/app/admin/error-dialog/error-dialog.component.html index 1a5eb69b..ccef78b8 100644 --- a/src/app/admin/error-dialog/error-dialog.component.html +++ b/src/app/admin/error-dialog/error-dialog.component.html @@ -9,5 +9,5 @@

} - + \ No newline at end of file diff --git a/src/app/admin/error-dialog/error-dialog.component.ts b/src/app/admin/error-dialog/error-dialog.component.ts index 8458df2a..000118f3 100644 --- a/src/app/admin/error-dialog/error-dialog.component.ts +++ b/src/app/admin/error-dialog/error-dialog.component.ts @@ -13,8 +13,4 @@ export class ErrorLogDialogComponent { logs = this.data - closeDialog(): void { - this.dialogRef.close(); - } - } diff --git a/src/app/admin/info-dialog/info-dialog.component.ts b/src/app/admin/info-dialog/info-dialog.component.ts index 212168e3..ed45be6d 100644 --- a/src/app/admin/info-dialog/info-dialog.component.ts +++ b/src/app/admin/info-dialog/info-dialog.component.ts @@ -31,8 +31,6 @@ export class InfoDialogComponent { } openStatistics() { - this.dialog.open(StatisticsComponent, { - data: String, - }); + this.dialog.open(StatisticsComponent); } } diff --git a/src/app/admin/info-page/info-page.component.ts b/src/app/admin/info-page/info-page.component.ts index 5a38fd73..f13609b5 100644 --- a/src/app/admin/info-page/info-page.component.ts +++ b/src/app/admin/info-page/info-page.component.ts @@ -2,12 +2,14 @@ import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { LoginService } from '../login.service'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { InfoDialogComponent } from '../info-dialog/info-dialog.component'; -import { PairingService } from '../../game/services/pairing.service'; import { MatButton } from '@angular/material/button'; import { LogData, StatusData } from '@/app/shared/models/backend-interfaces'; import { LoggingService } from '../../game/services/logging.service'; import { GraphComponent } from '../graph/graph.component'; +import { StatisticsComponent } from '../statistics/statistics.component'; +import { MatDialog } from '@angular/material/dialog'; +import { DialogComponent } from '../dialog/dialog.component'; +import { ErrorLogDialogComponent } from '../error-dialog/error-dialog.component'; @Component({ selector: 'app-info', @@ -31,10 +33,10 @@ export class InfoPageComponent { private router: Router, private loginService: LoginService, private _snackBar: MatSnackBar, - private _dialog: InfoDialogComponent, - private pairing: PairingService, + private dialog: MatDialog, private loggingService: LoggingService, ) {} + clearHighScore() { let msg = ''; @@ -90,7 +92,9 @@ export class InfoPageComponent { const name = res.CV_iteration_name; const time = res.CV_time_created; const count = res.BLOB_image_count; - this._dialog.openDialog(name, time, count.toString()); + this.dialog.open(DialogComponent, { + data: { iterationName: name, timeCreated: time, imageCount: count.toString() }, + }); }, () => { this.openSnackBar(this.errorMsg); @@ -99,13 +103,13 @@ export class InfoPageComponent { } getStatistics() { - this._dialog.openStatistics(); + this.dialog.open(StatisticsComponent); } getLogger() { this.loginService.getLogger().subscribe( (res: LogData[]) => { - this._dialog.openErrorLog(res) + this.dialog.open(ErrorLogDialogComponent, {data: res}); }, (error) => { this.openSnackBar(error); @@ -123,7 +127,7 @@ export class InfoPageComponent { message: str.slice(80,115), })) - this._dialog.openErrorLog(formatted_logs) + this.dialog.open(ErrorLogDialogComponent, {data: formatted_logs}); } diff --git a/src/app/admin/statistics/statistics.component.html b/src/app/admin/statistics/statistics.component.html index b603e64c..79111a9f 100644 --- a/src/app/admin/statistics/statistics.component.html +++ b/src/app/admin/statistics/statistics.component.html @@ -1,4 +1,4 @@ -
+
@@ -12,10 +12,13 @@ @else { } + + + +
- @if (dataFetched()) { @@ -28,7 +31,7 @@

Statistikk for {{ display_month }} {{ year }}

Statistikk for {{ selectedYear }}

}

Totalt antall spill: {{ scoreCount }}

-

+
@if (selected === "year") { @@ -38,6 +41,6 @@

Statistikk for {{ selectedYear }}

} - +
diff --git a/src/app/admin/statistics/statistics.component.scss b/src/app/admin/statistics/statistics.component.scss index df8bc84a..e77ff420 100644 --- a/src/app/admin/statistics/statistics.component.scss +++ b/src/app/admin/statistics/statistics.component.scss @@ -1,27 +1,37 @@ -.statistics { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); + .mat-dialog-container { + border-radius: 56px; + width: 698px; + height: 546px; + display: flex; - justify-content: center; align-items: center; + justify-content: center; + overflow-y: auto; + } + + .content { + padding: 20px; + background-color: #f5f5f5; + border-radius: 8px; } .statistics-content { - background: #fff; - padding: 2rem; - border-radius: 10px; - width: 50%; - text-align: center; + max-height: 500px; + overflow-y: auto; + margin-bottom: 20px; + padding: 10px; + margin-bottom: 10px; + background-color: #fff; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } button { margin-top: 1rem; padding: 0.5rem 1rem; font-size: 1rem; + align-items: center; } .confirm { @@ -94,4 +104,12 @@ .close-btn:hover { background-color: #d32f2f; } + + .cdk-overlay-backdrop { + z-index: 1000 !important; + } + + .cdk-overlay-pane { + z-index: 1001 !important; + } \ No newline at end of file diff --git a/src/app/admin/statistics/statistics.component.ts b/src/app/admin/statistics/statistics.component.ts index ffb26d03..9aebb082 100644 --- a/src/app/admin/statistics/statistics.component.ts +++ b/src/app/admin/statistics/statistics.component.ts @@ -1,5 +1,5 @@ -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Component, Inject, signal, ViewEncapsulation } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { Component, Inject, OnDestroy, signal } from '@angular/core'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { ToggleComponent } from '../toggle/toggle.component'; import { SelectMonthComponent } from '../select-month/select-month.component'; @@ -9,22 +9,23 @@ import { GraphComponent } from '../graph/graph.component'; import { LoginService } from '../login.service'; import { SelectYearComponent } from '../select-year/select-year.component'; + @Component({ selector: 'app-score', templateUrl: './statistics.component.html', styleUrls: ['./statistics.component.scss'], - encapsulation: ViewEncapsulation.None, standalone: true, imports: [ MatButtonToggleModule, ToggleComponent, SelectYearComponent, SelectMonthComponent, - GraphComponent + GraphComponent, + MatDialogModule ], }) -export class StatisticsComponent { +export class StatisticsComponent implements OnDestroy { scoreCount: number | null = null; dataFetched = signal(false); display_month = ""; @@ -37,6 +38,7 @@ export class StatisticsComponent { public dialogRef: MatDialogRef, private loginService: LoginService, @Inject(MAT_DIALOG_DATA) public data: string) { } + confirmSelection() { if (this.selected === "month") { @@ -64,7 +66,7 @@ export class StatisticsComponent { } } - closeStatistics(): void { + closeDialog(): void { this.dialogRef.close(); } @@ -83,4 +85,9 @@ export class StatisticsComponent { this.display_month = date[1] this.year = date[2]; } + + ngOnDestroy(): void { + this.dialogRef.close(); + } + }