diff --git a/apps/client/src/app/fly-squasher/main/main.component.html b/apps/client/src/app/fly-squasher/main/main.component.html index 32910047..a8af0b4f 100644 --- a/apps/client/src/app/fly-squasher/main/main.component.html +++ b/apps/client/src/app/fly-squasher/main/main.component.html @@ -1 +1,9 @@ + + +
Are you sure you wish to leave?
+
diff --git a/apps/client/src/app/fly-squasher/main/main.component.spec.ts b/apps/client/src/app/fly-squasher/main/main.component.spec.ts index aaa95af9..a0c4276f 100644 --- a/apps/client/src/app/fly-squasher/main/main.component.spec.ts +++ b/apps/client/src/app/fly-squasher/main/main.component.spec.ts @@ -10,6 +10,7 @@ import { } from "../game/fly-squasher-communicator.service"; import { SceneCommunicatorClientService } from "./scene-communicator-client.service"; import { sceneCommunicatorClientServiceStub } from "./scene-communicator-client.service.spec"; +import { ModalTestComponent } from "../../shared/components/modal/modal.component.spec"; jest.mock("../game/consts/game-config", () => ({ flySquasherGameConfig: {} @@ -21,7 +22,7 @@ describe("MainComponent", () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [MainComponent, GameContainerTestingComponent], + declarations: [MainComponent, ModalTestComponent, GameContainerTestingComponent], providers: [ { provide: AuthService, useValue: authServiceStub }, { provide: FlySquasherCommunicatorService, useValue: flySquasherCommunicatorServiceStub }, diff --git a/apps/client/src/app/fly-squasher/main/main.component.ts b/apps/client/src/app/fly-squasher/main/main.component.ts index ae0bb0aa..a3035e1f 100644 --- a/apps/client/src/app/fly-squasher/main/main.component.ts +++ b/apps/client/src/app/fly-squasher/main/main.component.ts @@ -1,24 +1,36 @@ -import { Component, Input, OnDestroy, OnInit } from "@angular/core"; +import { Component, Input, OnDestroy, OnInit, ViewChild } from "@angular/core"; import { flySquasherGameConfig } from "../game/consts/game-config"; import { FlySquasherGameInstance, FlySquasherLevels, FlySquasherUserInfo } from "@fuzzy-waddle/api-interfaces"; import { AuthService } from "../../auth/auth.service"; import { FlySquasherGameData } from "../game/fly-squasher-game-data"; import { FlySquasherCommunicatorService } from "../game/fly-squasher-communicator.service"; import { SceneCommunicatorClientService } from "./scene-communicator-client.service"; +import { Router } from "@angular/router"; +import { PreventNavigateBack } from "../../shared/handlers/prevent-navigate-back"; +import { ModalConfig } from "../../shared/components/modal/modal-config"; +import { ModalComponent } from "../../shared/components/modal/modal.component"; @Component({ templateUrl: "./main.component.html", styleUrls: ["./main.component.scss"] }) export class MainComponent implements OnInit, OnDestroy { + @ViewChild("modal") private modalComponent!: ModalComponent; protected readonly flySquasherGameConfig = flySquasherGameConfig; protected gameData!: FlySquasherGameData; @Input() level!: string; - + private preventNavigateBack = new PreventNavigateBack(this.router); + protected leaveModalConfirm: ModalConfig = { + modalTitle: "Leave the game?", + dismissButtonLabel: "Continue", + closeButtonLabel: "Leave", + onClose: async () => this.preventNavigateBack.navigateBack() + }; constructor( private readonly authService: AuthService, private readonly communicatorService: FlySquasherCommunicatorService, - private readonly sceneCommunicatorClientService: SceneCommunicatorClientService + private readonly sceneCommunicatorClientService: SceneCommunicatorClientService, + private readonly router: Router ) {} ngOnInit(): void { @@ -37,6 +49,14 @@ export class MainComponent implements OnInit, OnDestroy { this.sceneCommunicatorClientService.startCommunication(); } + protected async leave() { + await this.openModal(); + } + + private async openModal() { + return await this.modalComponent.open(); + } + ngOnDestroy(): void { this.sceneCommunicatorClientService.stopCommunication(); } diff --git a/apps/client/src/app/little-muncher/main/game-interface/game-interface.component.ts b/apps/client/src/app/little-muncher/main/game-interface/game-interface.component.ts index 426fe422..741b10ca 100644 --- a/apps/client/src/app/little-muncher/main/game-interface/game-interface.component.ts +++ b/apps/client/src/app/little-muncher/main/game-interface/game-interface.component.ts @@ -7,6 +7,8 @@ import { Subscription } from "rxjs"; import { faPause, faPlay } from "@fortawesome/free-solid-svg-icons"; import { AuthService } from "../../../auth/auth.service"; import { LittleMuncherHillEnum, LittleMuncherHills } from "@fuzzy-waddle/api-interfaces"; +import { PreventNavigateBack } from "../../../shared/handlers/prevent-navigate-back"; +import { Router } from "@angular/router"; @Component({ selector: "fuzzy-waddle-game-interface", @@ -21,12 +23,15 @@ export class GameInterfaceComponent implements OnInit, OnDestroy { protected readonly faPlay = faPlay; protected paused = false; protected isPlayer = false; - + private preventNavigateBack = new PreventNavigateBack(this.router); protected readonly leaveModalConfirm: ModalConfig = { modalTitle: "Leave the game?", dismissButtonLabel: "Continue", closeButtonLabel: "Leave", - onClose: async () => await this.gameInstanceClientService.stopLevel("localAndRemote").then() + onClose: async () => + await this.gameInstanceClientService + .stopLevel("localAndRemote") + .then(() => this.preventNavigateBack.allowNavigateBack()) }; private scoreSubscription?: Subscription; private pauseSubscription?: Subscription; @@ -35,7 +40,8 @@ export class GameInterfaceComponent implements OnInit, OnDestroy { private readonly authService: AuthService, private readonly gameInstanceClientService: GameInstanceClientService, private readonly communicatorService: LittleMuncherCommunicatorService, - private readonly changeDetectorRef: ChangeDetectorRef + private readonly changeDetectorRef: ChangeDetectorRef, + private readonly router: Router ) {} protected async leave() { diff --git a/apps/client/src/app/shared/components/modal/modal-config.ts b/apps/client/src/app/shared/components/modal/modal-config.ts index 3d4aac22..58280e3b 100644 --- a/apps/client/src/app/shared/components/modal/modal-config.ts +++ b/apps/client/src/app/shared/components/modal/modal-config.ts @@ -7,7 +7,7 @@ export interface ModalConfig { shouldDismiss?(): Promise | boolean; - onClose?(): Promise | boolean; + onClose?(): Promise | boolean | Promise; onDismiss?(): Promise | boolean; diff --git a/apps/client/src/app/shared/handlers/prevent-navigate-back.ts b/apps/client/src/app/shared/handlers/prevent-navigate-back.ts new file mode 100644 index 00000000..a7464e64 --- /dev/null +++ b/apps/client/src/app/shared/handlers/prevent-navigate-back.ts @@ -0,0 +1,29 @@ +import { NavigationStart, Router } from "@angular/router"; + +export class PreventNavigateBack { + private canNavigateBack = false; + + constructor(private readonly router: Router) { + this.disableBrowserBackButton(); + } + + private disableBrowserBackButton() { + // Subscribe to router events to handle back button in browser + this.router.events.subscribe((event) => { + if (!(event instanceof NavigationStart && event.navigationTrigger === "popstate" && !this.canNavigateBack)) { + return; + } + // noinspection JSIgnoredPromiseFromCall + this.router.navigateByUrl(this.router.url); + }); + } + + allowNavigateBack() { + this.canNavigateBack = true; + } + + navigateBack() { + this.allowNavigateBack(); + window.history.back(); + } +}