import {PullListComponent} from './pull-list.component';
import {ReturnComponent} from './return.component';
import {NoTimezoneSetComponent} from './no-timezone-set.component';
-import {PatronService} from '@eg/staff/share/patron.service';
+import {PatronModule} from '@eg/staff/share/patron/patron.module';
import {BookingResourceBarcodeValidatorDirective} from './booking_resource_validator.directive';
import {FmRecordEditorModule} from '@eg/share/fm-editor/fm-editor.module';
import {OrgFamilySelectModule} from '@eg/share/org-family-select/org-family-select.module';
BookingRoutingModule,
ReactiveFormsModule,
FmRecordEditorModule,
- OrgFamilySelectModule
+ OrgFamilySelectModule,
+ PatronModule
],
- providers: [PatronService],
declarations: [
CancelReservationDialogComponent,
CreateReservationComponent,
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
import {Subscription, of} from 'rxjs';
import {single, filter, switchMap, debounceTime, tap} from 'rxjs/operators';
-import {PatronService} from '@eg/staff/share/patron.service';
+import {PatronService} from '@eg/staff/share/patron/patron.service';
import {PcrudService} from '@eg/core/pcrud.service';
import {IdlObject} from '@eg/core/idl.service';
import {ReservationsGridComponent} from './reservations-grid.component';
import {NgbTabChangeEvent, NgbTabset} from '@ng-bootstrap/ng-bootstrap';
import {Observable, from, of, Subscription} from 'rxjs';
import { single, switchMap, tap, debounceTime } from 'rxjs/operators';
-import {PatronService} from '@eg/staff/share/patron.service';
+import {PatronService} from '@eg/staff/share/patron/patron.service';
import {PcrudService} from '@eg/core/pcrud.service';
import {IdlObject} from '@eg/core/idl.service';
import {ReservationsGridComponent} from './reservations-grid.component';
<eg-staff-banner bannerText="Sandbox" i18n-bannerText>
</eg-staff-banner>
+<div class="mt-4 mb-4">
+ <h4>Inline Patron Search Form</h4>
+ <eg-patron-search (patronsSelected)="patronSearchSelected($event)">
+ </eg-patron-search>
+</div>
+
<eg-title
i18n-prefix i18n-suffix
prefix=":) {{dynamicTitleText}}"
<eg-grid-column name="hook"></eg-grid-column>
</eg-grid>
</div>
+
+
printContext: 'default'
});
}
+
+ patronSearchSelected(selection: any) {
+ console.log('patron search selection', selection);
+ }
}
import {FmRecordEditorModule} from '@eg/share/fm-editor/fm-editor.module';
import {StaffCommonModule} from '@eg/staff/common.module';
import {TranslateModule} from '@eg/share/translate/translate.module';
+import {PatronModule} from '@eg/staff/share/patron/patron.module';
import {SandboxRoutingModule} from './routing.module';
import {SandboxComponent} from './sandbox.component';
import {ReactiveFormsModule} from '@angular/forms';
],
imports: [
StaffCommonModule,
+ PatronModule,
TranslateModule,
FmRecordEditorModule,
OrgFamilySelectModule,
+++ /dev/null
-import {Injectable} from '@angular/core';
-import {NetService} from '@eg/core/net.service';
-import {AuthService} from '@eg/core/auth.service';
-import {Observable} from 'rxjs';
-
-
-@Injectable()
-export class PatronService {
- constructor(
- private net: NetService,
- private auth: AuthService
- ) {}
-
- bcSearch(barcode: string): Observable<any> {
- return this.net.request(
- 'open-ils.actor',
- 'open-ils.actor.get_barcodes',
- this.auth.token(), this.auth.user().ws_ou(),
- 'actor', barcode.trim());
- }
-
-}
-
--- /dev/null
+import {NgModule} from '@angular/core';
+import {StaffCommonModule} from '@eg/staff/common.module';
+import {GridModule} from '@eg/share/grid/grid.module';
+import {PatronService} from './patron.service'
+import {PatronSearchComponent} from './search.component';
+
+@NgModule({
+ declarations: [
+ PatronSearchComponent
+ ],
+ imports: [
+ StaffCommonModule,
+ GridModule
+ ],
+ exports: [
+ PatronSearchComponent
+ ],
+ providers: [
+ PatronService
+ ]
+})
+
+export class PatronModule {}
+
--- /dev/null
+import {Injectable} from '@angular/core';
+import {NetService} from '@eg/core/net.service';
+import {AuthService} from '@eg/core/auth.service';
+import {Observable} from 'rxjs';
+
+
+@Injectable()
+export class PatronService {
+ constructor(
+ private net: NetService,
+ private auth: AuthService
+ ) {}
+
+ bcSearch(barcode: string): Observable<any> {
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.get_barcodes',
+ this.auth.token(), this.auth.user().ws_ou(),
+ 'actor', barcode.trim());
+ }
+
+}
+
--- /dev/null
+
+
+<div class="patron-search-form">
+ <div class="row">
+
+ <div class="col-lg-2">
+ <input class="form-control" type="text" id='focus-this-input'
+ i18n-aria-label aria-label="Last Name"
+ i18n-placeholder placeholder="Last Name"
+ [(ngModel)]="search.au.family_name"/>
+ </div>
+
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2">
+ <button class="btn btn-success" (click)="performSearch()" i18n>Search</button>
+ </div>
+ <div class="col-lg-2"></div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ <div class="col-lg-2"></div>
+ </div>
+</div>
+
+<div class="patron-search-grid">
+ <eg-grid #searchGrid idlClass="au" [dataSource]="dataSource"
+ [showDeclaredFieldsOnly]="true" persistKey="circ.patron.search">
+
+ <eg-grid-column path='id'></eg-grid-column>
+ <eg-grid-column path='card.barcode'></eg-grid-column>
+ <eg-grid-column path='profile.name'></eg-grid-column>
+ <eg-grid-column path='family_name' [sortable]="true" [multiSortable]="true">
+ </eg-grid-column>
+ <eg-grid-column path='first_given_name' [sortable]="true" [multiSortable]="true">
+ </eg-grid-column>
+ <eg-grid-column path='second_given_name' [sortable]="true" [multiSortable]="true">
+ </eg-grid-column>
+ <eg-grid-column path='dob' [sortable]="true" [multiSortable]="true">
+ </eg-grid-column>
+ <eg-grid-column path='home_ou.shortname' i18n-label label="Home Library">
+ </eg-grid-column>
+ <eg-grid-column path='create_date' i18n-label label="Created On"
+ [sortable]="true" [multiSortable]="true">
+ </eg-grid-column>
+
+ </eg-grid>
+</div>
--- /dev/null
+import {Component, Input, Output, OnInit, AfterViewInit,
+ EventEmitter, ViewChild, Renderer2} from '@angular/core';
+import {Observable, of} from 'rxjs';
+import {IdlService} from '@eg/core/idl.service';
+import {EventService} from '@eg/core/event.service';
+import {NetService} from '@eg/core/net.service';
+import {AuthService} from '@eg/core/auth.service';
+import {OrgService} from '@eg/core/org.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ComboboxEntry, ComboboxComponent} from '@eg/share/combobox/combobox.component';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {Pager} from '@eg/share/util/pager';
+
+@Component({
+ selector: 'eg-patron-search',
+ templateUrl: './search.component.html'
+})
+
+export class PatronSearchComponent implements OnInit, AfterViewInit {
+
+ @ViewChild('searchGrid', {static: false}) searchGrid: GridComponent;
+ @Output() patronsSelected: EventEmitter<any>;
+
+ search = {
+ au: {},
+ aua: {},
+ include_inactive: false
+ };
+
+ searchSort = [
+ "family_name ASC",
+ "first_given_name ASC",
+ "second_given_name ASC",
+ "dob DESC"
+ ];
+
+ searchFlesh = [
+ "card", "settings", "standing_penalties", "addresses",
+ "billing_address", "mailing_address", "stat_cat_entries",
+ "waiver_entries", "usr_activity", "notes", "profile"
+ ];
+
+ dataSource: GridDataSource;
+
+ constructor(
+ private renderer: Renderer2,
+ private net: NetService,
+ private org: OrgService,
+ private auth: AuthService
+ ) {
+ this.patronsSelected = new EventEmitter<any>();
+ this.dataSource = new GridDataSource();
+ this.dataSource.getRows = (pager: Pager, sort: any[]) => {
+ return this.getRows(pager, sort);
+ };
+ }
+
+ ngOnInit() {
+ }
+
+ ngAfterViewInit() {
+ this.renderer.selectRootElement('#focus-this-input').focus();
+ }
+
+ rowsSelected(rows: any) {
+ this.patronsSelected.emit(rows);
+ }
+
+ getRows(pager: Pager, sort: any[]): Observable<any> {
+
+ const search = this.compileSearch();
+ if (!search) { return of(); }
+
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.patron.search.advanced.fleshed',
+ this.auth.token(),
+ this.compileSearch(),
+ pager.limit,
+ this.searchSort,
+ null, // todo?
+ this.auth.user().ws_ou(),
+ this.searchFlesh,
+ pager.offset
+ );
+ }
+
+ isValue(val: any): boolean {
+ return (val !== null && val !== undefined && val !== '');
+ }
+
+ compileSearch(): any {
+
+ let hasSearch = false;
+ const search: Object = {};
+
+ Object.keys(this.search.au).forEach(field => {
+ const val = this.search.au[field];
+ if (this.isValue(val)) {
+ hasSearch = true;
+ search[field] = {value: val, group: 0}
+ }
+ });
+
+ return hasSearch ? search : null;
+ }
+
+ performSearch() {
+ this.searchGrid.reload();
+ }
+}
+