LP1904036 Patron tabs can be opened in new browser tabs/windows
authorBill Erickson <berickxx@gmail.com>
Mon, 21 Mar 2022 16:20:08 +0000 (12:20 -0400)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Oct 2022 00:13:41 +0000 (20:13 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.ts
Open-ILS/src/eg2/src/app/staff/circ/patron/patron.service.ts

index a0d6ca3..638d82a 100644 (file)
@@ -67,7 +67,7 @@
   <div [ngClass]="{'col-lg-9': showSummaryPane(), 'col-lg-12': !showSummaryPane()}">
 
     <div class="sticky-top-with-nav bg-white">
-      <ul ngbNav #patronNav="ngbNav" class="nav-tabs"
+      <ul ngbNav #patronNav="ngbNav" class="nav-tabs" [keyboard]="false"
         [activeId]="patronTab" (navChange)="beforeTabChange($event)">
 
         <ng-container *ngIf="patronTab !== 'search'">
@@ -85,7 +85,8 @@
         </ng-container>
 
         <li ngbNavItem="checkout" [disabled]="!context.summary">
-          <a ngbNavLink i18n>Check Out</a>
+          <a ngbNavLink (click)="navItemClick('checkout', $event)"
+            routerLink="/staff/circ/patron/{{patronId}}/checkout" i18n>Check Out</a>
           <ng-template ngbNavContent>
             <div class="">
               <eg-patron-checkout></eg-patron-checkout> 
@@ -94,7 +95,8 @@
         </li>
 
         <li ngbNavItem="items_out" [disabled]="!context.summary">
-          <a ngbNavLink i18n>
+          <a ngbNavLink (click)="navItemClick('items_out', $event)"
+            routerLink="/staff/circ/patron/{{patronId}}/items_out" i18n>
             Items Out ({{counts('checkouts', 'total_out')}})
           </a>
           <ng-template ngbNavContent>
         </li>
 
         <li ngbNavItem="holds" [disabled]="!context.summary">
-          <a ngbNavLink i18n>
+          <a ngbNavLink (click)="navItemClick('holds', $event)"
+            routerLink="/staff/circ/patron/{{patronId}}/holds" i18n>
             Holds ({{counts('holds', 'ready')}} / {{counts('holds', 'total')}})
           </a>
           <ng-template ngbNavContent>
         </li>
 
         <li ngbNavItem="bills" [disabled]="!context.summary">
-          <a ngbNavLink (click)="billsTabClicked()" i18n>
+          <a ngbNavLink (click)="navItemClick('bills', $event)"
+            routerLink="/staff/circ/patron/{{patronId}}/bills" i18n>
             Bills 
             <span [ngClass]="{'text-danger': counts('fines', 'balance_owed') > 0}">
               ({{counts('fines', 'balance_owed') | currency}})
         </li>
 
         <li ngbNavItem="messages" [disabled]="!context.summary">
-          <a ngbNavLink i18n>Messages</a>
+          <a ngbNavLink (click)="navItemClick('messages', $event)"
+            routerLink="/staff/circ/patron/{{patronId}}/messages" i18n>Messages</a>
           <ng-template ngbNavContent>
             <div class="">
               <eg-patron-messages [patronId]="patronId"></eg-patron-messages>
         </li>
 
         <li ngbNavItem="edit" [disabled]="!context.summary">
-          <a ngbNavLink i18n>Edit</a>
+          <a ngbNavLink (click)="navItemClick('edit', $event)"
+            routerLink="/staff/circ/patron/{{patronId}}/edit" i18n>Edit</a>
           <ng-template ngbNavContent>
             <eg-patron-edit #patronEditor [patronId]="patronId" [toolbar]="editorToolbar">
             </eg-patron-edit> 
index 60703cd..90e6d84 100644 (file)
@@ -1,5 +1,6 @@
 import {Component, ViewChild, OnInit, AfterViewInit, HostListener} from '@angular/core';
 import {Router, ActivatedRoute, ParamMap, RoutesRecognized} from '@angular/router';
+import {Location} from '@angular/common';
 import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
 import {Observable, throwError, empty} from 'rxjs';
 import {filter, pairwise, concatMap, tap} from 'rxjs/operators';
@@ -56,6 +57,7 @@ export class PatronComponent implements OnInit, AfterViewInit {
     constructor(
         private router: Router,
         private route: ActivatedRoute,
+        private ngLocation: Location,
         private net: NetService,
         private auth: AuthService,
         private pcrud: PcrudService,
@@ -178,47 +180,48 @@ export class PatronComponent implements OnInit, AfterViewInit {
     ngAfterViewInit() {
     }
 
-    beforeTabChange(evt: NgbNavChangeEvent) {
-        // tab will change with route navigation.
+    // Navigate, opening new tabs when requested via control-click.
+    // NOTE: The nav items have routerLinks, but for some reason,
+    // control-click on the links does not open them in a new tab.
+    // Mouse middle-click does, though.  *shrug*
+    navItemClick(tab: string, evt: PointerEvent) {
         evt.preventDefault();
-
-        // Protect against tab changes with dirty data.
         this.canDeactivate().then(ok => {
             if (ok) {
-                this.patronTab = evt.nextId;
-                this.routeToTab();
+                this.routeToTab(tab, evt.ctrlKey);
             }
         });
     }
 
-    // The bills tab has various sub-interfaces.  If the user is already
-    // on the Bills tab and clicks the tab, return them to the main bills
-    // screen.
-    // Avoid the navigate call when not on the bills tab because it
-    // interferes with the pre-tab-change "changes pending" confirm dialog
-    // used by the editor and possibily others.
-    billsTabClicked() {
-        if (this.patronTab === 'bills') {
-            this.router.navigate(['/staff/circ/patron', this.patronId, 'bills']);
-        }
+    beforeTabChange(evt: NgbNavChangeEvent) {
+        // Prevent the nav component from changing tabs so we can
+        // control the behaviour.
+        evt.preventDefault();
     }
 
-    routeToTab() {
+    routeToTab(tab?: string, newWindow?: boolean) {
         let url = '/staff/circ/patron/';
 
-        switch (this.patronTab) {
+        tab = tab || this.patronTab;
+
+        switch (tab) {
             case 'search':
             case 'bcsearch':
-                url += this.patronTab;
+                url += tab;
                 break;
             case 'other':
                 url += `${this.patronId}/${this.altTab}`;
                 break;
             default:
-                url += `${this.patronId}/${this.patronTab}`;
+                url += `${this.patronId}/${tab}`;
         }
 
-        this.router.navigate([url]);
+        if (newWindow) {
+            url = this.ngLocation.prepareExternalUrl(url);
+            window.open(url);
+        } else {
+            this.router.navigate([url]);
+        }
     }
 
     showSummaryPane(): boolean {
index e696cba..2b69f59 100644 (file)
@@ -140,9 +140,10 @@ export class PatronContextService {
 
     patronAlertsShown(): boolean {
         if (!this.summary) { return false; }
-        const shown = this.store.getSessionItem('eg.circ.last_alerted_patron');
+        this.store.addLoginSessionKey('eg.circ.last_alerted_patron');
+        const shown = this.store.getLoginSessionItem('eg.circ.last_alerted_patron');
         if (shown === this.summary.patron.id()) { return true; }
-        this.store.setSessionItem('eg.circ.last_alerted_patron', this.summary.patron.id());
+        this.store.setLoginSessionItem('eg.circ.last_alerted_patron', this.summary.patron.id());
         return false;
     }