diff --git a/package-lock.json b/package-lock.json index e858c06..47a88fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "i": "^0.3.7", "jquery": "^3.6.0", "npm": "^10.2.3", - "rxjs": "~6.6.0", + "rxjs": "^7.8.1", "socket.io-client": "^4.2.0", "tslib": "^2.3.0", "zone.js": "~0.13.3" @@ -71,15 +71,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/architect/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/build-angular": { "version": "16.2.9", "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.9.tgz", @@ -241,15 +232,6 @@ "vite": "^3.0.0 || ^4.0.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/vite": { "version": "4.4.7", "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", @@ -324,15 +306,6 @@ "webpack-dev-server": "^4.0.0" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/core": { "version": "16.2.9", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.9.tgz", @@ -360,15 +333,6 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/schematics": { "version": "16.2.9", "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.9.tgz", @@ -387,15 +351,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular/animations": { "version": "16.2.12", "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.12.tgz", @@ -7331,15 +7286,6 @@ "node": ">=8" } }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13424,21 +13370,14 @@ } }, "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "tslib": "^2.1.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -15627,17 +15566,6 @@ "requires": { "@angular-devkit/core": "16.2.9", "rxjs": "7.8.1" - }, - "dependencies": { - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - } } }, "@angular-devkit/build-angular": { @@ -15738,15 +15666,6 @@ "dev": true, "requires": {} }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, "vite": { "version": "4.4.7", "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", @@ -15769,17 +15688,6 @@ "requires": { "@angular-devkit/architect": "0.1602.9", "rxjs": "7.8.1" - }, - "dependencies": { - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - } } }, "@angular-devkit/core": { @@ -15794,17 +15702,6 @@ "picomatch": "2.3.1", "rxjs": "7.8.1", "source-map": "0.7.4" - }, - "dependencies": { - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - } } }, "@angular-devkit/schematics": { @@ -15818,17 +15715,6 @@ "magic-string": "0.30.1", "ora": "5.4.1", "rxjs": "7.8.1" - }, - "dependencies": { - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - } } }, "@angular/animations": { @@ -20871,15 +20757,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -25090,18 +24967,11 @@ } }, "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } + "tslib": "^2.1.0" } }, "safe-buffer": { diff --git a/package.json b/package.json index afafcf0..808906e 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "i": "^0.3.7", "jquery": "^3.6.0", "npm": "^10.2.3", - "rxjs": "~6.6.0", + "rxjs": "^7.8.1", "socket.io-client": "^4.2.0", "tslib": "^2.3.0", "zone.js": "~0.13.3" diff --git a/src/app/admin/admin-testing/admin-testing.component.html b/src/app/admin/admin-testing/admin-testing.component.html index 98182b6..9b9c020 100644 --- a/src/app/admin/admin-testing/admin-testing.component.html +++ b/src/app/admin/admin-testing/admin-testing.component.html @@ -4,11 +4,12 @@

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 aac42ab..d3f56fa 100644 --- a/src/app/admin/admin-testing/admin-testing.component.ts +++ b/src/app/admin/admin-testing/admin-testing.component.ts @@ -49,4 +49,8 @@ export class AdminTestingComponent implements OnInit, OnDestroy { clearGameQueue() { this.testingApiService.clearGameQueue().pipe(takeUntil(this.destroyed$)).subscribe((r => console.log(r))); } + + simulateEndGamePoints() { + this.testingApiService.simulateEndGamePoints().pipe(takeUntil(this.destroyed$)).subscribe(r => console.log(r)); + } } diff --git a/src/app/admin/components/main-actions/main-actions.component.ts b/src/app/admin/components/main-actions/main-actions.component.ts index f5c5c3c..6925519 100644 --- a/src/app/admin/components/main-actions/main-actions.component.ts +++ b/src/app/admin/components/main-actions/main-actions.component.ts @@ -25,6 +25,7 @@ export class MainActionsComponent implements OnInit { { title: 'Registration', name: 'register'}, { title: 'Onboarding', name: 'onboarding' }, { title: 'Start quiz', name: 'quiz' }, + { title: 'Endgame Points', name: 'endgamepoints' }, { title: 'End', name: 'finish' }, ]; diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 02f5a9f..e6ac10a 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -6,6 +6,7 @@ import { RegisterComponent } from "./views/register/register.component"; import { OnboardingComponent } from "./views/onboarding/onboarding.component"; import { InitialComponent } from './views/initial/initial.component'; import { FinishComponent } from './views/finish/finish.component'; +import {EndgamepointsComponent} from "./views/endgamepoints/endgamepoints.component"; const routes: Routes = [ { path: 'quiz', component: QuizComponent }, @@ -14,6 +15,7 @@ const routes: Routes = [ { path: 'onboarding', component: OnboardingComponent }, { path: 'initial', component: InitialComponent }, { path: 'finish', component: FinishComponent }, + { path: 'endgamepoints', component: EndgamepointsComponent }, { path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)}, ]; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f6ef8ff..abee8ec 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -28,6 +28,7 @@ import { FinishComponent } from './views/finish/finish.component'; import { InitialComponent } from './views/initial/initial.component'; import { SkrepaComponent } from './components/skrepa/skrepa.component'; import { VersusComponent } from './components/versus/versus.component'; +import { EndgamepointsComponent } from './views/endgamepoints/endgamepoints.component'; @NgModule({ declarations: [ @@ -52,6 +53,7 @@ import { VersusComponent } from './components/versus/versus.component'; InitialComponent, SkrepaComponent, VersusComponent, + EndgamepointsComponent, ], imports: [ BrowserModule, diff --git a/src/app/components/game-queue/game-queue.component.html b/src/app/components/game-queue/game-queue.component.html index cd5d043..3413d44 100644 --- a/src/app/components/game-queue/game-queue.component.html +++ b/src/app/components/game-queue/game-queue.component.html @@ -31,18 +31,24 @@
-
-

Результаты

-

Ответили правильно

-
- +
+

Ответили правильно

-

Не смогли

-
- +
+
+ +
+
+
+

Не смогли

+
+
+
+ +
diff --git a/src/app/components/participant-item/participant-item.component.html b/src/app/components/participant-item/participant-item.component.html index eb252cd..76ca1ac 100644 --- a/src/app/components/participant-item/participant-item.component.html +++ b/src/app/components/participant-item/participant-item.component.html @@ -1,9 +1,9 @@
-
+
- {{ participant?.name }} + {{ participant.name }}
diff --git a/src/app/components/question/question.component.ts b/src/app/components/question/question.component.ts index 398121e..a6e885c 100644 --- a/src/app/components/question/question.component.ts +++ b/src/app/components/question/question.component.ts @@ -17,7 +17,7 @@ export class QuestionComponent implements OnInit, OnDestroy { private questionSubscription: Subscription; countdownInterval:ReturnType|null= null; countdown = 0; - readonly countDownTimer =20; + readonly countDownTimer = 20; constructor(private apiService:ApiService, private eventService: EventService, private voiceService: VoiceService) { } diff --git a/src/app/components/versus/versus.component.html b/src/app/components/versus/versus.component.html index 65e881b..9755b3d 100644 --- a/src/app/components/versus/versus.component.html +++ b/src/app/components/versus/versus.component.html @@ -21,4 +21,5 @@
-
\ No newline at end of file +
+ \ No newline at end of file diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts index b712ff3..4875104 100644 --- a/src/app/services/api.service.ts +++ b/src/app/services/api.service.ts @@ -13,7 +13,7 @@ import {QuestionresultsDto} from "../../types/questionresults.dto"; import {map} from "rxjs/operators"; import {VersusItem} from "../../types/versus-item"; -export interface FeatureFlagStateDto { +export class FeatureFlagStateDto { name: string; state: boolean; } @@ -34,6 +34,24 @@ export interface ConfigRecordDto { value: string; } +export interface EndgameResultsDto { + maxInvalidAnswers: { + id: number; + count: number; + name: string; + }, + maxRewards: { + id: number; + count: number; + name: string; + }, + maxPenalties: { + id: number; + count: number; + name: string; + } +} + @Injectable({ providedIn: 'root' }) @@ -115,7 +133,14 @@ export class ApiService { } getQuestionResults() { - return this.httpClient.get(`${API_URL}/quiz/question-results`) + return this.httpClient.get(`${API_URL}/quiz/question-results`).pipe(map((data) => + data.map((item) => { + return { + ...item, + time: new Date(item.time) + } + }) + )); } getFeatureFlagState(feature: string) { @@ -140,4 +165,8 @@ export class ApiService { loser: loser }); } + + getEndgameResults() { + return this.httpClient.get(`${API_URL}/quiz/endgame-results`) + } } diff --git a/src/app/services/testing-api.service.ts b/src/app/services/testing-api.service.ts index 76a15e5..c723891 100644 --- a/src/app/services/testing-api.service.ts +++ b/src/app/services/testing-api.service.ts @@ -24,4 +24,8 @@ export class TestingApiService { clearGameQueue() { return this.httpClient.post(`${API_URL}/game/clear-queue`, {}); } + + simulateEndGamePoints() { + return this.httpClient.post(`${API_URL}/quiz/calculate-endgame-extrapoints`, {}) + } } diff --git a/src/app/services/voice.service.ts b/src/app/services/voice.service.ts index 3341ca6..956dca9 100644 --- a/src/app/services/voice.service.ts +++ b/src/app/services/voice.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http"; import { API_URL } from "../../app.constants"; -import { Subject } from "rxjs"; +import {Observable, of, Subject} from "rxjs"; @Injectable({ providedIn: 'root' @@ -17,6 +17,19 @@ export class VoiceService { this.voiceSubject.next(url); } + playAudio$(url: string) { + this.voiceSubject.next(url); + return new Observable((observer) => { + const subscription = this.audioEndedSubject.subscribe({ + next: () => { + observer.next(null); + observer.complete(); + } + }); + return () => subscription.unsubscribe(); + }) + } + getAudioUrl(text: string,voice: number = 1) { return `${API_URL}/voice/tts?voice=${voice}&text=${text}` } diff --git a/src/app/shared/featureflags.ts b/src/app/shared/featureflags.ts index c78fa83..96b765f 100644 --- a/src/app/shared/featureflags.ts +++ b/src/app/shared/featureflags.ts @@ -4,5 +4,6 @@ export class FeatureFlagList { "DontMarkQuestionsAsCompleted", "DisableVoice", "ProdMode", + "EndgamePointsUseCssAnimation", ]; } \ No newline at end of file diff --git a/src/app/shared/sharedmethods.ts b/src/app/shared/sharedmethods.ts new file mode 100644 index 0000000..37be26b --- /dev/null +++ b/src/app/shared/sharedmethods.ts @@ -0,0 +1,5 @@ +export class SharedMethods { + static sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } +} \ No newline at end of file diff --git a/src/app/views/endgamepoints/endgamepoints.component.html b/src/app/views/endgamepoints/endgamepoints.component.html new file mode 100644 index 0000000..edae027 --- /dev/null +++ b/src/app/views/endgamepoints/endgamepoints.component.html @@ -0,0 +1,83 @@ + + +
+
+
+
+
+
+
+ Время наградить особо отличившихся! +
+
+ За тупость +2 + +
+ +
+
+
+
+ За тяжелую судьбу +2 + +
+ +
+
+
+
+ За полный успех -2 + +
+ +
+
+
+
+
+
+ + + +
+ + +
+
+ Время наградить особо отличившихся! +
+
+ За тупость +2 + +
+ +
+
+
+
+ За тяжелую судьбу +2 + +
+ +
+
+
+
+ За полный успех −2 + +
+ +
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/app/views/endgamepoints/endgamepoints.component.scss b/src/app/views/endgamepoints/endgamepoints.component.scss new file mode 100644 index 0000000..102b8a9 --- /dev/null +++ b/src/app/views/endgamepoints/endgamepoints.component.scss @@ -0,0 +1,202 @@ +$shooting-time: 3000ms; + +@keyframes slideInUp { + 0% { + transform: translateY(3000%); + } + 100% { + transform: translateY(0); + } +} + +@keyframes opacityIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +@keyframes fontSizeTitle { + 0% { + font-size: 1em; + } + 100% { + font-size: 2em; + } + +} + +.background-video { + position: relative; + height: 100vh; /* Full viewport height */ + width: 100%; /* Full width */ + overflow: hidden; +} + +.dark-container { + position:relative; + height: 100vh; + width: 100%; + overflow: hidden; + background-color: #000220; +} +.background-video video { + position: absolute; + width: 100%; + height: 100vh; + object-fit: cover; /* Ensures the video covers the container */ + z-index: -1; /* Places the video behind the content */ +} + +.content { + color: white; + position: absolute; + top: 50px; + left: 20px; + right: 20px; + z-index: 100; + text-align: center; + font-family: Arial, sans-serif; + padding: 20px; +} + +.text-announce { + margin-top: 15%; + font-size: 2em; + font-weight: bold; + animation: slideInUp 1s forwards, fontSizeTitle 1s forwards, opacityIn 1s forwards; +} + +.shooting_star { + position: absolute; + left: 10%; + top: 10%; + // width: 100px; + height: 2px; + background: linear-gradient(-45deg, rgb(243, 227, 6), rgba(0, 0, 255, 0)); + border-radius: 999px; + filter: drop-shadow(0 0 6px rgb(250, 253, 148)); + animation: + tail $shooting-time ease-in-out infinite, + shooting $shooting-time ease-in-out infinite; + + &::before { + content: ''; + position: absolute; + top: calc(50% - 1px); + right: 0; + // width: 30px; + height: 2px; + background: linear-gradient(-45deg, rgba(0, 0, 255, 0), rgba(95, 145, 255, 1), rgba(0, 0, 255, 0)); + transform: translateX(50%) rotateZ(45deg); + border-radius: 100%; + animation: shining $shooting-time ease-in-out infinite; + } + + &::after { + // CodePen Error + // @extend .shooting_star::before; + + content: ''; + position: absolute; + top: calc(50% - 1px); + right: 0; + // width: 30px; + height: 2px; + background: linear-gradient(-45deg, rgba(0, 0, 255, 0), rgba(95, 145, 255, 1), rgba(0, 0, 255, 0)); + transform: translateX(50%) rotateZ(45deg); + border-radius: 100%; + animation: shining $shooting-time ease-in-out infinite; + transform: translateX(50%) rotateZ(-45deg); + } + + @for $i from 1 through 20 { + &:nth-child(#{$i}) { + $delay: random(9999) + 0ms; + top: calc(50% - #{random(2000) - 200px}); + left: calc(50% - #{random(300) + 0px}); + animation-delay: $delay; + opacity: random(50) / 100 + 0.5; + + &::before, + &::after { + animation-delay: $delay; + } + } + } +} + +@keyframes tail { + 0% { + width: 0; + } + + 30% { + width: 100px; + } + + 100% { + width: 0; + } +} + +@keyframes shining { + 0% { + width: 0; + } + + 50% { + width: 30px; + } + + 100% { + width: 0; + } +} + +@keyframes shooting { + 0% { + transform: translateX(0); + } + + 100% { + transform: translateX(300px); + } +} + +@keyframes sky { + 0% { + transform: rotate(45deg); + } + + 100% { + transform: rotate(45 + 360deg); + } +} + + +@keyframes glow { + 0% { + text-shadow: 0 0 2px #f5f5f5, 0 0 10px #f5f5f5, 0 0 20px #ffc14d, 0 0 30px #fff1e0, 0 0 40px #ff4da6, 0 0 50px #ff4da6, 0 0 75px #ff4da6; + } + 100% { + text-shadow: 0 0 20px #ffffff, 0 0 20px #ff0080, 0 0 30px #ff0080, 0 0 40px #ff0080, 0 0 50px #ff0080, 0 0 75px #ff0080, 0 0 100px #ff0080; + } +} +.night { + position: relative; + width: 100%; + height: 100%; + transform: rotateZ(45deg); + animation: sky 100000ms linear infinite; +} + +.score { + background-color: #f8b12c; + border-radius: 50%; + padding: 10px; + text-shadow: 0 0 5px #f5f5f5, 0 0 10px #f5f5f5, 0 0 20px #ff4da6, 0 0 30px #ff4da6, 0 0 40px #ff4da6, 0 0 50px #ff4da6, 0 0 75px #ff4da6; + animation: glow 2s infinite alternate; +} \ No newline at end of file diff --git a/src/app/views/endgamepoints/endgamepoints.component.spec.ts b/src/app/views/endgamepoints/endgamepoints.component.spec.ts new file mode 100644 index 0000000..f4f8e6e --- /dev/null +++ b/src/app/views/endgamepoints/endgamepoints.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EndgamepointsComponent } from './endgamepoints.component'; + +describe('EndgamepointsComponent', () => { + let component: EndgamepointsComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [EndgamepointsComponent] + }); + fixture = TestBed.createComponent(EndgamepointsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/views/endgamepoints/endgamepoints.component.ts b/src/app/views/endgamepoints/endgamepoints.component.ts new file mode 100644 index 0000000..7f7806f --- /dev/null +++ b/src/app/views/endgamepoints/endgamepoints.component.ts @@ -0,0 +1,99 @@ +import {Component, OnInit} from '@angular/core'; +import {ApiService, EndgameResultsDto, FeatureFlagStateDto} from "../../services/api.service"; +import { + of, + Subject, + lastValueFrom, + firstValueFrom, + mergeWith, + combineLatestAll, + combineLatest, + mergeMap, + forkJoin, merge +} from "rxjs"; +import { takeUntil} from "rxjs/operators"; +import {VoiceService} from "../../services/voice.service"; +import {animate, keyframes, style, transition, trigger} from "@angular/animations"; +import {Participant} from "../../../types/participant"; +import {SharedMethods} from "../../shared/sharedmethods"; + +@Component({ + selector: 'app-endgamepoints', + templateUrl: './endgamepoints.component.html', + styleUrls: ['./endgamepoints.component.scss'], + animations: [ + trigger('slideOut', [ + transition(':leave', [ + animate( + '1300ms ease-in', + style({ transform: 'translateY(-100%)', opacity: 0 }) + ), + ]), + ])] +}) +export class EndgamepointsComponent implements OnInit{ + loaded = false; + useCssAnimation = false; + destroyed$ = new Subject(); + showInitialText = true; + showMaxAmountOfInvalidAnswers = false; + endgameResults: EndgameResultsDto | null; + participants: Participant[] = []; + maxAmountOfPenalties = false; + maxAmountOfRewards = false; + constructor(private apiService: ApiService, private voiceService: VoiceService) { + } + + + ngOnInit(): void { + const ff$ = this.apiService.getFeatureFlagState("EndgamePointsUseCssAnimation"); + // @ts-ignore + const results$ = this.apiService.getEndgameResults(); + combineLatest([results$, ff$]) + .pipe(takeUntil(this.destroyed$)) + .subscribe(([results,ff]) => { + const userData$ = []; + userData$.push( + this.apiService.getParticipant(results.maxInvalidAnswers.id), + this.apiService.getParticipant(results.maxPenalties.id), + this.apiService.getParticipant(results.maxRewards.id), + ); + merge(...userData$).pipe(takeUntil(this.destroyed$)).subscribe((r) => this.participants.push(r)); + this.useCssAnimation = ff.state; + this.endgameResults = results; + this.loaded = true; + this.playScene().then(() => {}); + console.log(results); + }); + } + + + async playScene() { + await firstValueFrom(this.voiceService.playAudio$(this.voiceService.getAudioUrl("Время наградить особо отличившихся!"))); + this.showInitialText = false; + await SharedMethods.sleep(1000); + this.showMaxAmountOfInvalidAnswers = true; + await SharedMethods.sleep(500); + await firstValueFrom(this.voiceService.playAudio$(this.voiceService.getAudioUrl(` За максимальное количество неверных ответов, плюс два очка получает ${this.endgameResults?.maxInvalidAnswers.name}`))); + this.showMaxAmountOfInvalidAnswers = false; + await SharedMethods.sleep(3000); + this.maxAmountOfPenalties = true; + await firstValueFrom(this.voiceService.playAudio$(this.voiceService.getAudioUrl(`За самое большое количество полученных наказаний плюс два очка получил ${this.endgameResults?.maxPenalties.name}`))); + await SharedMethods.sleep(3000) + this.maxAmountOfPenalties = false; + await firstValueFrom(this.voiceService.playAudio$(this.voiceService.getAudioUrl(`И чтобы сделать игру более справедливой, есть последняя номинация`))); + this.maxAmountOfRewards = true; + await firstValueFrom(this.voiceService.playAudio$(this.voiceService.getAudioUrl(`${this.endgameResults?.maxRewards.name} лишается двух очков за свой невероятный ум`))); + await SharedMethods.sleep(15000); + + } + + + getParticipant(id: number | undefined): Participant|null { + if(id) { + const p = this.participants.find(x => x.telegramId === id); + return p !== undefined ? p : null; + } + return null; + } +} diff --git a/src/app/views/onboarding/onboarding.component.ts b/src/app/views/onboarding/onboarding.component.ts index 53d5fc8..1c397d8 100644 --- a/src/app/views/onboarding/onboarding.component.ts +++ b/src/app/views/onboarding/onboarding.component.ts @@ -118,7 +118,6 @@ export class OnboardingComponent implements OnInit, OnDestroy { } shakeCard(card: ElementRef) { - console.log(`shake card`); this.renderer.addClass(card.nativeElement, 'shake'); this.renderer.addClass(card.nativeElement, 'zoom-in'); if(!this.allRulesAnnounced) { @@ -142,7 +141,6 @@ export class OnboardingComponent implements OnInit, OnDestroy { } stopShaking(card: ElementRef) { - console.log(`stop shacking`); this.renderer.removeClass(card.nativeElement, 'shake'); } diff --git a/src/assets/endgame/1469-147538044.mp4 b/src/assets/endgame/1469-147538044.mp4 new file mode 100644 index 0000000..771f3d3 Binary files /dev/null and b/src/assets/endgame/1469-147538044.mp4 differ diff --git a/src/assets/endgame/48569-454825064.mp4 b/src/assets/endgame/48569-454825064.mp4 new file mode 100644 index 0000000..2199982 Binary files /dev/null and b/src/assets/endgame/48569-454825064.mp4 differ diff --git a/src/assets/endgame/energetic-bgm-242515.mp3 b/src/assets/endgame/energetic-bgm-242515.mp3 new file mode 100644 index 0000000..c7308e9 Binary files /dev/null and b/src/assets/endgame/energetic-bgm-242515.mp3 differ diff --git a/src/assets/versus/cinematical-epic-loop-190906.mp3 b/src/assets/versus/cinematical-epic-loop-190906.mp3 new file mode 100644 index 0000000..0ae2c1b Binary files /dev/null and b/src/assets/versus/cinematical-epic-loop-190906.mp3 differ