diff --git a/src/app/shared/menu/providers/comcol-subscribe.menu.spec.ts b/src/app/shared/menu/providers/comcol-subscribe.menu.spec.ts index 3c1cf2c189d..2416f77d09a 100644 --- a/src/app/shared/menu/providers/comcol-subscribe.menu.spec.ts +++ b/src/app/shared/menu/providers/comcol-subscribe.menu.spec.ts @@ -1,48 +1,54 @@ +import { PLATFORM_ID } from '@angular/core'; import { TestBed } from '@angular/core/testing'; +import { AuthService } from '@dspace/core/auth/auth.service'; import { AuthorizationDataService } from '@dspace/core/data/feature-authorization/authorization-data.service'; +import { SubscriptionsDataService } from '@dspace/core/data/subscriptions-data.service'; import { Collection } from '@dspace/core/shared/collection.model'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; import { of } from 'rxjs'; import { MenuItemType } from '../menu-item-type.model'; -import { PartialMenuSection } from '../menu-provider.model'; import { SubscribeMenuProvider } from './comcol-subscribe.menu'; describe('SubscribeMenuProvider', () => { - const expectedSections: PartialMenuSection[] = [ - { - visible: true, - model: { - type: MenuItemType.ONCLICK, - text: 'subscriptions.tooltip', - function: jasmine.any(Function) as any, - }, - icon: 'bell', - }, - ]; - let provider: SubscribeMenuProvider; - const dso: Collection = Object.assign(new Collection(), { _links: { self: { href: 'self-link' } } }); - + const dso: Collection = Object.assign(new Collection(), { + uuid: 'mock-uuid', + _links: { self: { href: 'self-link' } }, + }); let authorizationService; let modalService; + let authService; + let subscriptionsDataService; beforeEach(() => { - authorizationService = jasmine.createSpyObj('authorizationService', { - 'isAuthorized': of(true), + isAuthorized: of(true), }); modalService = jasmine.createSpyObj('modalService', ['open']); + authService = jasmine.createSpyObj('authService', { + getAuthenticatedUserFromStore: of({ id: 'mock-user-id' }), + }); + + subscriptionsDataService = jasmine.createSpyObj('subscriptionsDataService', { + getSubscriptionsByPersonDSO: of({ payload: { page: [] } }), + }); + TestBed.configureTestingModule({ providers: [ SubscribeMenuProvider, { provide: AuthorizationDataService, useValue: authorizationService }, { provide: NgbModal, useValue: modalService }, + { provide: AuthService, useValue: authService }, + { provide: SubscriptionsDataService, useValue: subscriptionsDataService }, + { provide: TranslateService, useValue: {} }, + { provide: PLATFORM_ID, useValue: 'browser' }, ], }); provider = TestBed.inject(SubscribeMenuProvider); @@ -53,13 +59,32 @@ describe('SubscribeMenuProvider', () => { }); describe('getSectionsForContext', () => { - it('should return the expected sections', (done) => { - provider.getSectionsForContext(dso).subscribe((sections) => { - expect(sections).toEqual(expectedSections); - done(); - }); + it('should return subscribe section when user has no subscription', (done) => { + provider.getSectionsForContext(dso) + .pipe() + .subscribe((sections) => { + if (sections.length > 0 && sections[0].visible) { + expect(sections[0].model.type).toBe(MenuItemType.ONCLICK); + expect((sections[0].model as any).text).toBe('subscriptions.tooltip'); + expect(sections[0].icon).toBe('bell'); + done(); + } + }); }); - }); + it('should return manage subscription section when user is already subscribed', (done) => { + subscriptionsDataService.getSubscriptionsByPersonDSO.and.returnValue( + of({ payload: { page: [{ id: 'sub-1' }] } }), + ); + provider.getSectionsForContext(dso) + .pipe() + .subscribe((sections) => { + if (sections.length > 0 && sections[0].visible) { + expect((sections[0].model as any).text).toBe('subscriptions.manage'); + done(); + } + }); + }); + }); }); diff --git a/src/app/shared/menu/providers/comcol-subscribe.menu.ts b/src/app/shared/menu/providers/comcol-subscribe.menu.ts index 227a1d30988..d952792eb1c 100644 --- a/src/app/shared/menu/providers/comcol-subscribe.menu.ts +++ b/src/app/shared/menu/providers/comcol-subscribe.menu.ts @@ -5,16 +5,32 @@ * * http://www.dspace.org/license/ */ -import { Injectable } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; +import { + Inject, + Injectable, + PLATFORM_ID, +} from '@angular/core'; +import { AuthService } from '@dspace/core/auth/auth.service'; import { AuthorizationDataService } from '@dspace/core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '@dspace/core/data/feature-authorization/feature-id'; +import { SubscriptionsDataService } from '@dspace/core/data/subscriptions-data.service'; import { DSpaceObject } from '@dspace/core/shared/dspace-object.model'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; import { combineLatest, Observable, + of, + Subject, } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { + catchError, + first, + map, + startWith, + switchMap, +} from 'rxjs/operators'; import { SubscriptionModalComponent } from '../../subscriptions/subscription-modal/subscription-modal.component'; import { OnClickMenuItemModel } from '../menu-item/models/onclick.model'; @@ -27,33 +43,70 @@ import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu'; */ @Injectable() export class SubscribeMenuProvider extends DSpaceObjectPageMenuProvider { + private refresh$ = new Subject(); + constructor( + protected authService: AuthService, protected authorizationService: AuthorizationDataService, + protected subscriptionService: SubscriptionsDataService, protected modalService: NgbModal, + protected translateService: TranslateService, + @Inject(PLATFORM_ID) private platformId: unknown, ) { super(); } public getSectionsForContext(dso: DSpaceObject): Observable { - return combineLatest([ - this.authorizationService.isAuthorized(FeatureID.CanSubscribe, dso.self), - ]).pipe( - map(([canSubscribe]) => { - return [ - { - visible: canSubscribe, - model: { - type: MenuItemType.ONCLICK, - text: 'subscriptions.tooltip', - function: () => { - const modalRef = this.modalService.open(SubscriptionModalComponent); - modalRef.componentInstance.dso = dso; - }, - } as OnClickMenuItemModel, - icon: 'bell', - }, - ] as PartialMenuSection[]; + if (!isPlatformBrowser(this.platformId)) { + return of([]); + } + const sectionId = `subscribe-btn-${dso.uuid}`; + + return this.refresh$.pipe( + startWith(null), + switchMap(() => combineLatest([ + this.authorizationService.isAuthorized(FeatureID.CanSubscribe, dso.self), + this.authService.getAuthenticatedUserFromStore().pipe(first()), + ])), + switchMap(([canSubscribe, user]) => { + const baseSection = { + id: sectionId, + visible: false, + model: null, + } as PartialMenuSection; + + if (!canSubscribe || !user) { + return of([baseSection]); + } + + const openModal = () => { + const modalRef = this.modalService.open(SubscriptionModalComponent); + modalRef.componentInstance.dso = dso; + modalRef.componentInstance.updated.subscribe(() => this.refresh$.next()); + }; + + return this.subscriptionService.getSubscriptionsByPersonDSO(user.id, dso.uuid).pipe( + map(rd => { + const subscription = rd.payload?.page?.[0]; + return [{ + ...baseSection, + visible: true, + model: { + type: MenuItemType.ONCLICK, + text: subscription ? 'subscriptions.manage' : 'subscriptions.tooltip', + function: openModal, + } as OnClickMenuItemModel, + icon: 'bell', + }]; + }), + catchError(() => of([baseSection])), + ); }), + startWith([{ + id: sectionId, + visible: false, + model: null, + } as PartialMenuSection]), ); } } diff --git a/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.ts b/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.ts index 85e83ca5555..8ec465706e8 100644 --- a/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.ts +++ b/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.ts @@ -130,6 +130,8 @@ export class SubscriptionModalComponent implements OnInit { */ @Output() updateSubscription: EventEmitter = new EventEmitter(); + @Output() updated = new EventEmitter(); + constructor( private formBuilder: UntypedFormBuilder, private modalService: NgbModal, @@ -303,7 +305,8 @@ export class SubscriptionModalComponent implements OnInit { } combineLatest([...toBeProcessed]).subscribe((res) => { - this.activeModal.close(); + this.updated.emit(); + this.activeModal.close('updated'); }); } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 5b964f471fb..c155fac998f 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -6135,7 +6135,7 @@ "subscriptions.tooltip": "Subscribe", - "subscriptions.unsubscribe": "Unsubscribe", + "subscriptions.manage": "Manage Subscription", "subscriptions.modal.title": "Subscriptions",