diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 2275fe59b..a9b404688 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -17,6 +17,7 @@ import { PingService } from './core/core-services/ping.service'; import { SpinnerService } from './core/ui-services/spinner.service'; import { Router } from '@angular/router'; import { ViewUser } from './site/users/models/view-user'; +import { RoutingStateService } from './core/ui-services/routing-state.service'; /** * Enhance array with own functions @@ -80,7 +81,8 @@ export class AppComponent { loadFontService: LoadFontService, dataStoreUpgradeService: DataStoreUpgradeService, // to start it. prioritizeService: PrioritizeService, - pingService: PingService + pingService: PingService, + routingState: RoutingStateService ) { // manually add the supported languages translate.addLangs(['en', 'de', 'cs']); diff --git a/client/src/app/core/ui-services/routing-state.service.spec.ts b/client/src/app/core/ui-services/routing-state.service.spec.ts new file mode 100644 index 000000000..c7fd3c949 --- /dev/null +++ b/client/src/app/core/ui-services/routing-state.service.spec.ts @@ -0,0 +1,17 @@ +import { TestBed } from '@angular/core/testing'; + +import { RoutingStateService } from './routing-state.service'; +import { E2EImportsModule } from 'e2e-imports.module'; + +describe('RoutingStateService', () => { + beforeEach(() => + TestBed.configureTestingModule({ + imports: [E2EImportsModule] + }) + ); + + it('should be created', () => { + const service: RoutingStateService = TestBed.get(RoutingStateService); + expect(service).toBeTruthy(); + }); +}); diff --git a/client/src/app/core/ui-services/routing-state.service.ts b/client/src/app/core/ui-services/routing-state.service.ts new file mode 100644 index 000000000..ab8a05ceb --- /dev/null +++ b/client/src/app/core/ui-services/routing-state.service.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { Router, RoutesRecognized } from '@angular/router'; +import { filter, pairwise } from 'rxjs/operators'; + +/** + * Watches URL changes. + * Can be enhanced using locale storage to support back-navigation even after reload + */ +@Injectable({ + providedIn: 'root' +}) +export class RoutingStateService { + /** + * Hold the previous URL + */ + private _previousUrl: string; + + /** + * Unsafe paths that the user should not go "back" to + * TODO: Might also work using Routing parameters + */ + private unsafeUrls: string[] = ['/login', '/privacypolicy', '/legalnotice']; + + /** + * @return Get the previous URL + */ + public get previousUrl(): string { + return this._previousUrl ? this._previousUrl : null; + } + + public get isSafePrevUrl(): boolean { + return !!this.previousUrl && !this.unsafeUrls.includes(this.previousUrl); + } + + /** + * Watch routing changes and save the last visited URL + * + * @param router Angular Router + */ + public constructor(private router: Router) { + this.router.events + .pipe( + filter(e => e instanceof RoutesRecognized), + pairwise() + ) + .subscribe((event: any[]) => { + this._previousUrl = event[0].urlAfterRedirects; + console.log('prev URL: ', this._previousUrl); + }); + } +} diff --git a/client/src/app/shared/components/head-bar/head-bar.component.html b/client/src/app/shared/components/head-bar/head-bar.component.html index 239f9dbdb..9109cc283 100644 --- a/client/src/app/shared/components/head-bar/head-bar.component.html +++ b/client/src/app/shared/components/head-bar/head-bar.component.html @@ -7,12 +7,12 @@
- - diff --git a/client/src/app/shared/components/head-bar/head-bar.component.ts b/client/src/app/shared/components/head-bar/head-bar.component.ts index 6b09d336b..6c3fd4944 100644 --- a/client/src/app/shared/components/head-bar/head-bar.component.ts +++ b/client/src/app/shared/components/head-bar/head-bar.component.ts @@ -1,9 +1,9 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; -import { Location } from '@angular/common'; import { Router, ActivatedRoute } from '@angular/router'; import { ViewportService } from 'app/core/ui-services/viewport.service'; import { MainMenuService } from 'app/core/core-services/main-menu.service'; +import { RoutingStateService } from 'app/core/ui-services/routing-state.service'; /** * Reusable head bar component for Apps. @@ -111,6 +111,10 @@ export class HeadBarComponent { @Output() public saveEvent = new EventEmitter(); + public get showBackButton(): boolean { + return !this.nav && !this.editMode && !this.multiSelectMode && this.routingState.isSafePrevUrl; + } + /** * Empty constructor */ @@ -119,7 +123,7 @@ export class HeadBarComponent { private menu: MainMenuService, private router: Router, private route: ActivatedRoute, - private location: Location + private routingState: RoutingStateService ) {} /** @@ -149,7 +153,7 @@ export class HeadBarComponent { */ public onBackButton(): void { if (this.goBack) { - this.location.back(); + this.router.navigateByUrl(this.routingState.previousUrl); } else { this.router.navigate([this.prevUrl], { relativeTo: this.route }); } diff --git a/requirements/production.txt b/requirements/production.txt index d0948c463..cb9e07044 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -6,7 +6,7 @@ bleach>=1.5.0,<3.2 channels>=2.1.2,<2.2 daphne>=2.2,<2.3 Django>=2.1,<2.3 -djangorestframework>=3.4,<3.10 +djangorestframework>=3.9.4,<3.10 jsonfield2>=3.0,<3.1 jsonschema>=3.0,<3.1 lz4>=2.1.6