From: Bill Erickson Date: Thu, 1 Apr 2021 16:28:27 +0000 (-0400) Subject: LP1904036 Hold notify mods X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=9e8416ef2510193b208d1c495c7d675a28bb61cc;p=working%2FEvergreen.git LP1904036 Hold notify mods Signed-off-by: Bill Erickson Signed-off-by: Jane Sandberg Signed-off-by: Galen Charlton --- diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.html index e052f0c7f4..d8951c840f 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.html +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.html @@ -24,6 +24,8 @@ i18n-dialogBody dialogBody="An address is required during registration"> + +
diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts index 7471da3ed5..45ee036287 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts @@ -1,5 +1,6 @@ import {Component, OnInit, AfterViewInit, Input, ViewChild} from '@angular/core'; import {Router, ActivatedRoute, ParamMap} from '@angular/router'; +import {empty, from} from 'rxjs'; import {concatMap, tap} from 'rxjs/operators'; import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap'; import {OrgService} from '@eg/core/org.service'; @@ -21,6 +22,7 @@ import {ServerStoreService} from '@eg/core/server-store.service'; import {EditToolbarComponent, VisibilityLevel} from './edit-toolbar.component'; import {PatronSearchFieldSet} from '@eg/staff/share/patron/search.component'; import {AlertDialogComponent} from '@eg/share/dialog/alert.component'; +import {HoldNotifyUpdateDialogComponent} from './hold-notify-update.component'; const COMMON_USER_SETTING_TYPES = [ 'circ.holds_behind_desk', @@ -28,7 +30,7 @@ const COMMON_USER_SETTING_TYPES = [ 'opac.hold_notify', 'opac.default_phone', 'opac.default_pickup_location', - 'opac.default_sms_carrier', + 'opac.default_sms_carrier_id', 'opac.default_sms_notify' ]; @@ -122,6 +124,8 @@ export class EditComponent implements OnInit, AfterViewInit { private profileSelect: ProfileSelectComponent; @ViewChild('secondaryGroupsDialog') private secondaryGroupsDialog: SecondaryGroupsDialogComponent; + @ViewChild('holdNotifyUpdateDialog') + private holdNotifyUpdateDialog: HoldNotifyUpdateDialogComponent; @ViewChild('addrAlert') private addrAlert: AlertDialogComponent; @ViewChild('addrRequiredAlert') private addrRequiredAlert: AlertDialogComponent; @@ -160,6 +164,18 @@ export class EditComponent implements OnInit, AfterViewInit { fieldVisibility: {[key: string]: FieldVisibility} = {}; + holdNotifyValues = { + day_phone: null, + other_phone: null, + evening_phone: null, + default_phone: null, + default_sms: null, + default_sms_carrier_id: null, + phone_notify: false, + email_notify: false, + sms_notify: false + }; + // All locations we have the specified permissions permOrgs: {[name: string]: number[]}; @@ -348,7 +364,6 @@ export class EditComponent implements OnInit, AfterViewInit { this.fieldDoc[doc.fm_class()] = {}; } this.fieldDoc[doc.fm_class()][doc.field()] = doc.string(); - console.log(this.fieldDoc); })).toPromise(); } @@ -495,28 +510,49 @@ export class EditComponent implements OnInit, AfterViewInit { } absorbPatronData() { + + const usets = this.userSettings; + let setting; + + this.holdNotifyValues.day_phone = this.patron.day_phone(); + this.holdNotifyValues.other_phone = this.patron.other_phone(); + this.holdNotifyValues.evening_phone = this.patron.evening_phone(); + this.patron.settings().forEach(setting => { const value = setting.value(); if (value !== '' && value !== null) { - this.userSettings[setting.name()] = JSON.parse(value); + usets[setting.name()] = JSON.parse(value); } }); - const holdNotify = this.userSettings['opac.hold_notify']; + const holdNotify = usets['opac.hold_notify']; + if (holdNotify) { - this.holdNotifyTypes.email = holdNotify.match(/email/) !== null; - this.holdNotifyTypes.phone = holdNotify.match(/phone/) !== null; - this.holdNotifyTypes.sms = holdNotify.match(/sms/) !== null; + this.holdNotifyTypes.email = this.holdNotifyValues.email_notify + = holdNotify.match(/email/) !== null; + + this.holdNotifyTypes.phone = this.holdNotifyValues.phone_notify + = holdNotify.match(/phone/) !== null; + + this.holdNotifyTypes.sms = this.holdNotifyValues.sms_notify + = holdNotify.match(/sms/) !== null; + } + + if (setting = usets['opac.default_sms_carrier_id']) { + setting = usets['opac.default_sms_carrier_id'] = Number(setting); + this.holdNotifyValues.default_sms_carrier_id = setting; } - if (this.userSettings['opac.default_sms_carrier']) { - this.userSettings['opac.default_sms_carrier'] = - Number(this.userSettings['opac.default_sms_carrier']); + if (setting = usets['opac.default_phone']) { + this.holdNotifyValues.default_phone = setting; } - if (this.userSettings['opac.default_pickup_location']) { - this.userSettings['opac.default_pickup_location'] = - Number(this.userSettings['opac.default_pickup_location']); + if (setting = usets['opac.default_sms_notify']) { + this.holdNotifyValues.default_sms = setting; + } + + if (setting = usets['opac.default_pickup_location']) { + usets['opac.default_pickup_location'] = Number(setting); } this.expireDate = new Date(this.patron.expire_date()); @@ -574,6 +610,8 @@ export class EditComponent implements OnInit, AfterViewInit { this.patron = patron; } + + objectFromPath(path: string, index: number): IdlObject { const base = path ? this.patron[path]() : this.patron; if (index === null || index === undefined) { @@ -648,15 +686,6 @@ export class EditComponent implements OnInit, AfterViewInit { userSettingChange(name: string, value: any) { this.userSettings[name] = value; - - switch (name) { - case 'opac.default_phone': - case 'opac.default_sms_notify': - case 'opac.default_sms_carrier': - // TODO hold related contact info updated - break; - } - this.adjustSaveSate(); } @@ -776,7 +805,6 @@ export class EditComponent implements OnInit, AfterViewInit { handlePhoneChange(field: string, value: string) { this.dupeValueChange(field, value); - // TODO: hold contact info stuff const pwUsePhone = this.context.settingsCache['patron.password.use_phone']; @@ -1167,6 +1195,7 @@ export class EditComponent implements OnInit, AfterViewInit { this.loading = true; return this.saveUser() .then(_ => this.saveUserSettings()) + .then(_ => this.updateHoldPrefs()) .then(_ => this.postSaveRedirect()); } @@ -1236,6 +1265,66 @@ export class EditComponent implements OnInit, AfterViewInit { ).toPromise(); } + + updateHoldPrefs(): Promise { + if (this.patron.isnew()) { return Promise.resolve(); } + + return this.collectHoldNotifyChange() + .then(mods => { + if (mods.length === 0) { return Promise.resolve(); } + + this.holdNotifyUpdateDialog.smsCarriers = this.smsCarriers; + this.holdNotifyUpdateDialog.mods = mods; + + return this.holdNotifyUpdateDialog.open().toPromise(); + }); + } + + // Compare current values with those collected at patron load time. + // For any that have changed, ask the server if the original values + // are used on active holds. + collectHoldNotifyChange(): Promise { + const mods = []; + const holdNotify = this.userSettings['opac.hold_notify'] || ''; + + return from(Object.keys(this.holdNotifyValues)) + .pipe(concatMap(field => { + + let newValue, matches; + + if (field.match(/default_/)) { + newValue = this.userSettings[`opac.${field}`] || null; + + } else if (field.match(/_phone/)) { + newValue = this.patron[field](); + + } else if (matches = field.match(/(\w+)_notify/)) { + newValue = this.userSettings['opac.hold_notify'].match(matches[1]) !== null; + } + + const oldValue = this.holdNotifyValues[field]; + + // No change to apply? + if (newValue === oldValue) { return empty(); } + + return this.net.request( + 'open-ils.circ', + 'open-ils.circ.holds.retrieve_by_notify_staff', + this.auth.token(), this.patronId, newValue, field + ).pipe(tap(holds => { + if (holds && holds.length > 0) { + mods.push({ + field: field, + newValue: newValue, + oldValue: oldValue, + holds: holds + }); + }; + })); + })).toPromise().then(_ => mods); + } + + printPatron() { // TODO } diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/hold-notify-update.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/hold-notify-update.component.html new file mode 100644 index 0000000000..3c8236eee7 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/hold-notify-update.component.html @@ -0,0 +1,44 @@ + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/hold-notify-update.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/hold-notify-update.component.ts new file mode 100644 index 0000000000..41e73e426b --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/hold-notify-update.component.ts @@ -0,0 +1,72 @@ +import {Component, OnInit, Input, ViewChild} from '@angular/core'; +import {Observable, empty} from 'rxjs'; +import {switchMap, tap} from 'rxjs/operators'; +import {IdlObject, IdlService} from '@eg/core/idl.service'; +import {NetService} from '@eg/core/net.service'; +import {EventService} from '@eg/core/event.service'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {AuthService} from '@eg/core/auth.service'; +import {OrgService} from '@eg/core/org.service'; +import {DialogComponent} from '@eg/share/dialog/dialog.component'; +import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; +import {StringComponent} from '@eg/share/string/string.component'; +import {ComboboxEntry} from '@eg/share/combobox/combobox.component'; + +/* Apply notification changes to affected holds */ + +export interface HoldNotifyMod { + field: string, + newValue: any, + oldValue: any, + holds: any[] +} + +@Component({ + selector: 'eg-hold-notify-update-dialog', + templateUrl: 'hold-notify-update.component.html' +}) + +export class HoldNotifyUpdateDialogComponent + extends DialogComponent implements OnInit { + + // Values provided directly by our parent component + smsCarriers: ComboboxEntry[]; + mods: HoldNotifyMod[] = []; + + selected: {[field: string]: boolean} = {}; + + constructor( + private modal: NgbModal, + private toast: ToastService, + private net: NetService, + private idl: IdlService, + private evt: EventService, + private pcrud: PcrudService, + private org: OrgService, + private auth: AuthService) { + super(modal); + } + + applyChanges() { + } + + isPhoneChange(mod: HoldNotifyMod): boolean { + return mod.field.match(/_phone/) !== null; + } + + isBoolChange(mod: HoldNotifyMod): boolean { + return mod.field.match(/_notify/) !== null && !this.isCarrierChange(mod); + } + + isCarrierChange(mod: HoldNotifyMod): boolean { + return mod.field.match(/carrier/) !== null; + } + + carrierName(id: number): string { + const entry = this.smsCarriers.filter(e => e.id === id)[0]; + return entry ? entry.label : ''; + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.module.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.module.ts index 439059fc53..2b2d45069e 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/patron.module.ts @@ -29,6 +29,7 @@ import {PatronGroupComponent} from './group.component'; import {RegisterPatronComponent} from './register.component'; import {SecondaryGroupsDialogComponent} from './secondary-groups.component'; import {PatronBarcodesDialogComponent} from './barcodes.component'; +import {HoldNotifyUpdateDialogComponent} from './hold-notify-update.component'; @NgModule({ declarations: [ @@ -49,7 +50,8 @@ import {PatronBarcodesDialogComponent} from './barcodes.component'; RegisterPatronComponent, PatronStatCatsComponent, PatronBarcodesDialogComponent, - SecondaryGroupsDialogComponent + SecondaryGroupsDialogComponent, + HoldNotifyUpdateDialogComponent ], imports: [ StaffCommonModule,