LP1816475: more improvements to the Create screen
authorJane Sandberg <sandbej@linnbenton.edu>
Tue, 2 Apr 2019 03:58:02 +0000 (20:58 -0700)
committerJane Sandberg <sandbej@linnbenton.edu>
Wed, 17 Apr 2019 20:41:54 +0000 (13:41 -0700)
Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu>
Open-ILS/src/eg2/src/app/share/daterange-select/daterange-select.component.html
Open-ILS/src/eg2/src/app/share/daterange-select/daterange-select.component.ts
Open-ILS/src/eg2/src/app/staff/booking/create-reservation.component.html
Open-ILS/src/eg2/src/app/staff/booking/create-reservation.component.ts
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.data.booking-sticky-settings.sql

index 72b297c..7441d97 100644 (file)
@@ -1,4 +1,4 @@
-import {Component} from '@angular/core';
+import {Component, Output, EventEmitter} from '@angular/core';
 import {NgbDate, NgbCalendar} from '@ng-bootstrap/ng-bootstrap';
 
 @Component({
@@ -31,6 +31,8 @@ export class DateRangeSelectComponent {
   fromDate: NgbDate;
   toDate: NgbDate;
 
+  @Output() onChange = new EventEmitter<{start: NgbDate, end: NgbDate}>();
+
   constructor(calendar: NgbCalendar) {
     this.fromDate = calendar.getToday();
     this.toDate = calendar.getNext(calendar.getToday(), 'd', 10);
@@ -45,6 +47,7 @@ export class DateRangeSelectComponent {
       this.toDate = null;
       this.fromDate = date;
     }
+    this.onChange.emit({start: this.fromDate, end: this.toDate});
   }
 
   isHovered(date: NgbDate) {
index 6a9777f..4cf6b61 100644 (file)
   <div class="col">
     <div class="input-group">
       <div class="input-group-prepend">
+        <label for="pickup-library" i18n class="input-group-text">Owning library</label>
+      </div>
+      <eg-org-select domId="owning-library">
+      </eg-org-select>
+    </div>
+  </div>
+  <div class="col">
+    <div class="form-check">
+      <input type="checkbox" class="form-check-input" id="include-descendants">
+      <label class="form-check-label" for="include-descendants" i18n>+ Descendants</label>
+    </div>
+  </div>
+  <div class="col">
+    <div class="input-group">
+      <div class="input-group-prepend">
         <label class="input-group-text" for="ideal-reservation-type" i18n>Reservation type</label>
       </div>
       <div ngbDropdown>
           <span class="input-group-prepend">
             <label class="input-group-text" for="granularity" i18n>Granularity</label>
           </span>
-          <eg-combobox (onChange)="granularity = $event.entryId">
+          <eg-combobox (onChange)="changeGranularity($event)" [startId]="granularity">
             <eg-combobox-entry entryId="15" entryLabel="15 minutes"
             i18n-entryLabel></eg-combobox-entry>
             <eg-combobox-entry entryId="30" entryLabel="30 minutes"
index 830d506..a7d2231 100644 (file)
@@ -1,12 +1,14 @@
-import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { Component, Input, OnInit, AfterViewInit, QueryList, ViewChildren, ViewChild } from '@angular/core';
 import { NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
 import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
+import {DateRangeSelectComponent} from '@eg/share/daterange-select/daterange-select.component';
 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {GridDataSource,  GridRowFlairEntry} from '@eg/share/grid/grid';
 import {IdlObject} from '@eg/core/idl.service';
 import {PcrudService} from '@eg/core/pcrud.service';
+import {ServerStoreService} from '@eg/core/server-store.service';
 import {ToastService} from '@eg/share/toast/toast.service';
 
 import * as Moment from 'moment-timezone';
@@ -16,7 +18,7 @@ import * as Moment from 'moment-timezone';
     templateUrl: './create-reservation.component.html'
 })
 
-export class CreateReservationComponent implements OnInit {
+export class CreateReservationComponent implements OnInit, AfterViewInit {
 
     advancedCollapsed = true;
     attributes: IdlObject[] = [];
@@ -26,19 +28,26 @@ export class CreateReservationComponent implements OnInit {
 
     startTime: Moment;
     endTime: Moment;
-    granularity: 15 | 30 | 60 = 30;
+    granularity: 15 | 30 | 60 | 1440 = 30; // 1440 minutes = 24 hours
 
     scheduleSource: GridDataSource = new GridDataSource();
 
     resources: IdlObject[] = [];
     limitByAttr: (attributeId: number, $event: ComboboxEntry) => void;
 
-    @ViewChild('dateLimiter') dateLimiter: DateSelectComponent;
+    setGranularity: () => void;
+    handleMultiDayReservation: () => void;
+    handleSingleDayReservation: () => void;
+    changeGranularity: ($event: ComboboxEntry) => void;
+
+    @ViewChildren('dateLimiter') dateLimiters: QueryList<DateSelectComponent>;
+    @ViewChildren('dateRangeLimiter') dateRangeLimiters: QueryList<DateRangeSelectComponent>;
+    @ViewChildren('scheduleGrid') scheduleGrids: QueryList<GridComponent>;
     @ViewChild('newDialog') newDialog: FmRecordEditorComponent;
-    @ViewChild('scheduleGrid') scheduleGrid: GridComponent;
 
     constructor(
         private pcrud: PcrudService,
+        private store: ServerStoreService,
         private toast: ToastService,
     ) {
         this.resourceAvailabilityIcon = (row: any) => {
@@ -56,8 +65,6 @@ export class CreateReservationComponent implements OnInit {
 
 
     ngOnInit() {
-        this.dateLimiter.initialDate = new Date();
-
 
         this.isBooked = (row: any, col: any) => {
             if ((col.name !== 'time') && (row[col.name])) {
@@ -71,12 +78,44 @@ export class CreateReservationComponent implements OnInit {
             console.log('event: ' + JSON.stringify($event));
         };
 
+        this.setGranularity = () => {
+            if (this.multiday) { // multiday reservations always use day granularity
+                this.granularity = 1440;
+            } else {
+                this.store.getItem('eg.booking.create.granularity').then(granularity => {
+                    if (granularity != null) { this.granularity = granularity; }
+                });
+            }
+           this.scheduleGrids.forEach((g) => g.reload());
+        };
+
+        this.handleMultiDayReservation = () => {
+            this.multiday = true;
+            this.setGranularity();
+        };
+
+        this.handleSingleDayReservation = () => {
+            this.multiday = false;
+            this.setGranularity();
+        };
+
+        this.changeGranularity = ($event) => {
+            this.granularity = $event.id;
+            this.store.setItem('eg.booking.create.granularity', $event.id);
+        };
+
     }
+
+    ngAfterViewInit() {
+        this.dateLimiters.forEach((dl) => dl.initialDate = new Date());
+        this.setGranularity();
+    }
+
     showNewDialog(idlThing: IdlObject) {
         return this.newDialog.open({size: 'lg'}).then(
             ok => {
                 this.toast.success('Reservation successfully created'); // TODO: needs i18n, pluralization
-                this.scheduleGrid.reload();
+               this.scheduleGrids.forEach((g) => g.reload());
             },
             err => {}
         );
@@ -117,16 +156,18 @@ export class CreateReservationComponent implements OnInit {
             r => {
                 this.resources.push(r);
 
-                this.startTime = Moment(new Date(
-                    this.dateLimiter.current.year,
-                    this.dateLimiter.current.month - 1,
-                    this.dateLimiter.current.day,
-                    13, 0, 0), 'Asia/Tokyo');
-                this.endTime = Moment(new Date(
-                    this.dateLimiter.current.year,
-                    this.dateLimiter.current.month - 1,
-                    this.dateLimiter.current.day,
-                    17, 0, 0), 'Asia/Tokyo');
+                this.dateLimiters.forEach((dl) => {
+                    this.startTime = Moment.tz([
+                        dl.current.year,
+                        dl.current.month - 1,
+                        dl.current.day, 9],
+                        'Asia/Tokyo');
+                    this.endTime = Moment.tz([
+                        dl.current.year,
+                        dl.current.month - 1,
+                        dl.current.day, 17],
+                        'Asia/Tokyo');
+                });
                 let currentTime = this.startTime;
                 while (currentTime < this.endTime) {
                     const existingRow = this.scheduleSource.data.findIndex((row) => row['time'] === currentTime.format('LT')) ;
index 8c011ea..fba3f0b 100644 (file)
@@ -19951,6 +19951,12 @@ VALUES (
         'Sticky setting for tab in Booking Return',
         'cwst', 'label')
 ), (
+    'eg.booking.create.granularity', 'gui', 'integer',
+    oils_i18n_gettext(
+        'booking.create.granularity',
+        'Sticky setting for granularity combobox in Booking Create',
+        'cwst', 'label')
+), (
     'eg.booking.pickup.ready.only_show_captured', 'gui', 'bool',
     oils_i18n_gettext(
         'booking.pickup.ready.only_show_captured',
index e47486e..e901ba5 100644 (file)
@@ -56,6 +56,12 @@ VALUES (
         'Sticky setting for tab in Booking Return',
         'cwst', 'label')
 ), (
+    'eg.booking.create.granularity', 'gui', 'integer',
+    oils_i18n_gettext(
+        'booking.create.granularity',
+        'Sticky setting for granularity combobox in Booking Create',
+        'cwst', 'label')
+), (
     'eg.booking.pickup.ready.only_show_captured', 'gui', 'bool',
     oils_i18n_gettext(
         'booking.pickup.ready.only_show_captured',