From a5ea4ce2b564eb82d882d9dc378a09fcb3ddd499 Mon Sep 17 00:00:00 2001 From: Renaud Michotte Date: Mon, 8 Jun 2020 09:51:54 +0200 Subject: [PATCH] circulation: display circulation notes automatically. When circulation operations are done, if item contains the corresponding circulation note, this note will be displayed as a permanent toastr message. * refactoring item circulation collapsed informations design. * adds postprocessRecord behavior to avoid empty notes array on item. Co-authored-by : Renaud Michotte --- .../circulation/checkin/checkin.component.ts | 38 +++++++--- .../app/circulation/item/item.component.html | 73 +++++++++++++------ projects/admin/src/app/circulation/items.ts | 29 ++++++++ .../circulation/patron/loan/loan.component.ts | 28 ++++++- projects/admin/src/app/routes/items-route.ts | 7 ++ projects/admin/src/app/scss/styles.scss | 4 +- 6 files changed, 140 insertions(+), 39 deletions(-) diff --git a/projects/admin/src/app/circulation/checkin/checkin.component.ts b/projects/admin/src/app/circulation/checkin/checkin.component.ts index 046b65611..e18ff0be4 100644 --- a/projects/admin/src/app/circulation/checkin/checkin.component.ts +++ b/projects/admin/src/app/circulation/checkin/checkin.component.ts @@ -22,10 +22,10 @@ import { RecordService } from '@rero/ng-core'; import { ToastrService } from 'ngx-toastr'; import { map } from 'rxjs/operators'; import { User } from '../../class/user'; +import { ItemsService } from '../../service/items.service'; import { PatronService } from '../../service/patron.service'; import { UserService } from '../../service/user.service'; -import { ItemAction, ItemStatus } from '../items'; -import { ItemsService } from '../../service/items.service'; +import { Item, ItemAction, ItemNoteType, ItemStatus } from '../items'; @Component({ selector: 'admin-circulation-checkout', @@ -56,7 +56,7 @@ export class CheckinComponent implements OnInit { * @param _itemsService: Items Service * @param _router: Router * @param _translate: Translate Service - * @param toastService: Toastr Service + * @param _toastService: Toastr Service * @param _patronService: Patron Service */ constructor( @@ -122,6 +122,7 @@ export class CheckinComponent implements OnInit { ); break; case ItemAction.checkin: + this._displayCirculationNote(item, ItemNoteType.CHECKIN); if (item.action_applied.checkin) { this.getPatronInfo(item.action_applied.checkin.patron.barcode); } @@ -173,14 +174,8 @@ export class CheckinComponent implements OnInit { this._recordService .getRecords('patrons', `barcode:${barcode}`, 1, 1) .pipe( - map((response: any) => { - if (response.hits.total === 0) { - return null; - } - return response.hits.hits[0].metadata; - }) - ) - .subscribe( + map((response: any) => (response.hits.total === 0) ? null : response.hits.hits[0].metadata) + ).subscribe( patron => { if ( patron !== null && @@ -218,6 +213,27 @@ export class CheckinComponent implements OnInit { ); } } + + /** display a circulation note about an item as a permanent toastr message + * + * @param item: the item + * @param noteType: the note type to display + */ + private _displayCirculationNote(item: Item, noteType: ItemNoteType): void { + const note = item.getNote(noteType); + if (note != null) { + this._toastService.warning( + note.content, + `${this._translate.instant('item')} [${item.barcode}]`, + { + closeButton: true, // add a close button to the toastr message + disableTimeOut: true, // permanent toastr message (until click on 'close' button) + tapToDismiss: false // toastr message only close when click on the 'close' button. + } + ); + } + } + hasFees(event: boolean) { if (event) { this._toastService.error( diff --git a/projects/admin/src/app/circulation/item/item.component.html b/projects/admin/src/app/circulation/item/item.component.html index a8d0a9f56..1ba2be76d 100644 --- a/projects/admin/src/app/circulation/item/item.component.html +++ b/projects/admin/src/app/circulation/item/item.component.html @@ -15,12 +15,14 @@  along with this program. If not, see . --> -
+
-
+
-
-
    -
  • {{ 'Location' | translate }}: - {{ item.loan.pickup_location_pid | getRecord: 'locations' : 'field' : 'code' | async }} {{ item.location.name }} -
  • -
  • {{ 'Renewals' | translate }}: {{ item.loan.extension_count }} -
  • -
  • {{ 'Fees' | translate }}: - {{ totalAmountOfFee | currency: organisation.default_currency }}
  • +
    +
    + +
    Location
    +
    + {{ item.loan.pickup_location_pid | getRecord: 'locations' : 'field' : 'code' | async }} {{ item.location.name }} +
    +
    + +
    Renewals
    +
    {{ item.loan.extension_count }}
    +
    + +
    Fees
    +
    {{ totalAmountOfFee | currency: organisation.default_currency }}
    +
    -
  • {{ 'Notifications' | translate }}: -
      -
    • - {{ notification.metadata.process_date | dateTranslate :'shortDate' }}: - {{ notification.metadata.notification_type | translate}}
    • -
    -
  • + +
    Notifications
    +
    +
      +
    • + {{ notification.metadata.process_date | dateTranslate :'shortDate' }}: + {{ notification.metadata.notification_type | translate }} +
    • +
    +
    +
    -
  • {{ 'Requests' | translate }}: {{ item.pending_loans.length }}
  • -
  • {{ 'For' | translate }}: {{ item.pending_loans[0].patron.name }}
  • -
+ +
Requests
+
{{ item.pending_loans.length }}
+
For
+
{{ item.pending_loans[0].patron.name }}
+
+ +
{{ note.type | translate }}
+
{{ note.content }}
+
+ +
{{ note.type | translate }}
+
{{ note.content }}
+
+
diff --git a/projects/admin/src/app/circulation/items.ts b/projects/admin/src/app/circulation/items.ts index 4f4b777f9..cc7b8136b 100644 --- a/projects/admin/src/app/circulation/items.ts +++ b/projects/admin/src/app/circulation/items.ts @@ -37,6 +37,13 @@ export enum ItemStatus { MISSING = _('missing') } +export enum ItemNoteType { + PUBLIC = _('public_note'), + STAFF = _('staff_note'), + CHECKIN = _('checkin_note'), + CHECKOUT = _('checkout_note') +} + export enum LoanState { CREATED = _('CREATED'), PENDING = _('PENDING'), @@ -117,6 +124,12 @@ export class Loan { return false; } } + +export class ItemNote { + type: ItemNoteType; + content: string; +} + export class Item { available: boolean; barcode: string; @@ -134,6 +147,7 @@ export class Item { pending_loans: Loan[]; number_of_extensions: number; location: any; + notes: ItemNote[]; constructor(obj?: any) { Object.assign(this, obj); @@ -176,4 +190,19 @@ export class Item { public get hasRequests() { return (this.pending_loans && this.pending_loans.length > 0); } + + /** Search on item notes a note corresponding to the note type + * + * @param type: the note type + * @return Return the corresponding note or null if not found + */ + public getNote(type: ItemNoteType): ItemNote | null { + if (this.notes == null) { + return null; + } + const filteredNotes = this.notes.filter(note => note.type === type); + return (filteredNotes) + ? filteredNotes[0] + : null; + } } diff --git a/projects/admin/src/app/circulation/patron/loan/loan.component.ts b/projects/admin/src/app/circulation/patron/loan/loan.component.ts index cf334baa4..eb9aa933d 100644 --- a/projects/admin/src/app/circulation/patron/loan/loan.component.ts +++ b/projects/admin/src/app/circulation/patron/loan/loan.component.ts @@ -20,11 +20,11 @@ import { TranslateService } from '@ngx-translate/core'; import { ToastrService } from 'ngx-toastr'; import { forkJoin } from 'rxjs'; import { User } from '../../../class/user'; +import { PatronBlockedMessagePipe } from '../../../pipe/patron-blocked-message.pipe'; +import { ItemsService } from '../../../service/items.service'; import { PatronService } from '../../../service/patron.service'; import { UserService } from '../../../service/user.service'; -import { Item, ItemAction, ItemStatus } from '../../items'; -import { ItemsService } from '../../../service/items.service'; -import { PatronBlockedMessagePipe } from '../../../pipe/patron-blocked-message.pipe'; +import { Item, ItemAction, ItemNoteType, ItemStatus } from '../../items'; @Component({ selector: 'admin-loan', @@ -186,11 +186,13 @@ export class LoanComponent implements OnInit { newItems.map(newItem => { switch (newItem.actionDone) { case ItemAction.checkin: { + this._displayCirculationNote(newItem, ItemNoteType.CHECKIN); this.checkedOutItems = this.checkedOutItems.filter(currItem => currItem.pid !== newItem.pid); this.checkedInItems.unshift(newItem); break; } case ItemAction.checkout: { + this._displayCirculationNote(newItem, ItemNoteType.CHECKOUT); this.checkedOutItems.unshift(newItem); this.checkedInItems = this.checkedInItems.filter(currItem => currItem.pid !== newItem.pid); break; @@ -236,6 +238,26 @@ export class LoanComponent implements OnInit { ); } + /** display a circulation note about an item as a permanent toastr message + * + * @param item: the item + * @param noteType: the note type to display + */ + private _displayCirculationNote(item: Item, noteType: ItemNoteType): void { + const note = item.getNote(noteType); + if (note != null) { + this._toastService.warning( + note.content, + `${this._translate.instant('item')} [${item.barcode}]`, + { + closeButton: true, // add a close button to the toastr message + disableTimeOut: true, // permanent toastr message (until click on 'close' button) + tapToDismiss: false // toastr message only close when click on the 'close' button. + } + ); + } + } + hasFees(event: boolean) { if (event) { this._toastService.error( diff --git a/projects/admin/src/app/routes/items-route.ts b/projects/admin/src/app/routes/items-route.ts index 25be6d535..5d19e040e 100644 --- a/projects/admin/src/app/routes/items-route.ts +++ b/projects/admin/src/app/routes/items-route.ts @@ -70,6 +70,13 @@ export class ItemsRoute extends BaseRoute implements RouteInterface { } return data; }, + postprocessRecordEditor: (record: any) => { + // If we try to save an item with without any notes, then remove the empty array notes array from record + if (record.notes && record.notes.length === 0) { + delete record.notes; + } + return record; + }, formFieldMap: (field: FormlyFieldConfig, jsonSchema: JSONSchema7): FormlyFieldConfig => { return this.populateLocationsByCurrentUserLibrary( field, jsonSchema diff --git a/projects/admin/src/app/scss/styles.scss b/projects/admin/src/app/scss/styles.scss index 93e683f2b..884ef1327 100644 --- a/projects/admin/src/app/scss/styles.scss +++ b/projects/admin/src/app/scss/styles.scss @@ -74,7 +74,9 @@ header { content: " \f08e"; } - +.toast-container .ngx-toastr { + width: 450px !important; // override width for all toastr message +} json-schema-form { input.ng-valid,