From 9462031af50f0208267e1ca9c400caf1de23dbe7 Mon Sep 17 00:00:00 2001 From: Kirill Ivlev Date: Wed, 13 Nov 2024 02:09:03 +0400 Subject: [PATCH] versus implementation --- .../admin-testing.component.html | 6 +++ .../admin-testing/admin-testing.component.ts | 12 ++++++ .../queue-actions.component.html | 5 +++ .../queue-actions/queue-actions.component.ts | 20 +++++++++- src/app/app.component.html | 2 +- src/app/app.component.ts | 37 +++++++++++++------ .../cards-history.component.scss | 2 +- .../participant-item.component.html | 2 +- .../participant-item.component.ts | 13 +++++-- .../components/question/question.component.ts | 30 +++++++++++---- .../components/versus/versus.component.html | 18 +++++++-- .../components/versus/versus.component.scss | 34 ++++++++++++++++- src/app/components/versus/versus.component.ts | 26 +++++++++++-- src/app/services/api.service.ts | 32 ++++++++++++++++ src/app/services/event.service.ts | 4 ++ src/app/services/testing-api.service.ts | 14 ++++++- src/types/server-event.ts | 3 ++ src/types/versus-item.ts | 6 +++ 18 files changed, 227 insertions(+), 39 deletions(-) create mode 100644 src/types/versus-item.ts diff --git a/src/app/admin/admin-testing/admin-testing.component.html b/src/app/admin/admin-testing/admin-testing.component.html index 8c78e96..98182b6 100644 --- a/src/app/admin/admin-testing/admin-testing.component.html +++ b/src/app/admin/admin-testing/admin-testing.component.html @@ -1,6 +1,12 @@

Game testing menu

+

Players

+ +

Game

+ +

Versus

+
diff --git a/src/app/admin/admin-testing/admin-testing.component.ts b/src/app/admin/admin-testing/admin-testing.component.ts index 4d2522b..aac42ab 100644 --- a/src/app/admin/admin-testing/admin-testing.component.ts +++ b/src/app/admin/admin-testing/admin-testing.component.ts @@ -37,4 +37,16 @@ export class AdminTestingComponent implements OnInit, OnDestroy { simulateVersus() { this.testingApiService.simulateVersus().pipe(takeUntil(this.destroyed$)).subscribe((r) => console.log(r)); } + + resetAllVersusTasksAsIncompleted() { + this.testingApiService.resetAllVersusTasksAsIncompleted().pipe(takeUntil(this.destroyed$)).subscribe((r) => console.log(r)); + } + + resetAllPlayersScore() { + this.testingApiService.resetAllPlayersScore().pipe(takeUntil(this.destroyed$)).subscribe(r => console.log(r)); + } + + clearGameQueue() { + this.testingApiService.clearGameQueue().pipe(takeUntil(this.destroyed$)).subscribe((r => console.log(r))); + } } diff --git a/src/app/admin/components/queue-actions/queue-actions.component.html b/src/app/admin/components/queue-actions/queue-actions.component.html index cc698f5..4f528f2 100644 --- a/src/app/admin/components/queue-actions/queue-actions.component.html +++ b/src/app/admin/components/queue-actions/queue-actions.component.html @@ -3,3 +3,8 @@
tg: {{ gameQueue.type }}
+
+

Who won

