-
-
+
+
+
+ (onButtonClick)="this.router.navigateByUrl(PathsEnum.HOME)">
diff --git a/src/app/wrong-answer-window/wrong-answer-window.component.ts b/src/app/wrong-answer-window/wrong-answer-window.component.ts
index 0f008d1..e29e542 100644
--- a/src/app/wrong-answer-window/wrong-answer-window.component.ts
+++ b/src/app/wrong-answer-window/wrong-answer-window.component.ts
@@ -2,9 +2,10 @@ import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router";
import {PathsEnum} from "../../model/enums/PathsEnum";
import {AppStorageService} from "../../service/app-storage.service";
-import {QuestionResultTemplateParams, TemplateEnum} from "../../model/Template";
+import {QuestionResultTemplateParams, QuestionResultTrifectaTemplateParams} from "../../model/Template";
import {EncryptionService} from "../../service/encryption.service";
import {TemplateService} from "../../service/template.service";
+import {GameMode} from "../../model/enums/GameModesEnum";
@Component({
selector: 'app-wrong-answer-window',
@@ -13,14 +14,15 @@ import {TemplateService} from "../../service/template.service";
})
export class WrongAnswerWindowComponent implements OnInit {
- public correctAnswer: string | null = '';
+ public correctAnswers: string[] = [];
public clipboardText: string = '';
public displayClipboardMessage: boolean = false;
+ public hoursToPlayAgain: number = 0;
private wrongAnswerSound: HTMLAudioElement = new Audio('assets/sounds/critical_stop.wav');
constructor(
- private readonly router: Router,
+ protected readonly router: Router,
private readonly route: ActivatedRoute,
private readonly encryptionService: EncryptionService,
private readonly templateService: TemplateService,
@@ -32,7 +34,7 @@ export class WrongAnswerWindowComponent implements OnInit {
await this.retrieveRouteParams();
if (!this.appStorageService.canQuizBeAnswered()) {
- await this.returnHome();
+ await this.router.navigateByUrl(PathsEnum.HOME);
return;
}
@@ -40,10 +42,6 @@ export class WrongAnswerWindowComponent implements OnInit {
this.saveCurrentScore();
}
- public async returnHome(): Promise {
- await this.router.navigateByUrl(PathsEnum.HOME);
- }
-
public async showClipboardMessage(): Promise {
this.displayClipboardMessage = true;
@@ -53,16 +51,22 @@ export class WrongAnswerWindowComponent implements OnInit {
}
private saveCurrentScore() {
- this.appStorageService.saveAnswer(false);
+ this.appStorageService.saveAnswer(false, undefined, this.hoursToPlayAgain);
}
private async retrieveRouteParams(): Promise {
+ const routeGameModeTitle: string = this.route.snapshot.paramMap.get('mode')!;
const encryptedQuestionResult: string = this.route.snapshot.paramMap.get('result')!;
const decryptedQuestionResult: string = this.encryptionService.decrypt(encryptedQuestionResult);
- const questionResult: QuestionResultTemplateParams = JSON.parse(decryptedQuestionResult);
+ const questionResult: QuestionResultTemplateParams | QuestionResultTrifectaTemplateParams = JSON.parse(decryptedQuestionResult);
+ const gameMode: GameMode = GameMode.getByTitle(routeGameModeTitle);
- this.correctAnswer = questionResult.rightAnswer;
- this.clipboardText = await this.templateService.render(TemplateEnum.QUESTION_RESULT, questionResult);
+ this.hoursToPlayAgain = gameMode === GameMode.TRIFECTA ? 24 : 3;
+
+ this.correctAnswers = 'questions' in questionResult ? questionResult.correctAnswers : [questionResult.rightAnswer];
+ this.clipboardText = await this.templateService.render(gameMode.templateEnum, questionResult);
}
+
+ protected readonly PathsEnum = PathsEnum;
}
diff --git a/src/assets/icons/20x20/contact.png b/src/assets/icons/20x20/contact.png
new file mode 100644
index 0000000..210166a
Binary files /dev/null and b/src/assets/icons/20x20/contact.png differ
diff --git a/src/assets/icons/20x20/send.png b/src/assets/icons/20x20/send.png
new file mode 100644
index 0000000..f493361
Binary files /dev/null and b/src/assets/icons/20x20/send.png differ
diff --git a/src/assets/icons/30x30/normal.png b/src/assets/icons/30x30/normal.png
new file mode 100644
index 0000000..88c28b2
Binary files /dev/null and b/src/assets/icons/30x30/normal.png differ
diff --git a/src/assets/icons/30x30/time-rush.png b/src/assets/icons/30x30/time-rush.png
new file mode 100644
index 0000000..85d31c1
Binary files /dev/null and b/src/assets/icons/30x30/time-rush.png differ
diff --git a/src/assets/icons/30x30/trifecta.png b/src/assets/icons/30x30/trifecta.png
new file mode 100644
index 0000000..d6d417c
Binary files /dev/null and b/src/assets/icons/30x30/trifecta.png differ
diff --git a/src/assets/icons/trifecta.png b/src/assets/icons/trifecta.png
new file mode 100644
index 0000000..b9173b2
Binary files /dev/null and b/src/assets/icons/trifecta.png differ
diff --git a/src/assets/templates/question_result_trifecta.mustache b/src/assets/templates/question_result_trifecta.mustache
new file mode 100644
index 0000000..bd9512f
--- /dev/null
+++ b/src/assets/templates/question_result_trifecta.mustache
@@ -0,0 +1,24 @@
+{{#questions}}
+👉 {{{.}}}
+{{/questions}}
+
+The answers were...
+
+{{#correctAnswers}}
+ 🟩 {{{.}}}
+{{/correctAnswers}}
+
+I picked...
+
+{{#selectedAnswers}}
+ {{{icon}}} {{{answer}}} - {{{points}}} points
+{{/selectedAnswers}}
+
+{{#questionPoints}}
+Earned {{questionPoints}} points in total!
+{{/questionPoints}}
+{{^questionPoints}}
+Need some luck next time...
+{{/questionPoints}}
+
+🤔 XPQuiz - xpquiz.github.io ❔
diff --git a/src/model/Template.ts b/src/model/Template.ts
index d5acb8d..9767f69 100644
--- a/src/model/Template.ts
+++ b/src/model/Template.ts
@@ -1,11 +1,14 @@
export enum TemplateEnum {
WEEK_SCORE = "/assets/templates/week_score.mustache",
- QUESTION_RESULT = "/assets/templates/question_result.mustache"
+ QUESTION_RESULT = "/assets/templates/question_result.mustache",
+ QUESTION_RESULT_TRIFECTA = "/assets/templates/question_result_trifecta.mustache"
}
export interface TemplateParams {
}
+// Score
+
export interface WeekScoreTemplateParams extends TemplateParams {
year: number,
week: number,
@@ -14,6 +17,8 @@ export interface WeekScoreTemplateParams extends TemplateParams {
totalScore: number
}
+// Normal question
+
export interface QuestionResultTemplateParams extends TemplateParams {
question: string,
questionPoints: number | null,
@@ -21,3 +26,18 @@ export interface QuestionResultTemplateParams extends TemplateParams {
rightAnswer: string,
wrongAnswers: string[]
}
+
+// Trifecta
+
+export interface QuestionResultTrifectaTemplateParams extends TemplateParams {
+ questions: string[],
+ correctAnswers: string[],
+ selectedAnswers: TrifectaSelectedAnswer[],
+ questionPoints: number
+}
+
+interface TrifectaSelectedAnswer {
+ icon: string,
+ answer: string,
+ points: string
+}
diff --git a/src/model/enums/GameModesEnum.ts b/src/model/enums/GameModesEnum.ts
new file mode 100644
index 0000000..119f148
--- /dev/null
+++ b/src/model/enums/GameModesEnum.ts
@@ -0,0 +1,27 @@
+import {TemplateEnum} from "../Template";
+
+export class GameMode {
+ static readonly NORMAL = new GameMode('normal', 'Standard mode. Answer a question, wait 3 hours to play again. Simple as that.', 1, TemplateEnum.QUESTION_RESULT);
+ static readonly TRIFECTA = new GameMode('trifecta', 'Three questions for three times the score! At the risk of waiting 24 hours to play again.', 3, TemplateEnum.QUESTION_RESULT_TRIFECTA);
+ static readonly TIME_RUSH = new GameMode('time-rush', 'Coming soon...', -1, TemplateEnum.QUESTION_RESULT);
+
+ private constructor(public readonly title: string,
+ public readonly description: string,
+ public readonly questions: number,
+ public readonly templateEnum: TemplateEnum) {
+ }
+
+ public static getByTitle(title: string): GameMode {
+ switch(title) {
+ case 'normal':
+ return GameMode.NORMAL;
+ case 'trifecta':
+ return GameMode.TRIFECTA;
+ case 'time-rush':
+ return GameMode.TIME_RUSH;
+ default:
+ return GameMode.NORMAL;
+ }
+ }
+}
+
diff --git a/src/model/enums/PathsEnum.ts b/src/model/enums/PathsEnum.ts
index b642f28..bef3279 100644
--- a/src/model/enums/PathsEnum.ts
+++ b/src/model/enums/PathsEnum.ts
@@ -2,7 +2,9 @@ export enum PathsEnum {
HOME = 'home',
SCORES = 'scores',
ABOUT = 'about',
- QUIZ = 'quiz',
+ GAME_MODE = 'game-mode',
+ QUIZ_NORMAL = 'quiz-normal',
+ QUIZ_TRIFECTA = 'quiz-trifecta',
CORRECT_ANSWER = 'correct-answer',
WRONG_ANSWER = 'wrong-answer',
}
diff --git a/src/model/questions/Question.ts b/src/model/questions/Question.ts
index b1e14e6..bfa8ea1 100644
--- a/src/model/questions/Question.ts
+++ b/src/model/questions/Question.ts
@@ -1,7 +1,10 @@
export interface Question {
question: string;
+ answers: string[];
correctAnswer: string;
- incorrectAnswers: string[];
- difficulty: 'easy' | 'medium' | 'hard';
+ points: number;
+ difficulty: DifficultyType;
isNiche: boolean;
}
+
+export type DifficultyType = 'easy' | 'medium' | 'hard';
diff --git a/src/service/app-storage.service.ts b/src/service/app-storage.service.ts
index 6622963..6e9989e 100644
--- a/src/service/app-storage.service.ts
+++ b/src/service/app-storage.service.ts
@@ -27,7 +27,7 @@ export class AppStorageService {
}
}
- public saveAnswer(correctAnswer: boolean, questionScore?: number | null): void {
+ public saveAnswer(correctAnswer: boolean, questionScore: number | undefined, hoursToPlayAgain: number): void {
const currentYear: number = moment().year();
const currentWeek: number = moment().isoWeek();
@@ -67,7 +67,9 @@ export class AppStorageService {
this.storageService.save(
{
...appStorage,
- lastQuizResponseDate: moment().toISOString(),
+ // using - 3 because i fucked up no the main window, should have been saving something
+ // like "nextQuizResponseDate" instead of this shit
+ lastQuizResponseDate: moment().add(hoursToPlayAgain - 3, 'hours').toISOString(),
yearScoreMap: yearScoreMap
}
);
@@ -88,22 +90,6 @@ export class AppStorageService {
return this.storageService.get()??this.createNewAppStorage();
}
- public clearWeek(currentYear: number, currentWeek: number) {
- const appStorage: AppStorage = this.storageService.get()!;
-
- appStorage.yearScoreMap.get(currentYear)?.delete(currentWeek);
-
- this.storageService.save(appStorage);
- }
-
- public clearYear(currentYear: number) {
- const appStorage: AppStorage = this.storageService.get()!;
-
- appStorage.yearScoreMap.delete(currentYear);
-
- this.storageService.save(appStorage);
- }
-
public retrieveScoreForYear(currentYear: number): Map {
const appStorage: AppStorage = this.retrieveAppStorage();
diff --git a/src/service/storage.service.ts b/src/service/storage.service.ts
index c7f7af3..e330aa5 100644
--- a/src/service/storage.service.ts
+++ b/src/service/storage.service.ts
@@ -1,5 +1,4 @@
import {Injectable} from '@angular/core';
-import {AES, enc} from 'crypto-js';
import {AppStorage} from "../model/AppStorage";
import {EncryptionService} from "./encryption.service";
diff --git a/src/service/trivia.service.ts b/src/service/trivia.service.ts
index baa1dca..4cd732a 100644
--- a/src/service/trivia.service.ts
+++ b/src/service/trivia.service.ts
@@ -3,7 +3,7 @@ import {HttpClient} from "@angular/common/http";
import {firstValueFrom} from "rxjs";
import {TheTriviaApiResponse} from "../model/questions/TheTriviaApiResponse";
import {OpenTriviaDBResponse} from "../model/questions/OpenTriviaDBResponse";
-import {Question} from "../model/questions/Question";
+import {DifficultyType, Question} from "../model/questions/Question";
import {
QuizAPIResponse,
QuizAPIResponseAnswers,
@@ -11,12 +11,18 @@ import {
} from "../model/questions/QuizAPIResponse";
import {environment} from "../environments/environment";
+
@Injectable({
providedIn: 'root'
})
export class TriviaService {
- private readonly questionLimit: number = 1;
+ private readonly difficultyPointsMap: Map = new Map([
+ ['easy', 1],
+ ['medium', 3],
+ ['hard', 5]
+ ]);
+
private readonly questionMethods: Function[] = [
this.getQuestionsTheTriviaApi,
this.getQuestionsOpenTriviaDB,
@@ -28,13 +34,13 @@ export class TriviaService {
) {
}
- public async fetchQuestion(): Promise {
- while(true) {
+ public async fetchQuestion(questionNumber: number): Promise {
+ while (true) {
const randomNumber: number = this.randomIntFromInterval(0, this.questionMethods.length - 1);
const randomQuestionMethod: Function = this.questionMethods[randomNumber];
- const questions: Question[] = await randomQuestionMethod.call(this);
+ const questions: Question[] = await randomQuestionMethod.call(this, questionNumber);
- if(questions.length !== 0) return questions;
+ if (questions.length !== 0) return questions;
}
}
@@ -42,44 +48,58 @@ export class TriviaService {
return Math.floor(Math.random() * (max - min + 1) + min)
}
- private async getQuestionsTheTriviaApi(): Promise {
- const url: string = `${environment.theTriviaApiUrl}?limit=${this.questionLimit}`;
-
+ private async getQuestionsTheTriviaApi(questionNumber: number): Promise {
+ const url: string = `${environment.theTriviaApiUrl}?limit=${questionNumber}`;
const response: TheTriviaApiResponse[] = await firstValueFrom(
this.httpClient.get(url)
);
return response.map(res => {
+ const answers = [res.correctAnswer, ...res.incorrectAnswers]
+ .map((value) => ({value, sort: Math.random()}))
+ .sort((a, b) => a.sort - b.sort)
+ .map(({value}) => value);
+
return {
question: res.question.text,
+ answers,
correctAnswer: res.correctAnswer,
- incorrectAnswers: res.incorrectAnswers,
+ points: this.difficultyPointsMap.get(res.difficulty)!,
difficulty: res.difficulty,
isNiche: res.isNiche,
}
});
}
- private async getQuestionsOpenTriviaDB(): Promise {
- const url: string = `${environment.openTriviaDBUrl}?amount=${this.questionLimit}&encode=base64`;
+ private async getQuestionsOpenTriviaDB(questionNumber: number): Promise {
+ const url: string = `${environment.openTriviaDBUrl}?amount=${questionNumber}&encode=base64`;
const response: OpenTriviaDBResponse = await firstValueFrom(
this.httpClient.get(url)
);
return response.results.map(res => {
+ const correctAnswer: string = atob(res.correct_answer)
+
+ const answers = [correctAnswer, ...res.incorrect_answers.map(r => atob(r))]
+ .map((value) => ({value, sort: Math.random()}))
+ .sort((a, b) => a.sort - b.sort)
+ .map(({value}) => value);
+ const difficulty: DifficultyType = atob(res.difficulty) as DifficultyType;
+
return {
question: atob(res.question),
- correctAnswer: atob(res.correct_answer),
- incorrectAnswers: res.incorrect_answers.map(r => atob(r)),
- difficulty: atob(res.difficulty) as 'easy' | 'medium' | 'hard',
+ correctAnswer,
+ answers,
+ points: this.difficultyPointsMap.get(difficulty)!,
+ difficulty,
isNiche: false,
}
});
}
- private async getQuestionsQuizAPI(): Promise {
- const url: string = `${environment.quizAPIUrl}?limit=${this.questionLimit}`;
+ private async getQuestionsQuizAPI(questionNumber: number): Promise {
+ const url: string = `${environment.quizAPIUrl}?limit=${questionNumber}`;
const response: QuizAPIResponse[] = await firstValueFrom(
this.httpClient.get(url, {
headers: {'X-Api-Key': environment.quizAPIKey}
@@ -87,6 +107,7 @@ export class TriviaService {
);
return response.map(res => {
+ const difficulty: DifficultyType = res.difficulty.toLowerCase() as DifficultyType;
let incorrectAnswers: string[] = [];
let correctAnswer: string | undefined = undefined;
@@ -107,11 +128,17 @@ export class TriviaService {
incorrectAnswers.push(answer);
}
+ const answers = [correctAnswer!, ...incorrectAnswers]
+ .map((value) => ({value, sort: Math.random()}))
+ .sort((a, b) => a.sort - b.sort)
+ .map(({value}) => value);
+
return {
question: res.question,
correctAnswer: correctAnswer!,
- incorrectAnswers: incorrectAnswers,
- difficulty: res.difficulty.toLowerCase() as 'easy' | 'medium' | 'hard',
+ answers,
+ points: this.difficultyPointsMap.get(difficulty)!,
+ difficulty,
isNiche: false
}
});