diff --git a/projects/admin/src/app/service/holdings.service.spec.ts b/projects/admin/src/app/service/holdings.service.spec.ts index 004b61724..63b5cb0c1 100644 --- a/projects/admin/src/app/service/holdings.service.spec.ts +++ b/projects/admin/src/app/service/holdings.service.spec.ts @@ -68,8 +68,8 @@ describe('HoldingsService', () => { }); it('should return true on the possibility of making a request', () => { - httpClientSpy.get.and.returnValue(of(true)); - service.canRequest('pid').subscribe((result: any) => expect(result).toBeTrue()); + httpClientSpy.get.and.returnValue(of({ can: true, reasons: {} })); + service.canRequest('pid').subscribe((result: any) => expect(result.can).toBeTrue()); }); it('should return a list of pickup locations', () => { diff --git a/projects/admin/src/app/service/items.service.spec.ts b/projects/admin/src/app/service/items.service.spec.ts index dcea9f190..6b9a15ad5 100644 --- a/projects/admin/src/app/service/items.service.spec.ts +++ b/projects/admin/src/app/service/items.service.spec.ts @@ -203,8 +203,8 @@ describe('ItemsService', () => { }); it('canRequest', () => { - httpClientSpy.get.and.returnValue(of(true)); - service.canRequest('1').subscribe((result: boolean) => expect(result).toBeTrue()); + httpClientSpy.get.and.returnValue(of({ can: true, reasons: {} })); + service.canRequest('1').subscribe((result: any) => expect(result.can).toBeTrue()); }); it('needCallout', () => { diff --git a/projects/public-holdings-items/src/app/app.module.ts b/projects/public-holdings-items/src/app/app.module.ts index 8965d5304..cb67faec2 100644 --- a/projects/public-holdings-items/src/app/app.module.ts +++ b/projects/public-holdings-items/src/app/app.module.ts @@ -50,7 +50,7 @@ import { HoldingsComponent } from 'projects/public-search/src/app/document-detai import { ItemsComponent } from 'projects/public-search/src/app/document-detail/holdings/items/items.component'; import { ItemComponent } from 'projects/public-search/src/app/document-detail/item/item.component'; import { PickupLocationComponent } from 'projects/public-search/src/app/document-detail/request/pickup-location/pickup-location.component'; -import { RequestComponent } from 'projects/public-search/src/app/document-detail/request/request.component'; +import { HoldingsRequestComponent } from 'projects/public-search/src/app/document-detail/request/holdings-request.component'; import { AppConfigService } from './app-config-service.service'; import { AppInitializerService } from './app-initializer.service'; import { ItemRequestComponent } from 'projects/public-search/src/app/document-detail/item/item-request.component'; @@ -88,7 +88,7 @@ import { ItemRequestComponent } from 'projects/public-search/src/app/document-de ItemComponent, ItemsComponent, PickupLocationComponent, - RequestComponent, + HoldingsRequestComponent, DocumentDetailViewComponent, ElectronicHoldingsComponent, ItemRequestComponent diff --git a/projects/public-search/src/app/api/item-api.service.spec.ts b/projects/public-search/src/app/api/item-api.service.spec.ts index 0221dc0ec..cb0ca2942 100644 --- a/projects/public-search/src/app/api/item-api.service.spec.ts +++ b/projects/public-search/src/app/api/item-api.service.spec.ts @@ -58,7 +58,7 @@ describe('ItemService', () => { const canRequest = { can: true, - reasons: [] + reasons: {} }; const request = { diff --git a/projects/public-search/src/app/api/loan-api.service.spec.ts b/projects/public-search/src/app/api/loan-api.service.spec.ts index efc96e880..5a1d29a75 100644 --- a/projects/public-search/src/app/api/loan-api.service.spec.ts +++ b/projects/public-search/src/app/api/loan-api.service.spec.ts @@ -51,7 +51,7 @@ describe('LoanApiService', () => { const canExtend = { can: true, - reasons: [] + reasons: {} }; const renew = { diff --git a/projects/public-search/src/app/api/loan-api.service.ts b/projects/public-search/src/app/api/loan-api.service.ts index a17d93236..cf8b36d7b 100644 --- a/projects/public-search/src/app/api/loan-api.service.ts +++ b/projects/public-search/src/app/api/loan-api.service.ts @@ -17,7 +17,7 @@ import { HttpClient } from '@angular/common/http'; import { inject, Injectable } from '@angular/core'; import { LoanOverduePreview } from '@app/admin/classes/loans'; -import { ApiService, Error, Record, RecordService } from '@rero/ng-core'; +import { ApiService, Error, Record as EsRecord, RecordService } from '@rero/ng-core'; import { BaseApi } from '@rero/shared'; import { Observable, of } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; @@ -43,7 +43,7 @@ export class LoanApiService extends BaseApi { patronPid: string, page: number, itemsPerPage = 20, headers = BaseApi.reroJsonheaders, sort?: string - ): Observable { + ): Observable { const loanStates = ['ITEM_ON_LOAN']; return this.recordService.getRecords( 'loans', this._patronStateQuery(patronPid, loanStates), page, itemsPerPage, @@ -62,7 +62,7 @@ export class LoanApiService extends BaseApi { getRequest( patronPid: string, page: number, itemsPerPage = 10, headers = BaseApi.reroJsonheaders - ): Observable { + ): Observable { const requestStates = ['PENDING', 'ITEM_AT_DESK', 'ITEM_IN_TRANSIT_FOR_PICKUP']; return this.recordService.getRecords( 'loans', this._patronStateQuery(patronPid, requestStates), page, itemsPerPage, @@ -141,5 +141,5 @@ export class LoanApiService extends BaseApi { export type CanExtend = { can: boolean; - reasons: string[]; + reasons: Record; } diff --git a/projects/public-search/src/app/document-detail/holdings/holdings.component.ts b/projects/public-search/src/app/document-detail/holdings/holdings.component.ts index 930f182e4..94abdcf13 100644 --- a/projects/public-search/src/app/document-detail/holdings/holdings.component.ts +++ b/projects/public-search/src/app/document-detail/holdings/holdings.component.ts @@ -24,7 +24,7 @@ import { ButtonDirective } from 'primeng/button'; import { Message } from 'primeng/message'; import { Ripple } from 'primeng/ripple'; import { HoldingsApiService } from '../../api/holdings-api.service'; -import { RequestComponent } from '../request/request.component'; +import { HoldingsRequestComponent } from '../request/holdings-request.component'; import { HoldingsStore } from '../store/holdings-store'; import { ItemsComponent } from './items/items.component'; import { MultiSelect } from 'primeng/multiselect'; @@ -32,7 +32,7 @@ import { MultiSelect } from 'primeng/multiselect'; @Component({ selector: 'public-search-holdings', templateUrl: './holdings.component.html', - imports: [Message, Accordion, AccordionPanel, Ripple, AccordionHeader, SharedModule, TranslateDirective, AccordionContent, ItemsComponent, RequestComponent, NgClass, ButtonDirective, I18nPluralPipe, TranslatePipe, CoreModule, MultiSelect], + imports: [Message, Accordion, AccordionPanel, Ripple, AccordionHeader, SharedModule, TranslateDirective, AccordionContent, ItemsComponent, HoldingsRequestComponent, NgClass, ButtonDirective, I18nPluralPipe, TranslatePipe, CoreModule, MultiSelect], providers: [HoldingsStore] }) export class HoldingsComponent implements OnInit { diff --git a/projects/public-search/src/app/document-detail/item/item-request.component.ts b/projects/public-search/src/app/document-detail/item/item-request.component.ts index 5f7d1804b..02410eb7a 100644 --- a/projects/public-search/src/app/document-detail/item/item-request.component.ts +++ b/projects/public-search/src/app/document-detail/item/item-request.component.ts @@ -29,7 +29,7 @@ import { canRequest } from '../model/can-request-model'; ({ can: false }); - tooltip = computed(() => this.canRequest().reasons?.map( - (reason: string) => this.translateService.instant(reason) - ).join('\n\n')); + reasonsToDisplay = [ + "patron_type_overdue_items_limit", + "patron_type_fee_amount_limit", + "patron_type_unpaid_subscription", + "patron_type_request_limits" + ] + + allReasonsDisplayable = computed(() => + this.canRequest().reasons && + Object.keys(this.canRequest().reasons).every(key => this.reasonsToDisplay.includes(key)) + ); + + hiddenRequestButton = computed(() => this.canRequest().can || this.allReasonsDisplayable()); + + tooltip = computed(() => Object.values(this.canRequest().reasons || {}).map( + (reason: string) => "- " + this.translateService.instant(reason) + ).join('\n')); private _patron: IPatron; diff --git a/projects/public-search/src/app/document-detail/model/can-request-model.ts b/projects/public-search/src/app/document-detail/model/can-request-model.ts index 468b4a077..910ebce18 100644 --- a/projects/public-search/src/app/document-detail/model/can-request-model.ts +++ b/projects/public-search/src/app/document-detail/model/can-request-model.ts @@ -16,5 +16,5 @@ */ export type canRequest = { can: boolean; - reasons?: string[]; + reasons?: Record; } diff --git a/projects/public-search/src/app/document-detail/request/request.component.html b/projects/public-search/src/app/document-detail/request/holdings-request.component.html similarity index 79% rename from projects/public-search/src/app/document-detail/request/request.component.html rename to projects/public-search/src/app/document-detail/request/holdings-request.component.html index 66f4d8b54..54dc79a58 100644 --- a/projects/public-search/src/app/document-detail/request/request.component.html +++ b/projects/public-search/src/app/document-detail/request/holdings-request.component.html @@ -22,17 +22,17 @@ id="record-{{ record.metadata.pid }}-request-button" outlined (onClick)="showRequestDialog()" - [hidden]="!canRequest?.can" + [hidden]="!hiddenRequestButton()" + [disabled]="!canRequest().can" + [tooltipDisabled]="canRequest().can" + [pTooltip]="tooltip()" + tooltipPosition="top" > - @if (recordType === 'item') { - {{ 'Request' | translate }} + @if (holdingsItemsCount > 0) { + {{ 'Request another issue' | translate }} } @else { - @if (holdingsItemsCount > 0) { - {{ 'Request another issue' | translate }} - } @else { - {{ 'Request an issue' | translate }} - } + {{ 'Request an issue' | translate }} } } @else { diff --git a/projects/public-search/src/app/document-detail/request/request.component.ts b/projects/public-search/src/app/document-detail/request/holdings-request.component.ts similarity index 71% rename from projects/public-search/src/app/document-detail/request/request.component.ts rename to projects/public-search/src/app/document-detail/request/holdings-request.component.ts index a669ccc78..949ac042d 100644 --- a/projects/public-search/src/app/document-detail/request/request.component.ts +++ b/projects/public-search/src/app/document-detail/request/holdings-request.component.ts @@ -14,25 +14,27 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, inject, Input, OnInit, Output, signal, computed } from '@angular/core'; import { IPatron, UserService, SharedModule } from '@rero/shared'; import { ItemApiService } from '../../api/item-api.service'; import { HoldingsApiService } from '../../api/holdings-api.service'; import { Button } from 'primeng/button'; import { Tooltip } from 'primeng/tooltip'; import { PickupLocationComponent } from './pickup-location/pickup-location.component'; -import { TranslatePipe } from '@ngx-translate/core'; +import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { canRequest } from '../model/can-request-model'; @Component({ selector: 'public-search-request', - templateUrl: './request.component.html', + templateUrl: './holdings-request.component.html', imports: [Button, Tooltip, PickupLocationComponent, TranslatePipe, SharedModule] }) -export class RequestComponent implements OnInit { +export class HoldingsRequestComponent implements OnInit { private itemApiService: ItemApiService = inject(ItemApiService); private holdingsApiService: HoldingsApiService = inject(HoldingsApiService); private userService: UserService = inject(UserService); + private translateService: TranslateService = inject(TranslateService); /** Record: item or holding */ @Input() record: any; @@ -47,10 +49,25 @@ export class RequestComponent implements OnInit { @Input() holdingsItemsCount: number; /** Item Can request with reason(s) */ - canRequest = { - can: false, - reasons: [] - }; + canRequest = signal({ can: false, reasons: {} }); + + reasonsToDisplay = [ + "patron_type_overdue_items_limit", + "patron_type_fee_amount_limit", + "patron_type_unpaid_subscription", + "patron_type_request_limits" + ] + + allReasonsDisplayable = computed(() => + this.canRequest().reasons && + Object.keys(this.canRequest().reasons).every(key => this.reasonsToDisplay.includes(key)) + ); + + hiddenRequestButton = computed(() => this.canRequest().can || this.allReasonsDisplayable()); + + tooltip = computed(() => Object.values(this.canRequest().reasons || {}).map( + (reason: string) => "- " + this.translateService.instant(reason) + ).join('\n')); /** Request dialog */ requestDialog = false; @@ -84,7 +101,7 @@ export class RequestComponent implements OnInit { this.record.metadata.pid, this.record.metadata.library.pid, this._patron.patron.barcode[0], - ).subscribe((can: any) => this.canRequest = can); + ).subscribe((can: canRequest) => this.canRequest.set(can)); } } } diff --git a/projects/public-search/src/app/patron-profile/patron-profile-loans/patron-profile-loan/patron-profile-loan.component.html b/projects/public-search/src/app/patron-profile/patron-profile-loans/patron-profile-loan/patron-profile-loan.component.html index 92666db79..ecf3ddda6 100644 --- a/projects/public-search/src/app/patron-profile/patron-profile-loans/patron-profile-loan/patron-profile-loan.component.html +++ b/projects/public-search/src/app/patron-profile/patron-profile-loans/patron-profile-loan/patron-profile-loan.component.html @@ -49,7 +49,7 @@