+ + +
\ No newline at end of file diff --git a/src/app/admin/components/queue-actions/queue-actions.component.ts b/src/app/admin/components/queue-actions/queue-actions.component.ts index fb00be4..fe1bd5c 100644 --- a/src/app/admin/components/queue-actions/queue-actions.component.ts +++ b/src/app/admin/components/queue-actions/queue-actions.component.ts @@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { EventService } from "../../../services/event.service"; import { Subject } from "rxjs"; import { map, takeUntil } from "rxjs/operators"; -import { EventGameQueue, QueueTypes } from "../../../../types/server-event"; +import {EventGameQueue, QueueTypes, VersusBeginEvent} from "../../../../types/server-event"; import { ApiService } from "../../../services/api.service"; @Component({ @@ -14,7 +14,7 @@ export class QueueActionsComponent implements OnInit, OnDestroy { destroyed$ = new Subject() constructor(private eventService: EventService, private apiService: ApiService) { } gameQueue: EventGameQueue | null; - + versusData: VersusBeginEvent| null = null; ngOnInit(): void { this.eventService.gameQueueEvent.pipe( takeUntil(this.destroyed$), @@ -22,7 +22,17 @@ export class QueueActionsComponent implements OnInit, OnDestroy { ).subscribe(e => { this.gameQueue = e; }); + this.setVersusHandler(); } + + setVersusHandler() { + this.eventService.versusBegin.pipe(takeUntil(this.destroyed$)).subscribe((r) => { + this.versusData = r.data; + + }); + + } + ngOnDestroy() { this.destroyed$.complete(); } @@ -32,4 +42,10 @@ export class QueueActionsComponent implements OnInit, OnDestroy { // this.gameQueue = null; }) } + + versusWon(playerId: number) { + this.apiService.completeVersus(playerId).subscribe(r => { + this.versusData = null; + }) + } } diff --git a/src/app/app.component.html b/src/app/app.component.html index ed3f1f6..518d5f2 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3a8d2c0..07d46db 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -10,18 +10,31 @@ import { ToastService } from "./toast.service"; import { VoiceService } from "./services/voice.service"; import { Subject } from "rxjs"; import { getAudioPath } from "./helper/tts.helper"; +import {animate, keyframes, style, transition, trigger} from "@angular/animations"; @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] + styleUrls: ['./app.component.scss'], + animations: [ + trigger( + 'enterAnimation', [ + transition(':enter', [ + style({transform: 'translateX(100%)', opacity: 0}), + animate('500ms', style({transform: 'translateX(0)', opacity: 1})) + ]), + transition(':leave', [ + style({transform: 'translateX(0)', opacity: 1}), + animate('2000ms', style({transform: 'translateX(100%)', opacity: 0})) + ]) + ] + )] }) export class AppComponent implements OnInit, OnDestroy { title = 'thanksgiving'; connection = io(WEBSOCK_URL, { transports: ['websocket']}); destroyed = new Subject(); - versusInProgress = false; - versusData: VersusBeginEvent; + versusData: VersusBeginEvent|null = null; audioSrc: string; constructor( @@ -70,12 +83,14 @@ export class AppComponent implements OnInit, OnDestroy { } private setupVersusHandler() { - console.log(this.routeSnapshot.snapshot.url); - this.eventService.versusBegin.pipe(takeUntil(this.destroyed)).subscribe(r => { - if(this.router.url.indexOf('admin') === -1) { - this.versusInProgress = true; - this.versusData = r.data; - } - }) - } + this.eventService.versusBegin.pipe(takeUntil(this.destroyed)).subscribe(r => { + if (this.router.url.indexOf('admin') === -1) { + this.versusData = r.data; + } + }) + this.eventService.versusEnd.pipe(takeUntil(this.destroyed)).subscribe((r) => { + console.log(r); + this.versusData = null; + }) + } } diff --git a/src/app/components/cards-history/cards-history.component.scss b/src/app/components/cards-history/cards-history.component.scss index ae0a97f..707c824 100644 --- a/src/app/components/cards-history/cards-history.component.scss +++ b/src/app/components/cards-history/cards-history.component.scss @@ -2,7 +2,7 @@ .cards-history { position: fixed; - z-index: 20000; + z-index: 1000; width: 100%; bottom: 0; max-height: 70px; diff --git a/src/app/components/participant-item/participant-item.component.html b/src/app/components/participant-item/participant-item.component.html index 105c9a3..eb252cd 100644 --- a/src/app/components/participant-item/participant-item.component.html +++ b/src/app/components/participant-item/participant-item.component.html @@ -3,7 +3,7 @@
- {{ participant.name }} + {{ participant?.name }}
diff --git a/src/app/components/participant-item/participant-item.component.ts b/src/app/components/participant-item/participant-item.component.ts index 1b671bc..6716f02 100644 --- a/src/app/components/participant-item/participant-item.component.ts +++ b/src/app/components/participant-item/participant-item.component.ts @@ -64,13 +64,18 @@ export class ParticipantItemComponent implements OnInit, OnDestroy, OnChanges { } getCards() { - this.apiService.getCards(this.participant.telegramId).subscribe((r) => { - this.cards = r; - }) + if(this.participant) { + this.apiService.getCards(this.participant.telegramId).subscribe((r) => { + this.cards = r; + }) + } } getImageUrl() { - return `${API_URL}/guests/photo/${this.participant.telegramId}?$t=${this.imgTimestamp}`; + if(this.participant) { + return `${API_URL}/guests/photo/${this.participant.telegramId}?$t=${this.imgTimestamp}`; + } + return null; } } diff --git a/src/app/components/question/question.component.ts b/src/app/components/question/question.component.ts index 6ec0a0a..398121e 100644 --- a/src/app/components/question/question.component.ts +++ b/src/app/components/question/question.component.ts @@ -15,6 +15,7 @@ export class QuestionComponent implements OnInit, OnDestroy { @Input() question: Question; destroyed$ = new Subject(); private questionSubscription: Subscription; + countdownInterval:ReturnType|null= null; countdown = 0; readonly countDownTimer =20; @@ -31,20 +32,33 @@ export class QuestionComponent implements OnInit, OnDestroy { this.countdown = -1; }); - this.countdown = this.countDownTimer; - setInterval(() => { - console.log(`question countdown`); - if(this.countdown === 0) { - this.continueGame(); - } - this.countdown--; - }, 1000) + this.startCountdown(); this.questionSubscription = this.eventService.questionChangedEvent.subscribe(() =>{ this.getQuestion(); this.countdown = 20; }); + this.setUpVersusHandler(); + } + startCountdown() { + this.countdown = this.countDownTimer; + this.countdownInterval = setInterval(() => { + if(this.countdown === 0) { + this.continueGame(); + } + this.countdown--; + }, 1000) + } + setUpVersusHandler() { + this.eventService.versusBegin.pipe(takeUntil(this.destroyed$)).subscribe((r) => { + if(this.countdownInterval) { + clearInterval(this.countdownInterval); + } + }); + this.eventService.versusBegin.pipe(takeUntil(this.destroyed$)).subscribe((r) => { + this.startCountdown(); + }) } continueGame() { diff --git a/src/app/components/versus/versus.component.html b/src/app/components/versus/versus.component.html index 4106edb..65e881b 100644 --- a/src/app/components/versus/versus.component.html +++ b/src/app/components/versus/versus.component.html @@ -1,14 +1,24 @@
-
-
+
-
- +
+
+
+
+
+

{{ versusData.text}}

+
+
+
{{ versusData.description }}
+
+
+ +
\ No newline at end of file diff --git a/src/app/components/versus/versus.component.scss b/src/app/components/versus/versus.component.scss index 0511793..b356e26 100644 --- a/src/app/components/versus/versus.component.scss +++ b/src/app/components/versus/versus.component.scss @@ -25,6 +25,26 @@ } } +@keyframes slideInUp { + 0% { + bottom: -100px; + } + 100% { + bottom: 25%; + } +} + +@keyframes opacityIn { + 0% { + opacity: 0; + } + 100% { + opacity: 0.84; + } +} + + + .versus { background-color: $thg_brown; @@ -66,7 +86,7 @@ color: white; font-size: 2rem; font-weight: bold; - animation: slideRight 1s ease forwards; + animation: slideRight 2s ease forwards; } /* Right player area */ @@ -82,5 +102,15 @@ color: white; font-size: 2rem; font-weight: bold; - animation: slideLeft 1s ease forwards; + animation: slideLeft 2s ease forwards; } + +.task { + position: absolute; + bottom: 0; + height: 10%; + width: 50%; + background-color: white; + opacity: 0.84; + animation: slideInUp 3s ease forwards, opacityIn 1500ms linear; +} \ No newline at end of file diff --git a/src/app/components/versus/versus.component.ts b/src/app/components/versus/versus.component.ts index 63805f1..b666673 100644 --- a/src/app/components/versus/versus.component.ts +++ b/src/app/components/versus/versus.component.ts @@ -1,8 +1,9 @@ import {Component, Input, OnDestroy, OnInit} from '@angular/core'; import {ApiService} from "../../services/api.service"; -import {Subject} from "rxjs"; -import {takeUntil} from "rxjs/operators"; +import {combineLatest, Subject} from "rxjs"; +import {combineAll, takeUntil} from "rxjs/operators"; import {Participant} from "../../../types/participant"; +import {VersusItem} from "../../../types/versus-item"; @Component({ selector: 'app-versus', @@ -15,18 +16,35 @@ export class VersusComponent implements OnInit, OnDestroy{ player1data: Participant; player2data: Participant; destroyed$ = new Subject(); + playersLoaded = false; + versusData: VersusItem | null = null; constructor(private apiService: ApiService) { } ngOnInit() { this.loadPlayersData(); + this.loadTask() } ngOnDestroy() { this.destroyed$.complete(); } loadPlayersData() { - this.apiService.getParticipant(this.player1).pipe(takeUntil(this.destroyed$)).subscribe((r) => this.player1data = r); - this.apiService.getParticipant(this.player2).pipe(takeUntil(this.destroyed$)).subscribe((r) => this.player2data = r); + const player1Data$ = this.apiService.getParticipant(this.player1); + const player2Data$ = this.apiService.getParticipant(this.player2); + combineLatest([player1Data$,player2Data$]).pipe(takeUntil(this.destroyed$)).subscribe(([d1,d2]) => { + this.player1data = d1; + this.player2data = d2; + this.playersLoaded = true; + }) + } + + private loadTask() { + setTimeout(() => { + this.apiService.getVersus().pipe(takeUntil(this.destroyed$)).subscribe((r) => { + this.versusData = r; + }) + }, 1500); + } } diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts index 861e621..dff07a7 100644 --- a/src/app/services/api.service.ts +++ b/src/app/services/api.service.ts @@ -10,12 +10,30 @@ import { GameState } from "./gameState"; import { PenaltyDto } from "../../types/penalty.dto"; import { PrizeDto } from "../../types/prize.dto"; import {QuestionresultsDto} from "../../types/questionresults.dto"; +import {map} from "rxjs/operators"; +import {VersusItem} from "../../types/versus-item"; export interface FeatureFlagStateDto { name: string; state: boolean; } +export interface StateInformationDto { + key: string; + value: { key: string; value: T }; +} + +export interface StateInformationVersusDto { + action: any; + player1: number; + player2: number; +} + +export interface ConfigRecordDto { + key: string; + value: string; +} + @Injectable({ providedIn: 'root' }) @@ -107,4 +125,18 @@ export class ApiService { setFeatureFlagState(feature: string, state: boolean) { return this.httpClient.post(`${API_URL}/featureflag`, { name: feature, state: state }); } + + getStateDetails() { + return this.httpClient.get(`${API_URL}/game/state-details`); + } + + getVersus() { + return this.httpClient.get(`${API_URL}/versus`); + } + + completeVersus(winner: number) { + return this.httpClient.post(`${API_URL}/versus/complete`, { + winner: winner + }); + } } diff --git a/src/app/services/event.service.ts b/src/app/services/event.service.ts index 0b9ee15..c963857 100644 --- a/src/app/services/event.service.ts +++ b/src/app/services/event.service.ts @@ -33,6 +33,7 @@ export class EventService { public userPropertyChanged = new EventEmitter>(); public featureFlagChanged = new EventEmitter>() public versusBegin = new EventEmitter>(); + public versusEnd = new EventEmitter> constructor() { } public emit(event: ServerEvent) { @@ -89,6 +90,9 @@ export class EventService { case "begin_versus": this.versusBegin.emit(event as ServerEvent); break; + case "end_versus": + this.versusEnd.emit(event as ServerEvent<{winner: number}>); + break; } } } diff --git a/src/app/services/testing-api.service.ts b/src/app/services/testing-api.service.ts index 26321e2..76a15e5 100644 --- a/src/app/services/testing-api.service.ts +++ b/src/app/services/testing-api.service.ts @@ -10,6 +10,18 @@ export class TestingApiService { constructor(private httpClient: HttpClient) { } public simulateVersus() { - return this.httpClient.post(`${API_URL}/game/simulate-versus`, {}); + return this.httpClient.post(`${API_URL}/versus/simulate-versus`, {}); + } + + resetAllVersusTasksAsIncompleted() { + return this.httpClient.post(`${API_URL}/versus/reset-all`, {}); + } + + resetAllPlayersScore() { + return this.httpClient.post(`${API_URL}/guests/reset-score`, {}); + } + + clearGameQueue() { + return this.httpClient.post(`${API_URL}/game/clear-queue`, {}); } } diff --git a/src/types/server-event.ts b/src/types/server-event.ts index 8321e71..d752923 100644 --- a/src/types/server-event.ts +++ b/src/types/server-event.ts @@ -54,6 +54,8 @@ export interface EventScoreChanged { export interface VersusBeginEvent { player1: number; player2: number; + player1name: string; + player2name: string; } export interface EventGameQueue { @@ -94,5 +96,6 @@ export interface ServerEvent { | 'user_property_changed' | 'feature_flag_changed' | 'begin_versus' + | 'end_versus' data: T } diff --git a/src/types/versus-item.ts b/src/types/versus-item.ts new file mode 100644 index 0000000..a5e3dfd --- /dev/null +++ b/src/types/versus-item.ts @@ -0,0 +1,6 @@ +export interface VersusItem { + text: string; + name: string; + completed: boolean; + description: string; +} \ No newline at end of file