Commit 0d2074a6 authored by Christopher Fullarton's avatar Christopher Fullarton

Adds warning if the quiz data can be lost by navigation interactions

parent 4ad94e6c
Pipeline #33529 passed with stages
in 15 minutes and 56 seconds
export interface IHasTriggeredNavigation {
hasTriggeredNavigation: boolean;
}
......@@ -13,7 +13,7 @@ export class ServerUnavailableModalComponent implements OnDestroy {
}
public reloadPage(): void {
location.reload(true);
window.caches.keys().then(keys => Promise.all(keys.map(key => window.caches.delete(key)))).finally(() => location.reload(true));
}
public ngOnDestroy(): void {
......
......@@ -9,6 +9,7 @@ import { StorageKey } from '../../../lib/enums/enums';
import { MessageProtocol } from '../../../lib/enums/Message';
import { QuizState } from '../../../lib/enums/QuizState';
import { IMessage } from '../../../lib/interfaces/communication/IMessage';
import { IHasTriggeredNavigation } from '../../../lib/interfaces/IHasTriggeredNavigation';
import { ServerUnavailableModalComponent } from '../../../modals/server-unavailable-modal/server-unavailable-modal.component';
import { MemberApiService } from '../../../service/api/member/member-api.service';
import { AttendeeService } from '../../../service/attendee/attendee.service';
......@@ -22,9 +23,11 @@ import { QuizService } from '../../../service/quiz/quiz.service';
templateUrl: './confidence-rate.component.html',
styleUrls: ['./confidence-rate.component.scss'],
})
export class ConfidenceRateComponent implements OnInit, OnDestroy {
export class ConfidenceRateComponent implements OnInit, OnDestroy, IHasTriggeredNavigation {
public static TYPE = 'ConfidenceRateComponent';
public hasTriggeredNavigation: boolean;
private _confidenceValue = '100';
get confidenceValue(): string {
......@@ -60,11 +63,18 @@ export class ConfidenceRateComponent implements OnInit, OnDestroy {
}
if (this.quizService.quiz.state === QuizState.Inactive) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
return;
}
});
if (this.attendeeService.hasConfidenceValue()) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
return;
}
this.quizService.loadDataToPlay(sessionStorage.getItem(StorageKey.CurrentQuizName)).then(() => {
this.handleMessages();
});
......@@ -111,6 +121,7 @@ export class ConfidenceRateComponent implements OnInit, OnDestroy {
public async sendConfidence(): Promise<Subscription> {
return this.memberApiService.putConfidenceValue(parseInt(this._confidenceValue, 10)).subscribe((data: IMessage) => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
});
}
......@@ -122,8 +133,10 @@ export class ConfidenceRateComponent implements OnInit, OnDestroy {
sessionStorage.removeItem(StorageKey.CurrentQuestionIndex);
}), this.messageQueue.subscribe(MessageProtocol.Start, payload => {
this.quizService.quiz.currentStartTimestamp = payload.currentStartTimestamp;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'voting']);
}), this.messageQueue.subscribe(MessageProtocol.Stop, payload => {
}), this.messageQueue.subscribe(MessageProtocol.Stop, () => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
}), this.messageQueue.subscribe(MessageProtocol.UpdatedResponse, payload => {
console.log('ConfidenceRateComponent: modify response data for nickname', payload.nickname);
......@@ -131,6 +144,7 @@ export class ConfidenceRateComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.UpdatedSettings, payload => {
this.quizService.quiz.sessionConfig = payload.sessionConfig;
}), this.messageQueue.subscribe(MessageProtocol.ReadingConfirmationRequested, payload => {
this.hasTriggeredNavigation = true;
if (environment.readingConfirmationEnabled) {
this.router.navigate(['/quiz', 'flow', 'reading-confirmation']);
} else {
......@@ -139,12 +153,14 @@ export class ConfidenceRateComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Reset, payload => {
this.attendeeService.clearResponses();
this.quizService.quiz.currentQuestionIndex = -1;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'lobby']);
}), this.messageQueue.subscribe(MessageProtocol.Added, payload => {
this.attendeeService.addMember(payload.member);
}), this.messageQueue.subscribe(MessageProtocol.Removed, payload => {
this.attendeeService.removeMember(payload.name);
}), this.messageQueue.subscribe(MessageProtocol.Closed, payload => {
}), this.messageQueue.subscribe(MessageProtocol.Closed, () => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}),
]);
......
import { isPlatformBrowser } from '@angular/common';
import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
......@@ -10,6 +9,7 @@ import { environment } from '../../../../environments/environment';
import { StorageKey } from '../../../lib/enums/enums';
import { MessageProtocol } from '../../../lib/enums/Message';
import { QuizState } from '../../../lib/enums/QuizState';
import { IHasTriggeredNavigation } from '../../../lib/interfaces/IHasTriggeredNavigation';
import { ILeaderBoardItem } from '../../../lib/interfaces/ILeaderboard';
import { ServerUnavailableModalComponent } from '../../../modals/server-unavailable-modal/server-unavailable-modal.component';
import { LeaderboardApiService } from '../../../service/api/leaderboard/leaderboard-api.service';
......@@ -26,9 +26,10 @@ import { QuizService } from '../../../service/quiz/quiz.service';
templateUrl: './leaderboard.component.html',
styleUrls: ['./leaderboard.component.scss'],
})
export class LeaderboardComponent implements OnInit, OnDestroy {
export class LeaderboardComponent implements OnInit, OnDestroy, IHasTriggeredNavigation {
public static TYPE = 'LeaderboardComponent';
public isLoadingData = true;
public hasTriggeredNavigation: boolean;
private _questionIndex: number;
private readonly _destroy = new Subject();
......@@ -89,6 +90,7 @@ export class LeaderboardComponent implements OnInit, OnDestroy {
}
if (this.quizService.quiz.state === QuizState.Inactive) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
return;
}
......@@ -177,6 +179,7 @@ export class LeaderboardComponent implements OnInit, OnDestroy {
this.headerLabelService.headerLabel = 'component.leaderboard.global_header';
this._questionIndex = null;
if (params['questionIndex']) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'leaderboard']);
return;
}
......@@ -205,6 +208,7 @@ export class LeaderboardComponent implements OnInit, OnDestroy {
sessionStorage.removeItem(StorageKey.CurrentQuestionIndex);
}),
this.messageQueue.subscribe(MessageProtocol.Start, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'voting']);
}), this.messageQueue.subscribe(MessageProtocol.UpdatedResponse, payload => {
console.log('LeaderboardComponent: modify response data for nickname', payload.nickname);
......@@ -214,15 +218,16 @@ export class LeaderboardComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Reset, payload => {
this.attendeeService.clearResponses();
this.quizService.quiz.currentQuestionIndex = -1;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'lobby']);
}), this.messageQueue.subscribe(MessageProtocol.Removed, payload => {
if (isPlatformBrowser(this.platformId)) {
const existingNickname = sessionStorage.getItem(StorageKey.CurrentNickName);
if (existingNickname === payload.name) {
this.router.navigate(['/']);
}
const existingNickname = sessionStorage.getItem(StorageKey.CurrentNickName);
if (existingNickname === payload.name) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}
}), this.messageQueue.subscribe(MessageProtocol.Closed, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}),
]);
......@@ -234,6 +239,7 @@ export class LeaderboardComponent implements OnInit, OnDestroy {
];
this.footerBarService.footerElemBack.onClickCallback = () => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
};
......
......@@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router';
import { QRCodeModule } from 'angularx-qrcode';
import { MarkdownModule } from 'ngx-markdown';
import { CasLoginService } from '../../service/login/cas-login.service';
import { ShowUnloadWarningGuard } from '../../service/show-unload-warning-guard/show-unload-warning.guard';
import { SharedModule } from '../../shared/shared.module';
import { ConfidenceRateComponent } from './confidence-rate/confidence-rate.component';
import { LeaderboardComponent } from './leaderboard/leaderboard.component';
......@@ -26,6 +27,7 @@ export const quizFlowRoutes: Routes = [
canLoad: [CasLoginService],
component: QuizLobbyComponent,
data: {},
canDeactivate: [ShowUnloadWarningGuard],
}, {
path: 'results',
component: QuizResultsComponent,
......@@ -46,14 +48,17 @@ export const quizFlowRoutes: Routes = [
path: 'voting',
component: VotingComponent,
data: {},
canDeactivate: [ShowUnloadWarningGuard],
}, {
path: 'reading-confirmation',
component: ReadingConfirmationComponent,
data: {},
canDeactivate: [ShowUnloadWarningGuard],
}, {
path: 'confidence-rate',
component: ConfidenceRateComponent,
data: {},
canDeactivate: [ShowUnloadWarningGuard],
},
];
......
import { isPlatformBrowser } from '@angular/common';
import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID, SecurityContext, TemplateRef } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { Router } from '@angular/router';
......@@ -14,6 +13,7 @@ import { UserRole } from '../../../lib/enums/UserRole';
import { FooterbarElement } from '../../../lib/footerbar-element/footerbar-element';
import { IMessage } from '../../../lib/interfaces/communication/IMessage';
import { IMemberSerialized } from '../../../lib/interfaces/entities/Member/IMemberSerialized';
import { IHasTriggeredNavigation } from '../../../lib/interfaces/IHasTriggeredNavigation';
import { ServerUnavailableModalComponent } from '../../../modals/server-unavailable-modal/server-unavailable-modal.component';
import { MemberApiService } from '../../../service/api/member/member-api.service';
import { QuizApiService } from '../../../service/api/quiz/quiz-api.service';
......@@ -35,9 +35,11 @@ import { QrCodeContentComponent } from './modals/qr-code-content/qr-code-content
templateUrl: './quiz-lobby.component.html',
styleUrls: ['./quiz-lobby.component.scss'],
})
export class QuizLobbyComponent implements OnInit, OnDestroy {
export class QuizLobbyComponent implements OnInit, OnDestroy, IHasTriggeredNavigation {
public static TYPE = 'QuizLobbyComponent';
public hasTriggeredNavigation: boolean;
private _nickToRemove: string;
get nickToRemove(): string {
......@@ -81,6 +83,7 @@ export class QuizLobbyComponent implements OnInit, OnDestroy {
}
if (this.quizService.quiz.state === QuizState.Inactive) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
return;
}
......@@ -200,6 +203,7 @@ export class QuizLobbyComponent implements OnInit, OnDestroy {
this.memberApiService.deleteMember(this.quizService.quiz.name, this.attendeeService.ownNick).subscribe();
this.attendeeService.cleanUp();
this.connectionService.cleanUp();
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
};
}
......@@ -238,6 +242,7 @@ export class QuizLobbyComponent implements OnInit, OnDestroy {
this.quizService.readingConfirmationRequested = environment.readingConfirmationEnabled ? data.step
=== MessageProtocol.ReadingConfirmationRequested
: false;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
self.isLoading = false;
});
......@@ -252,6 +257,7 @@ export class QuizLobbyComponent implements OnInit, OnDestroy {
this.quizService.close();
this.attendeeService.cleanUp();
this.connectionService.cleanUp();
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'manager', 'overview']);
}).catch(() => {});
};
......@@ -273,6 +279,7 @@ export class QuizLobbyComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Start, payload => {
this.quizService.quiz.currentStartTimestamp = payload.currentStartTimestamp;
}), this.messageQueue.subscribe(MessageProtocol.Closed, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}),
]);
......@@ -295,21 +302,22 @@ export class QuizLobbyComponent implements OnInit, OnDestroy {
private handleMessagesForAttendee(): void {
this._messageSubscriptions.push(...[
this.messageQueue.subscribe(MessageProtocol.Start, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'voting']);
}), this.messageQueue.subscribe(MessageProtocol.UpdatedSettings, payload => {
this.quizService.quiz.sessionConfig = payload.sessionConfig;
}), this.messageQueue.subscribe(MessageProtocol.ReadingConfirmationRequested, payload => {
this.hasTriggeredNavigation = true;
if (environment.readingConfirmationEnabled) {
this.router.navigate(['/quiz', 'flow', 'reading-confirmation']);
} else {
this.router.navigate(['/quiz', 'flow', 'voting']);
}
}), this.messageQueue.subscribe(MessageProtocol.Removed, payload => {
if (isPlatformBrowser(this.platformId)) {
const existingNickname = sessionStorage.getItem(StorageKey.CurrentNickName);
if (existingNickname === payload.name) {
this.router.navigate(['/']);
}
const existingNickname = sessionStorage.getItem(StorageKey.CurrentNickName);
if (existingNickname === payload.name) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}
}),
]);
......
......@@ -11,6 +11,7 @@ import { RangedQuestionEntity } from '../../../../lib/entities/question/RangedQu
import { StorageKey } from '../../../../lib/enums/enums';
import { MessageProtocol } from '../../../../lib/enums/Message';
import { IMemberSerialized } from '../../../../lib/interfaces/entities/Member/IMemberSerialized';
import { IHasTriggeredNavigation } from '../../../../lib/interfaces/IHasTriggeredNavigation';
import { ServerUnavailableModalComponent } from '../../../../modals/server-unavailable-modal/server-unavailable-modal.component';
import { AttendeeService } from '../../../../service/attendee/attendee.service';
import { ConnectionService } from '../../../../service/connection/connection.service';
......@@ -23,8 +24,9 @@ import { QuizService } from '../../../../service/quiz/quiz.service';
templateUrl: './question-details.component.html',
styleUrls: ['./question-details.component.scss'],
})
export class QuestionDetailsComponent implements OnInit, OnDestroy {
export class QuestionDetailsComponent implements OnInit, OnDestroy, IHasTriggeredNavigation {
public static TYPE = 'QuestionDetailsComponent';
public hasTriggeredNavigation: boolean;
private _question: AbstractQuestionEntity;
......@@ -75,6 +77,11 @@ export class QuestionDetailsComponent implements OnInit, OnDestroy {
footerBarService.replaceFooterElements([
this.footerBarService.footerElemBack,
]);
this.footerBarService.footerElemBack.onClickCallback = () => {
this.hasTriggeredNavigation = true;
history.back();
};
}
public sanitizeHTML(value: string): string {
......@@ -121,6 +128,7 @@ export class QuestionDetailsComponent implements OnInit, OnDestroy {
this._questionIndex = questionIndex;
if (this._questionIndex < 0 || this._questionIndex > this.quizService.quiz.currentQuestionIndex) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
return;
}
......@@ -136,6 +144,7 @@ export class QuestionDetailsComponent implements OnInit, OnDestroy {
}
public ngOnDestroy(): void {
this.footerBarService.footerElemBack.restoreClickCallback();
this._messageSubscriptions.forEach(id => this.messageQueue.unsubscribe(id));
this._destroy.next();
this._destroy.complete();
......@@ -165,8 +174,10 @@ export class QuestionDetailsComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Reset, payload => {
this.attendeeService.clearResponses();
this.quizService.quiz.currentQuestionIndex = -1;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'lobby']);
}), this.messageQueue.subscribe(MessageProtocol.Closed, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}),
]);
......@@ -179,10 +190,12 @@ export class QuestionDetailsComponent implements OnInit, OnDestroy {
private handleMessagesForAttendee(): void {
this._messageSubscriptions.push(...[
this.messageQueue.subscribe(MessageProtocol.Start, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'voting']);
}), this.messageQueue.subscribe(MessageProtocol.UpdatedSettings, payload => {
this.quizService.quiz.sessionConfig = payload.sessionConfig;
}), this.messageQueue.subscribe(MessageProtocol.ReadingConfirmationRequested, payload => {
this.hasTriggeredNavigation = true;
if (environment.readingConfirmationEnabled) {
this.router.navigate(['/quiz', 'flow', 'reading-confirmation']);
} else {
......
......@@ -81,6 +81,7 @@
<div *ngIf="showLeaderBoardButton(selectedQuestionIndex) || showQuestionButton(selectedQuestionIndex)"
class="btn-group w-100">
<button *ngIf="showLeaderBoardButton(selectedQuestionIndex)"
(click)="hasTriggeredNavigation = true"
[routerLink]="['/quiz', 'flow', 'leaderboard', visibleQuestions.length > 1 ? selectedQuestionIndex : 'all']"
class="btn btn-light w-100 cursor-pointer"
type="button">
......@@ -89,6 +90,7 @@
<span>{{'component.liveResults.ranking' | translate}}</span>
</button>
<button *ngIf="showQuestionButton(selectedQuestionIndex)"
(click)="hasTriggeredNavigation = true"
[routerLink]="['/quiz', 'flow', 'results', selectedQuestionIndex]"
class="btn btn-light w-100 cursor-pointer"
type="button">
......
......@@ -11,6 +11,7 @@ import { MessageProtocol, StatusProtocol } from '../../../lib/enums/Message';
import { QuestionType } from '../../../lib/enums/QuestionType';
import { QuizState } from '../../../lib/enums/QuizState';
import { IMemberSerialized } from '../../../lib/interfaces/entities/Member/IMemberSerialized';
import { IHasTriggeredNavigation } from '../../../lib/interfaces/IHasTriggeredNavigation';
import { ServerUnavailableModalComponent } from '../../../modals/server-unavailable-modal/server-unavailable-modal.component';
import { QuizApiService } from '../../../service/api/quiz/quiz-api.service';
import { AttendeeService } from '../../../service/attendee/attendee.service';
......@@ -28,8 +29,9 @@ import { ToLobbyConfirmComponent } from './modals/to-lobby-confirm/to-lobby-conf
styleUrls: ['./quiz-results.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class QuizResultsComponent implements OnInit, OnDestroy {
export class QuizResultsComponent implements OnInit, OnDestroy, IHasTriggeredNavigation {
public static TYPE = 'QuizResultsComponent';
public hasTriggeredNavigation: boolean;
public countdown: number;
public answers: Array<string> = [];
public showStartQuizButton: boolean;
......@@ -222,6 +224,7 @@ export class QuizResultsComponent implements OnInit, OnDestroy {
}
if (this.quizService.quiz.state === QuizState.Inactive) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
return;
}
......@@ -327,6 +330,7 @@ export class QuizResultsComponent implements OnInit, OnDestroy {
return this.quizApiService.getQuizStatus(this.quizService.quiz.name).toPromise().then(currentStateData => {
if (currentStateData.status !== StatusProtocol.Success) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
return;
}
......@@ -334,6 +338,7 @@ export class QuizResultsComponent implements OnInit, OnDestroy {
if (currentStateData.payload.state === QuizState.Active) {
this.attendeeService.clearResponses();
this.quizService.quiz.currentQuestionIndex = -1;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'lobby']);
return;
}
......@@ -470,8 +475,10 @@ export class QuizResultsComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Reset, payload => {
this.attendeeService.clearResponses();
this.quizService.quiz.currentQuestionIndex = -1;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'lobby']);
}), this.messageQueue.subscribe(MessageProtocol.Closed, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}),
]);
......@@ -504,10 +511,12 @@ export class QuizResultsComponent implements OnInit, OnDestroy {
private handleMessagesForAttendee(): void {
this._messageSubscriptions.push(...[
this.messageQueue.subscribe(MessageProtocol.Start, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'voting']);
}), this.messageQueue.subscribe(MessageProtocol.UpdatedSettings, payload => {
this.quizService.quiz.sessionConfig = payload.sessionConfig;
}), this.messageQueue.subscribe(MessageProtocol.ReadingConfirmationRequested, payload => {
this.hasTriggeredNavigation = true;
if (environment.readingConfirmationEnabled) {
this.router.navigate(['/quiz', 'flow', 'reading-confirmation']);
} else {
......@@ -516,6 +525,7 @@ export class QuizResultsComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Removed, payload => {
const existingNickname = sessionStorage.getItem(StorageKey.CurrentNickName);
if (existingNickname === payload.name) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}
}),
......
......@@ -9,6 +9,7 @@ import { StorageKey } from '../../../lib/enums/enums';
import { MessageProtocol } from '../../../lib/enums/Message';
import { QuizState } from '../../../lib/enums/QuizState';
import { IMemberSerialized } from '../../../lib/interfaces/entities/Member/IMemberSerialized';
import { IHasTriggeredNavigation } from '../../../lib/interfaces/IHasTriggeredNavigation';
import { ServerUnavailableModalComponent } from '../../../modals/server-unavailable-modal/server-unavailable-modal.component';
import { MemberApiService } from '../../../service/api/member/member-api.service';
import { AttendeeService } from '../../../service/attendee/attendee.service';
......@@ -23,9 +24,11 @@ import { QuizService } from '../../../service/quiz/quiz.service';
templateUrl: './reading-confirmation.component.html',
styleUrls: ['./reading-confirmation.component.scss'],
})
export class ReadingConfirmationComponent implements OnInit, OnDestroy {
export class ReadingConfirmationComponent implements OnInit, OnDestroy, IHasTriggeredNavigation {
public static TYPE = 'ReadingConfirmationComponent';
public hasTriggeredNavigation: boolean;
public questionIndex: number;
public questionText: string;
......@@ -74,12 +77,19 @@ export class ReadingConfirmationComponent implements OnInit, OnDestroy {
this._serverUnavailableModal.result.finally(() => this._serverUnavailableModal = null);
});
if (this.attendeeService.hasReadingConfirmation()) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
return;
}
this.quizService.quizUpdateEmitter.pipe(takeUntil(this._destroy)).subscribe(quiz => {
if (!quiz) {
return;
}
if (this.quizService.quiz.state === QuizState.Inactive) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
return;
}
......@@ -105,6 +115,7 @@ export class ReadingConfirmationComponent implements OnInit, OnDestroy {
public confirmReading(): void {
this.memberApiService.putReadingConfirmationValue().subscribe(() => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
});
}
......@@ -115,6 +126,7 @@ export class ReadingConfirmationComponent implements OnInit, OnDestroy {
this.quizService.quiz.currentQuestionIndex = payload.nextQuestionIndex;
sessionStorage.removeItem(StorageKey.CurrentQuestionIndex);
}), this.messageQueue.subscribe(MessageProtocol.Start, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'voting']);
}), this.messageQueue.subscribe(MessageProtocol.UpdatedResponse, payload => {
console.log('ReadingConfirmationComponent: modifying response data for nickname', payload.nickname);
......@@ -124,8 +136,10 @@ export class ReadingConfirmationComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Reset, payload => {
this.attendeeService.clearResponses();
this.quizService.quiz.currentQuestionIndex = -1;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'lobby']);
}), this.messageQueue.subscribe(MessageProtocol.Closed, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}), this.messageQueue.subscribe(MessageProtocol.Added, payload => {
this.attendeeService.addMember(payload.member);
......
import { isPlatformBrowser } from '@angular/common';
import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { Router } from '@angular/router';
......@@ -15,6 +14,7 @@ import { MessageProtocol, StatusProtocol } from '../../../lib/enums/Message';
import { QuestionType } from '../../../lib/enums/QuestionType';
import { QuizState } from '../../../lib/enums/QuizState';
import { IMessage } from '../../../lib/interfaces/communication/IMessage';
import { IHasTriggeredNavigation } from '../../../lib/interfaces/IHasTriggeredNavigation';
import { ServerUnavailableModalComponent } from '../../../modals/server-unavailable-modal/server-unavailable-modal.component';
import { MemberApiService } from '../../../service/api/member/member-api.service';
import { QuizApiService } from '../../../service/api/quiz/quiz-api.service';
......@@ -30,9 +30,10 @@ import { QuizService } from '../../../service/quiz/quiz.service';
templateUrl: './voting.component.html',
styleUrls: ['./voting.component.scss'],
})
export class VotingComponent implements OnInit, OnDestroy {
export class VotingComponent implements OnInit, OnDestroy, IHasTriggeredNavigation {
public static TYPE = 'VotingComponent';
public isSendingResponse: boolean;
public hasTriggeredNavigation: boolean;
private _answers: Array<string> = [];
......@@ -144,10 +145,8 @@ export class VotingComponent implements OnInit, OnDestroy {
public sendResponses(route?: string): void {
this.isSendingResponse = true;
this.router.navigate([
'/quiz', 'flow', route ? route : environment.confidenceSliderEnabled && //
this.quizService.quiz.sessionConfig.confidenceSliderEnabled ? 'confidence-rate' : 'results',
]);
this.hasTriggeredNavigation = true;
this.router.navigate(this.getNextRoute(route));
}
public initData(): void {
......@@ -171,11 +170,18 @@ export class VotingComponent implements OnInit, OnDestroy {
}
if (this.quizService.quiz.state === QuizState.Inactive) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
return;
}
this._currentQuestion = this.quizService.currentQuestion();
if (this.attendeeService.hasReponse()) {
this.hasTriggeredNavigation = true;
this.router.navigate(this.getNextRoute());
return;
}
this.initData();
this.questionTextService.eventEmitter.pipe(takeUntil(this._destroy)).subscribe((value: string | Array<string>) => {
......@@ -252,18 +258,20 @@ export class VotingComponent implements OnInit, OnDestroy {
}), this.messageQueue.subscribe(MessageProtocol.Reset, payload => {
this.attendeeService.clearResponses();
this.quizService.quiz.currentQuestionIndex = -1;
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'lobby']);
}), this.messageQueue.subscribe(MessageProtocol.Closed, payload => {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}), this.messageQueue.subscribe(MessageProtocol.Removed, payload => {
if (isPlatformBrowser(this.platformId)) {
const existingNickname = sessionStorage.getItem(StorageKey.CurrentNickName);
if (existingNickname === payload.name) {
this.router.navigate(['/']);
}
const existingNickname = sessionStorage.getItem(StorageKey.CurrentNickName);
if (existingNickname === payload.name) {
this.hasTriggeredNavigation = true;
this.router.navigate(['/']);
}
}), this.messageQueue.subscribe(MessageProtocol.Stop, payload => {
this._selectedAnswers = [];
this.hasTriggeredNavigation = true;
this.router.navigate(['/quiz', 'flow', 'results']);
}),
]);
......@@ -281,4 +289,11 @@ export class VotingComponent implements OnInit, OnDestroy {
QuestionType.YesNoSingleChoiceQuestion,
].includes(this._currentQuestion.TYPE);
}
private getNextRoute(route?: string): Array<string> {
return [
'/quiz', 'flow', route ? route : environment.confidenceSliderEnabled && //
this.quizService.quiz.sessionConfig.confidenceSliderEnabled ? 'confidence-rate' : 'results',
];
}
}
......@@ -100,6 +100,25 @@ export class AttendeeService {
});
}
public hasReponse(): boolean {
const response = this.getMember(this.ownNick).responses[this.quizService.quiz.currentQuestionIndex];
if (typeof response.value === 'number') {
return response && !isNaN(response.value);
}
return response && response.value.length > 0;
}
public hasReadingConfirmation(): boolean {
const response = this.getMember(this.ownNick).responses[this.quizService.quiz.currentQuestionIndex];
return response && response.readingConfirmation;
}
public hasConfidenceValue(): boolean {
const response = this.getMember(this.ownNick).responses[this.quizService.quiz.currentQuestionIndex];
return response && !isNaN(response.confidence);
}
private restoreMembers(): Promise<void> {
return new Promise<void>(resolve => {
this.memberApiService.getMembers(this.quizService.quiz.name).subscribe((data) => {
......
import { isPlatformBrowser } from '@angular/common';
import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { Inject, Injectable, Injector, PLATFORM_ID } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { RxStompService } from '@stomp/ng2-stompjs';
import { RxStompState } from '@stomp/rx-stomp';
......@@ -158,9 +159,9 @@ export class FooterBarService {
introTranslate: 'region.footer.footer_bar.description.fullscreen',
linkTarget: null,
isActive: isPlatformBrowser(this.platformId) ? window.outerWidth === screen.width && window.outerHeight === screen.height : false,
}, function (): void {
this.isActive = !this.isActive;
setFullScreen(this.isActive);
}, self => {
self.isActive = !self.isActive;
setFullScreen(self.isActive);
});
public footerElemHome: IFooterBarElement = new FooterbarElement({
id: 'home',
......@@ -260,8 +261,7 @@ export class FooterBarService {
showIntro: false,
introTranslate: 'region.footer.footer_bar.description.back',
linkTarget: null,
</