diff --git a/src/app/base/core.component.spec.ts b/src/app/base/core.component.spec.ts index d318d63be..37b95ddb8 100644 --- a/src/app/base/core.component.spec.ts +++ b/src/app/base/core.component.spec.ts @@ -2,14 +2,14 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { LoggerTestingModule } from 'ngx-logger/testing'; -import { Injector, PLATFORM_ID } from '@angular/core'; +import { Injector, PLATFORM_ID, signal } from '@angular/core'; import { Router, RouterModule } from '@angular/router'; import { REQUEST, RESPONSE } from '../../express.tokens'; import { EmptyMockComponent, SERVER_REQUEST, SERVER_RESPONSE } from '@tests/app.mocks'; import { AppInjector, CoreModule } from '@modules/core'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { CoreComponent } from './core.component'; @@ -108,7 +108,7 @@ describe('App/Base/CoreComponent running CLIENT side', () => { let router: Router; let routerSpy: jest.SpyInstance; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let component: CoreComponent; let fixture: ComponentFixture; @@ -131,7 +131,7 @@ describe('App/Base/CoreComponent running CLIENT side', () => { router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); }); it('should create the component', () => { @@ -231,7 +231,7 @@ describe('App/Base/CoreComponent running CLIENT side', () => { // })); it(`should run userUrlBasePath()`, () => { - authenticationStore.userUrlBasePath = () => 'innovator'; + ctx.user.userUrlBasePath = signal('innovator'); fixture = TestBed.createComponent(CoreComponent); component = fixture.componentInstance; diff --git a/src/app/base/core.component.ts b/src/app/base/core.component.ts index cbdb23578..bd51e28d3 100644 --- a/src/app/base/core.component.ts +++ b/src/app/base/core.component.ts @@ -12,7 +12,6 @@ import { REQUEST, RESPONSE } from '../../express.tokens'; import { AppInjector } from '@modules/core/injectors/app-injector'; import { EnvironmentVariablesStore } from '@modules/core/stores/environment-variables.store'; -import { AuthenticationStore } from '@modules/stores/authentication/authentication.store'; import { AlertType, LinkType, MappedObjectType } from '@modules/core/interfaces/base.interfaces'; import { URLS } from './constants'; @@ -50,10 +49,6 @@ export class CoreComponent implements OnDestroy { URLS: typeof URLS; }; - protected stores: { - authentication: AuthenticationStore; - }; - protected ctx: CtxStore; protected subscriptions: Subscription[] = []; @@ -91,10 +86,6 @@ export class CoreComponent implements OnDestroy { URLS: URLS }; - this.stores = { - authentication: injector.get(AuthenticationStore) - }; - this.ctx = injector.get(CtxStore); this.ctx.layout.setCurrentUrl(this.location.path()); @@ -190,7 +181,7 @@ export class CoreComponent implements OnDestroy { // If no url is provided, use the previous url or default to the dashboard to avoid getting out of the app. if (!urlOrCallback) { - urlOrCallback = this.ctx.layout.previousUrl() ?? `/${this.stores.authentication.userUrlBasePath()}/dashboard`; + urlOrCallback = this.ctx.layout.previousUrl() ?? `/${this.ctx.user.userUrlBasePath()}/dashboard`; } this.ctx.layout.update({ backLink: { label, callback: urlOrCallback, hiddenLabel } }); @@ -264,8 +255,9 @@ export class CoreComponent implements OnDestroy { // } // } + // TODO: this could return a signal or be a computed from the store userUrlBasePath(): string { - return this.stores.authentication.userUrlBasePath(); + return this.ctx.user.userUrlBasePath(); } redirectTo(url: string, queryParams: MappedObjectType = {}): void { diff --git a/src/app/base/core.service.spec.ts b/src/app/base/core.service.spec.ts index 78588c31f..303a13b55 100644 --- a/src/app/base/core.service.spec.ts +++ b/src/app/base/core.service.spec.ts @@ -2,17 +2,17 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { LoggerTestingModule } from 'ngx-logger/testing'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { AppInjector, CoreModule } from '@modules/core'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { UserRoleEnum } from './enums'; import { CoreService } from './core.service'; describe('App/Base/CoreService', () => { - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let service: CoreService; @@ -24,7 +24,7 @@ describe('App/Base/CoreService', () => { AppInjector.setInjector(TestBed.inject(Injector)); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); service = TestBed.inject(CoreService); }); @@ -34,28 +34,28 @@ describe('App/Base/CoreService', () => { }); it(`should run apiUserBasePath() as Admin`, () => { - authenticationStore.getUserType = () => UserRoleEnum.ADMIN; + ctx.user.getUserType = signal(UserRoleEnum.ADMIN); expect(service.apiUserBasePath()).toBe('user-admin'); }); it(`should run apiUserBasePath() as NA`, () => { - authenticationStore.getUserType = () => UserRoleEnum.ASSESSMENT; + ctx.user.getUserType = signal(UserRoleEnum.ASSESSMENT); expect(service.apiUserBasePath()).toBe('assessments'); }); it(`should run apiUserBasePath() as Accessor`, () => { - authenticationStore.getUserType = () => UserRoleEnum.ACCESSOR; + ctx.user.getUserType = signal(UserRoleEnum.ACCESSOR); expect(service.apiUserBasePath()).toBe('accessors'); }); it(`should run apiUserBasePath() as Innovator`, () => { - authenticationStore.getUserType = () => UserRoleEnum.INNOVATOR; + ctx.user.getUserType = signal(UserRoleEnum.INNOVATOR); expect(service.apiUserBasePath()).toBe('innovators'); }); it(`should run apiUserBasePath() as nothing`, () => { - authenticationStore.getUserType = () => undefined; + ctx.user.getUserType = signal(undefined); expect(service.apiUserBasePath()).toBe(''); }); it(`should run userUrlBasePath()`, () => { - authenticationStore.userUrlBasePath = () => 'innovator'; + ctx.user.userUrlBasePath = signal('innovator'); expect(service.userUrlBasePath()).toBe('innovator'); }); diff --git a/src/app/base/core.service.ts b/src/app/base/core.service.ts index 49fad44f6..02abd282a 100644 --- a/src/app/base/core.service.ts +++ b/src/app/base/core.service.ts @@ -6,9 +6,7 @@ import { NGXLogger } from 'ngx-logger'; import { AppInjector } from '@modules/core/injectors/app-injector'; import { EnvironmentVariablesStore } from '@modules/core/stores/environment-variables.store'; -import { AuthenticationStore } from '@modules/stores/authentication/authentication.store'; -import { UserRoleEnum } from '@modules/stores/authentication/authentication.enums'; -import { ContextLayoutType, CtxStore } from '@modules/stores'; +import { ContextLayoutType, CtxStore, UserRoleEnum } from '@modules/stores'; @Injectable() export class CoreService { @@ -18,10 +16,6 @@ export class CoreService { protected translateService: TranslateService; protected logger: NGXLogger; - protected stores: { - authentication: AuthenticationStore; - }; - protected ctx: CtxStore; protected APP_URL: string; @@ -38,10 +32,6 @@ export class CoreService { this.translateService = injector.get(TranslateService); this.logger = injector.get(NGXLogger); - this.stores = { - authentication: injector.get(AuthenticationStore) - }; - this.ctx = injector.get(CtxStore); this.APP_URL = this.envVariablesStore.APP_URL; this.API_URL = this.envVariablesStore.API_URL; @@ -60,7 +50,7 @@ export class CoreService { } apiUserBasePath(): string { - switch (this.stores.authentication.getUserType()) { + switch (this.ctx.user.getUserType()) { case UserRoleEnum.ADMIN: return 'user-admin'; case UserRoleEnum.ASSESSMENT: @@ -75,8 +65,9 @@ export class CoreService { } } + // TODO: could return a computed from the store userUrlBasePath(): string { - return this.stores.authentication.userUrlBasePath(); + return this.ctx.user.userUrlBasePath(); } translate(translation: string, params?: object): string { diff --git a/src/app/base/enums.ts b/src/app/base/enums.ts index b7d4547e4..2399b74c9 100644 --- a/src/app/base/enums.ts +++ b/src/app/base/enums.ts @@ -1,12 +1,5 @@ -// Authentication store. -export { - UserRoleEnum, - InnovatorOrganisationRoleEnum, - AccessorOrganisationRoleEnum -} from '@modules/stores/authentication/authentication.enums'; - -// Authentication store. -export { TermsOfUseTypeEnum } from '@modules/stores/authentication/authentication.enums'; +// Stores +export { UserRoleEnum, TermsOfUseTypeEnum } from '@modules/stores'; // Environment store. export { diff --git a/src/modules/core/guards/authentication-redirection.guard.spec.ts b/src/modules/core/guards/authentication-redirection.guard.spec.ts index ca3bfceb2..90ba910a0 100644 --- a/src/modules/core/guards/authentication-redirection.guard.spec.ts +++ b/src/modules/core/guards/authentication-redirection.guard.spec.ts @@ -6,15 +6,15 @@ import { ActivatedRouteSnapshot, RouterModule, RouterStateSnapshot } from '@angu import { EmptyMockComponent } from '@tests/app.mocks'; import { CoreModule } from '@modules/core'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { UserRoleEnum } from '@app/base/enums'; -import { PLATFORM_ID } from '@angular/core'; +import { PLATFORM_ID, signal } from '@angular/core'; import { AuthenticationRedirectionGuard } from './authentication-redirection.guard'; describe('Core/Guards/AuthenticationRedirectionGuard', () => { - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let guard: AuthenticationRedirectionGuard; @@ -37,7 +37,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { providers: [{ provide: PLATFORM_ID, useValue: 'browser' }] }); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); guard = TestBed.inject(AuthenticationRedirectionGuard); @@ -49,8 +49,8 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'terms-of-use' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.INNOVATOR; - authenticationStore.isTermsOfUseAccepted = () => false; + ctx.user.getUserType = signal(UserRoleEnum.INNOVATOR); + ctx.user.isTermsOfUseAccepted = signal(false); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); @@ -58,7 +58,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { const activatedRouteSnapshotMock: Partial = { queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => undefined; + ctx.user.getUserType = signal(undefined); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); @@ -67,7 +67,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'dashboard' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.ASSESSMENT; + ctx.user.getUserType = signal(UserRoleEnum.ASSESSMENT); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); it('should deny access and redirect when user type is ACCESSOR', () => { @@ -75,7 +75,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'dashboard' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.ACCESSOR; + ctx.user.getUserType = signal(UserRoleEnum.ACCESSOR); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); it('should deny access and redirect when user type is INNOVATOR', () => { @@ -83,7 +83,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'dashboard' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.INNOVATOR; + ctx.user.getUserType = signal(UserRoleEnum.INNOVATOR); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); it('should deny access and redirect when user type is ADMIN', () => { @@ -91,7 +91,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'dashboard' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.ADMIN; + ctx.user.getUserType = signal(UserRoleEnum.ADMIN); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); @@ -100,7 +100,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'innovator' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.ASSESSMENT; + ctx.user.getUserType = signal(UserRoleEnum.ASSESSMENT); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); it('should deny access and redirect when user type is ACCESSOR', () => { @@ -108,7 +108,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'innovator' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.ACCESSOR; + ctx.user.getUserType = signal(UserRoleEnum.ACCESSOR); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); it('should deny access and redirect when user type is INNOVATOR', () => { @@ -116,7 +116,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'accessor' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.INNOVATOR; + ctx.user.getUserType = signal(UserRoleEnum.INNOVATOR); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); it('should deny access and redirect when user type is ADMIN', () => { @@ -124,7 +124,7 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'innovator' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.ADMIN; + ctx.user.getUserType = signal(UserRoleEnum.ADMIN); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(false); }); @@ -133,11 +133,9 @@ describe('Core/Guards/AuthenticationRedirectionGuard', () => { routeConfig: { path: 'innovator' }, queryParams: { dismissNotification: undefined } }; - authenticationStore.getUserType = () => UserRoleEnum.INNOVATOR; - authenticationStore.isTermsOfUseAccepted = () => true; - authenticationStore.getUserContextInfo = () => { - return { id: 'userId', roleId: 'id', type: UserRoleEnum.INNOVATOR }; - }; + ctx.user.getUserType = signal(UserRoleEnum.INNOVATOR); + ctx.user.isTermsOfUseAccepted = signal(true); + ctx.user.getUserContext = signal({ id: 'userId', roleId: 'id', type: UserRoleEnum.INNOVATOR }); expect(guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any)).toBe(true); }); }); diff --git a/src/modules/core/guards/authentication-redirection.guard.ts b/src/modules/core/guards/authentication-redirection.guard.ts index 959bbddc4..d85114b4b 100644 --- a/src/modules/core/guards/authentication-redirection.guard.ts +++ b/src/modules/core/guards/authentication-redirection.guard.ts @@ -3,20 +3,17 @@ import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { CtxStore } from '@modules/stores'; -import { AuthenticationStore } from '@modules/stores/authentication/authentication.store'; - @Injectable() export class AuthenticationRedirectionGuard { constructor( @Inject(PLATFORM_ID) private platformId: object, private router: Router, - private authentication: AuthenticationStore, private ctx: CtxStore ) {} canActivate(activatedRouteSnapshot: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { const pathSegment = activatedRouteSnapshot.routeConfig?.path || ''; - const userContext = this.authentication.getUserContextInfo(); + const userContext = this.ctx.user.getUserContext(); const dismissNotification = activatedRouteSnapshot.queryParams.dismissNotification; if (isPlatformServer(this.platformId)) { @@ -33,12 +30,8 @@ export class AuthenticationRedirectionGuard { this.ctx.notifications.dismiss({ notificationIds: [dismissNotification] }); } - if ( - !state.url.endsWith('terms-of-use') && - userContext?.type !== 'ADMIN' && - !this.authentication.isTermsOfUseAccepted() - ) { - const path = this.authentication.userUrlBasePath() + '/terms-of-use'; + if (!state.url.endsWith('terms-of-use') && userContext?.type !== 'ADMIN' && !this.ctx.user.isTermsOfUseAccepted()) { + const path = this.ctx.user.userUrlBasePath() + '/terms-of-use'; this.router.navigateByUrl(path); return false; } @@ -47,7 +40,7 @@ export class AuthenticationRedirectionGuard { !state.url.endsWith('announcements') && !state.url.includes('terms-of-use') && userContext.type !== 'ADMIN' && - this.authentication.hasAnnouncements() + this.ctx.user.hasAnnouncements() ) { this.router.navigate(['announcements']); return false; @@ -60,21 +53,21 @@ export class AuthenticationRedirectionGuard { alert: activatedRouteSnapshot.queryParams.state } : undefined; - this.router.navigateByUrl(this.authentication.userUrlBasePath(), alert && { state: alert }); + this.router.navigateByUrl(this.ctx.user.userUrlBasePath(), alert && { state: alert }); return false; } if (pathSegment === 'account/email-notifications') { - const url = `${this.authentication.userUrlBasePath()}/${pathSegment}`; + const url = `${this.ctx.user.userUrlBasePath()}/${pathSegment}`; this.router.navigateByUrl(url); return false; } - if (pathSegment === this.authentication.userUrlBasePath()) { + if (pathSegment === this.ctx.user.userUrlBasePath()) { this.ctx.notifications.fetchUnread$.next(); return true; } else { - this.router.navigateByUrl(this.authentication.userUrlBasePath()); + this.router.navigateByUrl(this.ctx.user.userUrlBasePath()); return false; } } diff --git a/src/modules/core/guards/authentication.guard.spec.ts b/src/modules/core/guards/authentication.guard.spec.ts index 1b4bf3209..babf06335 100644 --- a/src/modules/core/guards/authentication.guard.spec.ts +++ b/src/modules/core/guards/authentication.guard.spec.ts @@ -8,13 +8,13 @@ import { of, throwError } from 'rxjs'; import { SERVER_REQUEST, SERVER_RESPONSE } from '@tests/app.mocks'; import { CoreModule } from '@modules/core'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { ActivatedRouteSnapshot, RouterModule, RouterStateSnapshot } from '@angular/router'; import { AuthenticationGuard } from './authentication.guard'; describe('Core/Guards/AuthenticationGuard running SERVER side', () => { - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let guard: AuthenticationGuard; @@ -30,7 +30,7 @@ describe('Core/Guards/AuthenticationGuard running SERVER side', () => { ] }); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); guard = TestBed.inject(AuthenticationGuard); @@ -42,7 +42,7 @@ describe('Core/Guards/AuthenticationGuard running SERVER side', () => { const activatedRouteSnapshotMock: Partial = {}; - authenticationStore.initializeAuthentication$ = () => throwError('error'); + ctx.user.initializeAuthentication$ = () => throwError('error'); guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any).subscribe(response => { expected = response; @@ -53,7 +53,7 @@ describe('Core/Guards/AuthenticationGuard running SERVER side', () => { }); describe('Core/Guards/AuthenticationGuard running CLIENT side', () => { - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let guard: AuthenticationGuard; @@ -65,7 +65,7 @@ describe('Core/Guards/AuthenticationGuard running CLIENT side', () => { providers: [{ provide: PLATFORM_ID, useValue: 'browser' }] }); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); guard = TestBed.inject(AuthenticationGuard); @@ -77,7 +77,7 @@ describe('Core/Guards/AuthenticationGuard running CLIENT side', () => { const activatedRouteSnapshotMock: Partial = {}; - authenticationStore.initializeAuthentication$ = () => of(true); + ctx.user.initializeAuthentication$ = () => of(true); guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any).subscribe(response => { expected = response; @@ -93,7 +93,7 @@ describe('Core/Guards/AuthenticationGuard running CLIENT side', () => { const activatedRouteSnapshotMock: Partial = {}; - authenticationStore.initializeAuthentication$ = () => throwError('error'); + ctx.user.initializeAuthentication$ = () => throwError('error'); guard.canActivate(activatedRouteSnapshotMock as any, routerStateSnapshopMock as any).subscribe(response => { expected = response; }); diff --git a/src/modules/core/guards/authentication.guard.ts b/src/modules/core/guards/authentication.guard.ts index b1032db16..2df3b06f6 100644 --- a/src/modules/core/guards/authentication.guard.ts +++ b/src/modules/core/guards/authentication.guard.ts @@ -8,9 +8,9 @@ import { catchError, map } from 'rxjs/operators'; import { RESPONSE } from '../../../express.tokens'; import { Response } from 'express'; -import { AuthenticationStore } from '../../stores/authentication/authentication.store'; import { LoggerService, Severity } from '../services/logger.service'; import { EnvironmentVariablesStore } from '../stores/environment-variables.store'; +import { CtxStore } from '@modules/stores'; @Injectable() export class AuthenticationGuard { @@ -18,12 +18,12 @@ export class AuthenticationGuard { @Inject(PLATFORM_ID) private platformId: object, @Optional() @Inject(RESPONSE) private serverResponse: Response, private environmentStore: EnvironmentVariablesStore, - private authentication: AuthenticationStore, + private ctx: CtxStore, private loggerService: LoggerService ) {} canActivate(_route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.authentication.initializeAuthentication$().pipe( + return this.ctx.user.initializeAuthentication$().pipe( map(response => response), catchError((e: HttpErrorResponse) => { this.loggerService.trackTrace( diff --git a/src/modules/core/helpers/utils.helper.ts b/src/modules/core/helpers/utils.helper.ts index 9e9373cff..5d20ac060 100644 --- a/src/modules/core/helpers/utils.helper.ts +++ b/src/modules/core/helpers/utils.helper.ts @@ -8,8 +8,7 @@ import { SupportUpdatedResponseDTO } from '@modules/feature-modules/accessor/services/accessor.service'; import { OrganisationsListDTO } from '@modules/shared/services/organisations.service'; -import { SchemaContextStore } from '@modules/stores'; -import { PhoneUserPreferenceEnum } from '@modules/stores/authentication/authentication.service'; +import { PhoneUserPreferenceEnum, SchemaContextStore } from '@modules/stores'; export class UtilsHelper { static isEmpty(value: any) { diff --git a/src/modules/core/interceptors/api-out.interceptor.spec.ts b/src/modules/core/interceptors/api-out.interceptor.spec.ts index e8c44e3b2..9d0e281b0 100644 --- a/src/modules/core/interceptors/api-out.interceptor.spec.ts +++ b/src/modules/core/interceptors/api-out.interceptor.spec.ts @@ -1,27 +1,30 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { PLATFORM_ID } from '@angular/core'; +import { PLATFORM_ID, signal } from '@angular/core'; import { REQUEST, RESPONSE } from '../../../express.tokens'; import { ENV, SERVER_REQUEST, SERVER_RESPONSE } from '@tests/app.mocks'; import { UserRoleEnum } from '@app/base/enums'; import { CoreModule, EnvironmentVariablesStore } from '@modules/core'; -import { AuthenticationService, AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { RouterModule } from '@angular/router'; +import { UserContextStore } from '@modules/stores/ctx/user/user.store'; +import { UserContextService } from '@modules/stores/ctx/user/user.service'; describe('Core/Interceptors/ApiOutInterceptor running SERVER side', () => { let httpMock: HttpTestingController; let envVariablesStore: EnvironmentVariablesStore; - let authenticationService: AuthenticationService; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, RouterModule, CoreModule, StoresModule], providers: [ - AuthenticationService, + CtxStore, + UserContextStore, + UserContextService, { provide: 'APP_SERVER_ENVIRONMENT_VARIABLES', useValue: ENV }, { provide: PLATFORM_ID, useValue: 'server' }, { provide: REQUEST, useValue: SERVER_REQUEST }, @@ -31,8 +34,7 @@ describe('Core/Interceptors/ApiOutInterceptor running SERVER side', () => { httpMock = TestBed.inject(HttpTestingController); envVariablesStore = TestBed.inject(EnvironmentVariablesStore); - authenticationStore = TestBed.inject(AuthenticationStore); - authenticationService = TestBed.inject(AuthenticationService); + ctx = TestBed.inject(CtxStore); }); afterEach(() => { @@ -43,13 +45,13 @@ describe('Core/Interceptors/ApiOutInterceptor running SERVER side', () => { const responseMock = true; let response: any = null; - authenticationStore.getUserContextInfo = () => ({ + ctx.user.getUserContext = signal({ id: 'userId', roleId: '123', type: UserRoleEnum.ADMIN }); - authenticationService - .verifyUserSession() + ctx.user + .verifyUserSession$() .subscribe({ next: success => (response = success), error: error => (response = error) }); const httpRequest = httpMock.expectOne(`${envVariablesStore.APP_URL}/session`); @@ -63,13 +65,15 @@ describe('Core/Interceptors/ApiOutInterceptor running SERVER side', () => { describe('Core/Interceptors/ApiOutInterceptor running CLIENT side', () => { let httpMock: HttpTestingController; let environmentStore: EnvironmentVariablesStore; - let authenticationService: AuthenticationService; + let ctx: CtxStore; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, RouterModule, CoreModule, StoresModule], providers: [ - AuthenticationService, + CtxStore, + UserContextStore, + UserContextService, { provide: 'APP_SERVER_ENVIRONMENT_VARIABLES', useValue: ENV }, { provide: PLATFORM_ID, useValue: 'browser' } @@ -78,7 +82,7 @@ describe('Core/Interceptors/ApiOutInterceptor running CLIENT side', () => { httpMock = TestBed.inject(HttpTestingController); environmentStore = TestBed.inject(EnvironmentVariablesStore); - authenticationService = TestBed.inject(AuthenticationService); + ctx = TestBed.inject(CtxStore); }); afterEach(() => { @@ -89,8 +93,8 @@ describe('Core/Interceptors/ApiOutInterceptor running CLIENT side', () => { const responseMock = true; let response: any = null; - authenticationService - .verifyUserSession() + ctx.user + .verifyUserSession$() .subscribe({ next: success => (response = success), error: error => (response = error) }); const httpRequest = httpMock.expectOne(`${environmentStore.APP_URL}/session`); diff --git a/src/modules/core/interceptors/api-out.interceptor.ts b/src/modules/core/interceptors/api-out.interceptor.ts index 1d258f311..4b655c93d 100644 --- a/src/modules/core/interceptors/api-out.interceptor.ts +++ b/src/modules/core/interceptors/api-out.interceptor.ts @@ -1,7 +1,7 @@ import { isPlatformServer } from '@angular/common'; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpXsrfTokenExtractor } from '@angular/common/http'; import { Inject, Injectable, Optional, PLATFORM_ID } from '@angular/core'; -import { AuthenticationStore } from '@modules/stores'; +import { CtxStore } from '@modules/stores'; import { Request } from 'express'; import { Observable } from 'rxjs'; import { REQUEST } from '../../../express.tokens'; @@ -13,13 +13,13 @@ export class ApiOutInterceptor implements HttpInterceptor { constructor( @Inject(PLATFORM_ID) private platformId: object, @Optional() @Inject(REQUEST) private serverRequest: Request, - private authentication: AuthenticationStore, + private ctx: CtxStore, private envVariablesStore: EnvironmentVariablesStore, private tokenExtractor: HttpXsrfTokenExtractor ) {} intercept(request: HttpRequest, next: HttpHandler): Observable> { - const userContext = this.authentication.getUserContextInfo(); + const userContext = this.ctx.user.getUserContext(); if (isPlatformServer(this.platformId)) { request = request.clone({ diff --git a/src/modules/feature-modules/accessor/base/sidebar-innovation-menu-outlet.component.ts b/src/modules/feature-modules/accessor/base/sidebar-innovation-menu-outlet.component.ts index 6ea10c7f2..5a0ae6bac 100644 --- a/src/modules/feature-modules/accessor/base/sidebar-innovation-menu-outlet.component.ts +++ b/src/modules/feature-modules/accessor/base/sidebar-innovation-menu-outlet.component.ts @@ -4,7 +4,7 @@ import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; import { ViewportScroller } from '@angular/common'; -import { AuthenticationStore, CtxStore, InnovationStatusEnum } from '@modules/stores'; +import { CtxStore, InnovationStatusEnum } from '@modules/stores'; @Component({ selector: 'app-base-sidebar-innovation-menu-outlet', @@ -18,8 +18,6 @@ export class SidebarInnovationMenuOutletComponent implements OnInit, OnDestroy { showHeading = false; isAllSectionsDetailsPage = false; isInnovationRecordPage = false; - isQualifyingAccessorRole: boolean; - private sectionsSidebar: { label: string; url: string; children?: { label: string; id: string; url: string }[] }[] = []; private _sidebarItems: { label: string; url: string; id?: string }[] = []; @@ -27,11 +25,8 @@ export class SidebarInnovationMenuOutletComponent implements OnInit, OnDestroy { constructor( private router: Router, readonly ctx: CtxStore, - private scroller: ViewportScroller, - private authenticationStore: AuthenticationStore + private scroller: ViewportScroller ) { - this.isQualifyingAccessorRole = this.authenticationStore.isQualifyingAccessorRole(); - this.subscriptions.add( this.router.events .pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd)) @@ -66,7 +61,7 @@ export class SidebarInnovationMenuOutletComponent implements OnInit, OnDestroy { ? [{ label: 'Support summary', url: `/accessor/innovations/${innovation.id}/support-summary` }] : []), { - label: this.isQualifyingAccessorRole ? 'Suggest support' : 'Data sharing preferences', + label: this.ctx.user.isQualifyingAccessor() ? 'Suggest support' : 'Data sharing preferences', url: `/accessor/innovations/${innovation.id}/support` }, { label: 'Activity log', url: `/accessor/innovations/${innovation.id}/activity-log` }, diff --git a/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.spec.ts b/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.spec.ts index 6b0ede76b..0e2edea01 100644 --- a/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.spec.ts +++ b/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.spec.ts @@ -3,10 +3,8 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Injector } from '@angular/core'; -import { USER_INFO_INNOVATOR } from '@tests/data.mocks'; - import { CoreModule, AppInjector } from '@modules/core'; -import { StoresModule, AuthenticationStore } from '@modules/stores'; +import { StoresModule } from '@modules/stores'; import { AccessorModule } from '@modules/feature-modules/accessor/accessor.module'; @@ -14,8 +12,6 @@ import { DashboardComponent } from './dashboard.component'; import { RouterModule } from '@angular/router'; describe('FeatureModules/Accessor/Dashboard/DashboardComponent', () => { - let authenticationStore: AuthenticationStore; - let component: DashboardComponent; let fixture: ComponentFixture; @@ -25,8 +21,6 @@ describe('FeatureModules/Accessor/Dashboard/DashboardComponent', () => { }); AppInjector.setInjector(TestBed.inject(Injector)); - - authenticationStore = TestBed.inject(AuthenticationStore); }); it('should create the component', () => { diff --git a/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.ts b/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.ts index f3e84c68e..8ba47abdd 100644 --- a/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.ts +++ b/src/modules/feature-modules/accessor/pages/dashboard/dashboard.component.ts @@ -28,8 +28,6 @@ export class DashboardComponent extends CoreComponent implements OnInit { cardsList: StatisticsCardType[] = []; - isQualifyingAccessorRole = false; - announcements: AnnouncementType[] = []; constructor( @@ -38,14 +36,13 @@ export class DashboardComponent extends CoreComponent implements OnInit { ) { super(); - this.setPageTitle('Home', { hint: `Hello ${this.stores.authentication.getUserInfo().displayName}` }); - this.isQualifyingAccessorRole = this.stores.authentication.isQualifyingAccessorRole(); + this.setPageTitle('Home', { hint: `Hello ${this.ctx.user.getDisplayName()}` }); this.user = { - displayName: this.stores.authentication.getUserInfo().displayName, - organisation: this.stores.authentication.getUserContextInfo()?.organisationUnit?.name || '', - passwordResetAt: this.stores.authentication.getUserInfo().passwordResetAt, - firstTimeSignInAt: this.stores.authentication.getUserInfo().firstTimeSignInAt + displayName: this.ctx.user.getDisplayName(), + organisation: this.ctx.user.getUserContext()?.organisationUnit?.name || '', + passwordResetAt: this.ctx.user.getUserInfo().passwordResetAt, + firstTimeSignInAt: this.ctx.user.getUserInfo().firstTimeSignInAt }; } @@ -55,7 +52,7 @@ export class DashboardComponent extends CoreComponent implements OnInit { const newState = history.state; delete newState.alert; history.replaceState(newState, ''); - this.stores.authentication.userPasswordSuccessfullyUpdated(); + this.ctx.user.updateInfo({ passwordChangeSinceLastSignIn: true }); } const qp: { statistics: UserStatisticsTypeEnum[] } = { @@ -95,7 +92,7 @@ export class DashboardComponent extends CoreComponent implements OnInit { } ]; - if (this.isQualifyingAccessorRole) { + if (this.ctx.user.isQualifyingAccessor()) { this.cardsList.unshift({ title: 'Review innovations', label: `Suggested innovations awaiting status assignment from your organisation unit`, diff --git a/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/custom-notifications-entrypoint.component.ts b/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/custom-notifications-entrypoint.component.ts index 6476dd18c..043a16239 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/custom-notifications-entrypoint.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/custom-notifications-entrypoint.component.ts @@ -2,7 +2,6 @@ import { Component, Input } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { CoreComponent } from '@app/base'; import { NotificationEnum } from '@modules/feature-modules/accessor/services/accessor.service'; -import { AuthenticationStore } from '@modules/stores'; export type CustomNotificationEntrypointComponentLinksType = { label: string; action: NotificationEnum }[]; @@ -14,16 +13,13 @@ export class CustomNotificationsEntrypointComponent extends CoreComponent { @Input() links: CustomNotificationEntrypointComponentLinksType = []; innovationId: string; - constructor( - private activatedRoute: ActivatedRoute, - private authenticationStore: AuthenticationStore - ) { + constructor(private activatedRoute: ActivatedRoute) { super(); this.innovationId = this.activatedRoute.snapshot.params.innovationId; } onNotify(customNotificationAction: NotificationEnum) { - const url = `/${this.authenticationStore.userUrlBasePath()}/innovations/${this.innovationId}/custom-notifications/new`; + const url = `/${this.ctx.user.userUrlBasePath()}/innovations/${this.innovationId}/custom-notifications/new`; this.router.navigateByUrl(url, { state: { customNotificationAction } }); } } diff --git a/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-delete/custom-notification-delete.component.ts b/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-delete/custom-notification-delete.component.ts index 71eced030..09cd271de 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-delete/custom-notification-delete.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-delete/custom-notification-delete.component.ts @@ -384,18 +384,16 @@ export class WizardInnovationCustomNotificationDeleteComponent extends CoreCompo } private redirectToManageCustomNotifications(): void { - this.redirectTo(`${this.stores.authentication.userUrlBasePath()}/account/manage-custom-notifications`); + this.redirectTo(`${this.ctx.user.userUrlBasePath()}/account/manage-custom-notifications`); } private redirectToInnovationCustomNotifications(): void { - this.redirectTo( - `${this.stores.authentication.userUrlBasePath()}/innovations/${this.innovation.id}/custom-notifications` - ); + this.redirectTo(`${this.ctx.user.userUrlBasePath()}/innovations/${this.innovation.id}/custom-notifications`); } private redirectToEditCustomNotification(): void { this.redirectTo( - `${this.stores.authentication.userUrlBasePath()}/innovations/${this.innovation.id}/custom-notifications/${this.subscriptionId}/edit` + `${this.ctx.user.userUrlBasePath()}/innovations/${this.innovation.id}/custom-notifications/${this.subscriptionId}/edit` ); } } diff --git a/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-new/custom-notification-new.component.ts b/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-new/custom-notification-new.component.ts index f5265aa5f..3c6b1fd31 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-new/custom-notification-new.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/custom-notifications/wizard-custom-notification-new/custom-notification-new.component.ts @@ -814,7 +814,7 @@ export class WizardInnovationCustomNotificationNewComponent extends CoreComponen private redirectInnovationCustomNotifications(): void { this.redirectTo( this.ctx.layout.previousUrl() ?? - `${this.stores.authentication.userUrlBasePath()}/innovations/${this.innovation.id}/custom-notifications` + `${this.ctx.user.userUrlBasePath()}/innovations/${this.innovation.id}/custom-notifications` ); } } diff --git a/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.html b/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.html index 8bf463179..99db4df56 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.html +++ b/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.html @@ -6,7 +6,7 @@

Please note that the innovator {{ innovation.owner.name }} is currently locked.

- +

{{ innovationSupport.organisationUnit }}

@@ -20,7 +20,7 @@ >
- Change support status
@@ -37,7 +37,9 @@
- Change accessors
@@ -50,7 +52,7 @@
@@ -62,7 +64,7 @@

{{ "features.accessor.cant_do_while_in_assessment" | translate }}

- +
Request status update diff --git a/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.ts b/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.ts index 0e3b35fbd..b89ea3c5c 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/overview/overview.component.ts @@ -23,9 +23,6 @@ export class InnovationOverviewComponent extends CoreComponent implements OnInit qaSuggestions: InnovationUnitSuggestionsType = []; - isQualifyingAccessorRole = false; - isAccessorRole = false; - innovationSummary: { label: string; value: null | string }[] = []; innovatorSummary: { label: string; value: string }[] = []; cardsList: StatisticsCardType[] = []; @@ -63,8 +60,6 @@ export class InnovationOverviewComponent extends CoreComponent implements OnInit this.search = this.activatedRoute.snapshot.queryParams.search; this.innovation = this.ctx.innovation.info(); - this.isQualifyingAccessorRole = this.stores.authentication.isQualifyingAccessorRole(); - this.isAccessorRole = this.stores.authentication.isAccessorRole(); this.isInAssessment = [ InnovationStatusEnum.AWAITING_NEEDS_REASSESSMENT, InnovationStatusEnum.NEEDS_ASSESSMENT, @@ -90,7 +85,7 @@ export class InnovationOverviewComponent extends CoreComponent implements OnInit ...(this.innovation.support?.id && { support: this.innovationsService.getInnovationSupportInfo(this.innovationId, this.innovation.support.id) }), - ...(this.isQualifyingAccessorRole && { + ...(this.ctx.user.isQualifyingAccessor() && { unitsSuggestions: this.innovationService.getInnovationQASuggestions(this.innovation.id) }), innovationProgress: this.innovationsService.getInnovationProgress(this.innovationId, true), @@ -102,7 +97,7 @@ export class InnovationOverviewComponent extends CoreComponent implements OnInit const innovationInfo = this.innovation; this.innovationSupport = { - organisationUnit: this.stores.authentication.getAccessorOrganisationUnitName(), + organisationUnit: this.ctx.user.getAccessorUnitName() ?? '', status: support?.status ?? InnovationSupportStatusEnum.UNASSIGNED, engagingAccessors: support?.engagingAccessors ?? [] }; diff --git a/src/modules/feature-modules/accessor/pages/innovation/support/organisations-support-status-suggest.component.ts b/src/modules/feature-modules/accessor/pages/innovation/support/organisations-support-status-suggest.component.ts index 5b2ecf502..95255bbfb 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/support/organisations-support-status-suggest.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/support/organisations-support-status-suggest.component.ts @@ -100,7 +100,7 @@ export class InnovationSupportOrganisationsSupportStatusSuggestComponent extends next: ([organisations, innovationSupports]) => { this.organisations = organisations; - const userUnitId = this.stores.authentication.getUserContextInfo()?.organisationUnit?.id ?? ''; + const userUnitId = this.ctx.user.getUserContext()?.organisationUnit?.id ?? ''; this.previousOrganisationsSuggestions = JSON.parse(sessionStorage.getItem('organisationsSuggestions') ?? '{}'); diff --git a/src/modules/feature-modules/accessor/pages/innovation/support/support-change-accessors.component.ts b/src/modules/feature-modules/accessor/pages/innovation/support/support-change-accessors.component.ts index 07ff0419b..a3d7de2f5 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/support/support-change-accessors.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/support/support-change-accessors.component.ts @@ -55,7 +55,7 @@ export class InnovationChangeAccessorsComponent extends CoreComponent implements this.stepNumber = 1; - this.userOrganisationUnit = this.stores.authentication.getUserContextInfo()?.organisationUnit || null; + this.userOrganisationUnit = this.ctx.user.getUserContext()?.organisationUnit || null; } ngOnInit(): void { @@ -94,7 +94,7 @@ export class InnovationChangeAccessorsComponent extends CoreComponent implements if (this.innovationSupportStatus === InnovationSupportStatusEnum.WAITING) { // add this user by default, and disable input - const userId = this.stores.authentication.getUserId(); + const userId = this.ctx.user.getUserId(); (this.form.get('accessors') as FormArray).push(new FormControl(userId)); this.disabledCheckboxAccessors = [userId]; } diff --git a/src/modules/feature-modules/accessor/pages/innovation/support/support-request-update-status.component.spec.ts b/src/modules/feature-modules/accessor/pages/innovation/support/support-request-update-status.component.spec.ts index a613323ca..ea5561d2f 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/support/support-request-update-status.component.spec.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/support/support-request-update-status.component.spec.ts @@ -1,11 +1,11 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { AppInjector, CoreModule } from '@modules/core'; import { AccessorModule } from '@modules/feature-modules/accessor/accessor.module'; import { AccessorService } from '@modules/feature-modules/accessor/services/accessor.service'; -import { AuthenticationStore, StoresModule, InnovationSupportStatusEnum } from '@modules/stores'; +import { StoresModule, InnovationSupportStatusEnum, CtxStore } from '@modules/stores'; import { USER_INFO_ACCESSOR } from '@tests/data.mocks'; import { InnovationSupportRequestUpdateStatusComponent } from './support-request-update-status.component'; @@ -18,7 +18,7 @@ describe('SupportUpdateStatusComponent', () => { let router: Router; let routerSpy: jest.SpyInstance; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let accessorService: AccessorService; beforeEach(async () => { @@ -33,12 +33,12 @@ describe('SupportUpdateStatusComponent', () => { router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); accessorService = TestBed.inject(AccessorService); activatedRoute.snapshot.params = { innovationId: 'Inno01', supportId: 'SupportId01' }; - authenticationStore.getUserInfo = () => USER_INFO_ACCESSOR; + ctx.user.getUserInfo = signal(USER_INFO_ACCESSOR); fixture = TestBed.createComponent(InnovationSupportRequestUpdateStatusComponent); component = fixture.componentInstance; diff --git a/src/modules/feature-modules/accessor/pages/innovation/support/support-update.component.ts b/src/modules/feature-modules/accessor/pages/innovation/support/support-update.component.ts index b0a3c1663..91bebf09f 100644 --- a/src/modules/feature-modules/accessor/pages/innovation/support/support-update.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovation/support/support-update.component.ts @@ -121,7 +121,7 @@ export class InnovationSupportUpdateComponent extends CoreComponent implements O this.stepNumber = 1; - this.userOrganisationUnit = this.stores.authentication.getUserContextInfo()?.organisationUnit || null; + this.userOrganisationUnit = this.ctx.user.getUserContext()?.organisationUnit || null; this.messageStatusUpdated = { [InnovationSupportStatusEnum.ENGAGING]: { @@ -291,7 +291,7 @@ export class InnovationSupportUpdateComponent extends CoreComponent implements O this.formAccessorsList = this.qualifyingAccessorsList.map(i => ({ value: i.id, label: i.name })); // add this user by default, and disable input - const userId = this.stores.authentication.getUserId(); + const userId = this.ctx.user.getUserId(); formSelectedAcessorsList.clear(); formSelectedAcessorsList.push(new FormControl(userId)); @@ -377,7 +377,7 @@ export class InnovationSupportUpdateComponent extends CoreComponent implements O } private uploadFileAndSaveStatus(file: any, body: ChangeSupportStatusDocumentType): void { - const httpUploadBody = { userId: this.stores.authentication.getUserId(), innovationId: this.innovationId }; + const httpUploadBody = { userId: this.ctx.user.getUserId(), innovationId: this.innovationId }; this.fileUploadService .uploadFile(httpUploadBody, file) diff --git a/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.spec.ts b/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.spec.ts index e4f5d8662..db98ac3ef 100644 --- a/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.spec.ts +++ b/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.spec.ts @@ -5,7 +5,7 @@ import { Injector } from '@angular/core'; import { ActivatedRoute, RouterModule } from '@angular/router'; import { CoreModule, AppInjector } from '@modules/core'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { StoresModule } from '@modules/stores'; import { AccessorModule } from '@modules/feature-modules/accessor/accessor.module'; import { InnovationsReviewComponent } from './innovations-review.component'; @@ -16,7 +16,6 @@ import { NotificationsService } from '@modules/shared/services/notifications.ser describe('FeatureModules/Accessor/Innovations/ReviewInnovationsComponent', () => { let activatedRoute: ActivatedRoute; - let authenticationStore: AuthenticationStore; let accessorService: AccessorService; let notificationsService: NotificationsService; @@ -32,7 +31,6 @@ describe('FeatureModules/Accessor/Innovations/ReviewInnovationsComponent', () => activatedRoute = TestBed.inject(ActivatedRoute); - authenticationStore = TestBed.inject(AuthenticationStore); accessorService = TestBed.inject(AccessorService); notificationsService = TestBed.inject(NotificationsService); }); diff --git a/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.ts b/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.ts index 3c37843c1..b866f8bd1 100644 --- a/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.ts +++ b/src/modules/feature-modules/accessor/pages/innovations/innovations-review.component.ts @@ -89,12 +89,12 @@ export class InnovationsReviewComponent extends CoreComponent implements OnInit private innovationsService: InnovationsService ) { super(); - this.userUnitAcronym = this.stores.authentication.state.userContext?.organisationUnit?.acronym ?? ''; - this.userUnit = this.stores.authentication.state.userContext?.organisationUnit?.name ?? ''; + this.userUnitAcronym = this.ctx.user.getUserContext()?.organisationUnit?.acronym ?? ''; + this.userUnit = this.ctx.user.getAccessorUnitName() ?? ''; this.setPageTitle('Innovations', { hint: `${this.userUnit}` }); - if (this.stores.authentication.isAccessorRole()) { + if (this.ctx.user.isAccessor()) { this.defaultStatus = 'ENGAGING'; this.tabs = [ { @@ -148,7 +148,7 @@ export class InnovationsReviewComponent extends CoreComponent implements OnInit notifications: null } ]; - } else if (this.stores.authentication.isQualifyingAccessorRole()) { + } else if (this.ctx.user.isQualifyingAccessor()) { this.defaultStatus = 'SUGGESTED'; this.tabs = [ { diff --git a/src/modules/feature-modules/accessor/pages/unit/accessor-and-innovation-list.component.ts b/src/modules/feature-modules/accessor/pages/unit/accessor-and-innovation-list.component.ts index c9ae9d02b..3cc9aaaf8 100644 --- a/src/modules/feature-modules/accessor/pages/unit/accessor-and-innovation-list.component.ts +++ b/src/modules/feature-modules/accessor/pages/unit/accessor-and-innovation-list.component.ts @@ -35,11 +35,11 @@ export class AccessorAndInnovationListComponent extends CoreComponent implements ngOnInit(): void { this.setPageStatus('LOADING'); - const ctx = this.stores.authentication.getUserContextInfo(); + const ctx = this.ctx.user.getUserContext(); const unit = ctx?.organisationUnit; const org = ctx?.organisation; if (!unit || !org) { - this.redirectTo(this.stores.authentication.userUrlBasePath()); + this.redirectTo(this.ctx.user.userUrlBasePath()); return; } @@ -50,7 +50,7 @@ export class AccessorAndInnovationListComponent extends CoreComponent implements this.onPageChange({ pageNumber: 1 }); this.setPageTitle('List of accessors and supported innovations', { - hint: this.stores.authentication.getAccessorOrganisationUnitName() + hint: this.ctx.user.getAccessorUnitName() }); this.setBackLink(); diff --git a/src/modules/feature-modules/accessor/services/accessor.service.spec.ts b/src/modules/feature-modules/accessor/services/accessor.service.spec.ts index 816633d2e..cb4493d1f 100644 --- a/src/modules/feature-modules/accessor/services/accessor.service.spec.ts +++ b/src/modules/feature-modules/accessor/services/accessor.service.spec.ts @@ -3,20 +3,19 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { ENV } from '@tests/app.mocks'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { AppInjector, CoreModule, EnvironmentVariablesStore } from '@modules/core'; -import { StoresModule, AuthenticationStore } from '@modules/stores'; +import { StoresModule, CtxStore } from '@modules/stores'; import { AccessorModule } from '@modules/feature-modules/accessor/accessor.module'; import { AccessorService } from './accessor.service'; -import { SupportLogType } from '@modules/shared/services/innovations.dtos'; describe('FeatureModules/Accessor/Services/AccessorService', () => { let httpMock: HttpTestingController; let envVariablesStore: EnvironmentVariablesStore; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let service: AccessorService; @@ -31,11 +30,11 @@ describe('FeatureModules/Accessor/Services/AccessorService', () => { httpMock = TestBed.inject(HttpTestingController); envVariablesStore = TestBed.inject(EnvironmentVariablesStore); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); service = TestBed.inject(AccessorService); - authenticationStore.getUserId = () => 'UserId01'; + ctx.user.getUserId = signal('UserId01'); }); afterEach(() => { diff --git a/src/modules/feature-modules/admin/pages/announcements/announcement-details.component.ts b/src/modules/feature-modules/admin/pages/announcements/announcement-details.component.ts index f35f2ffec..cd82cce90 100644 --- a/src/modules/feature-modules/admin/pages/announcements/announcement-details.component.ts +++ b/src/modules/feature-modules/admin/pages/announcements/announcement-details.component.ts @@ -51,9 +51,7 @@ export class PageAnnouncementDetailsComponent extends CoreComponent implements O next: response => { this.announcement = { ...response, - userGroupsLabels: response.userRoles - .map(item => this.stores.authentication.getRoleDescription(item, true)) - .join('\n'), + userGroupsLabels: response.userRoles.map(item => this.ctx.user.getRoleDescription(item, true)).join('\n'), isScheduled: response.status === AnnouncementStatusEnum.SCHEDULED, isActive: response.status === AnnouncementStatusEnum.ACTIVE, diff --git a/src/modules/feature-modules/admin/pages/announcements/announcement-newdit.component.ts b/src/modules/feature-modules/admin/pages/announcements/announcement-newdit.component.ts index 7bfd7c2bb..e7281494c 100644 --- a/src/modules/feature-modules/admin/pages/announcements/announcement-newdit.component.ts +++ b/src/modules/feature-modules/admin/pages/announcements/announcement-newdit.component.ts @@ -237,9 +237,7 @@ export class PageAnnouncementNewditComponent extends CoreComponent implements On content: outboundPayload.params.content, linkLabel: outboundPayload.params.link?.label ?? '', linkUrl: outboundPayload.params.link?.url ?? '', - userRoles: outboundPayload.userRoles - .map(item => this.stores.authentication.getRoleDescription(item, true)) - .join('\n'), + userRoles: outboundPayload.userRoles.map(item => this.ctx.user.getRoleDescription(item, true)).join('\n'), showToWhom: outboundPayload.userRoles.includes(UserRoleEnum.INNOVATOR) ? outboundPayload.filters?.length ? 'Specific types of innovations' diff --git a/src/modules/feature-modules/admin/pages/dashboard/dashboard.component.spec.ts b/src/modules/feature-modules/admin/pages/dashboard/dashboard.component.spec.ts deleted file mode 100644 index d59c0507e..000000000 --- a/src/modules/feature-modules/admin/pages/dashboard/dashboard.component.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { Injector } from '@angular/core'; -import { ActivatedRoute, RouterModule } from '@angular/router'; - -import { AppInjector, CoreModule } from '@modules/core'; -import { AdminModule } from '@modules/feature-modules/admin/admin.module'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; -import { USER_INFO_INNOVATOR } from '@tests/data.mocks'; - -import { PageDashboardComponent } from './dashboard.component'; - -describe('FeatureModules/Admin/Pages/Dashboard/PageDashboardComponent', () => { - let activatedRoute: ActivatedRoute; - - let authenticationStore: AuthenticationStore; - - let component: PageDashboardComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterModule.forRoot([]), CoreModule, StoresModule, AdminModule] - }); - - AppInjector.setInjector(TestBed.inject(Injector)); - - activatedRoute = TestBed.inject(ActivatedRoute); - - authenticationStore = TestBed.inject(AuthenticationStore); - - authenticationStore.getUserInfo = () => USER_INFO_INNOVATOR; - }); - - it('should create the component', () => { - fixture = TestBed.createComponent(PageDashboardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - expect(component).toBeTruthy(); - }); - - // it('should have alert when password changed', () => { - - // authenticationStore.getUserInfo = () => ({ - // ...USER_INFO_INNOVATOR, - // type: UserRoleEnum.ADMIN, - // passwordResetAt: new Date(new Date().getTime() - 1 * 60000).toString() - // }); - - // const expected = { type: 'SUCCESS', title: 'You have successfully changed your password.', setFocus: true }; - - // fixture = TestBed.createComponent(PageDashboardComponent); - // component = fixture.componentInstance; - // fixture.detectChanges(); - // expect(component.alert).toEqual(expected); - - // }); -}); diff --git a/src/modules/feature-modules/admin/pages/dashboard/dashboard.component.ts b/src/modules/feature-modules/admin/pages/dashboard/dashboard.component.ts index c33084db4..3ebd5eea0 100644 --- a/src/modules/feature-modules/admin/pages/dashboard/dashboard.component.ts +++ b/src/modules/feature-modules/admin/pages/dashboard/dashboard.component.ts @@ -18,7 +18,7 @@ export class PageDashboardComponent extends CoreComponent implements OnInit { const newState = history.state; delete newState.alert; history.replaceState(newState, ''); - this.stores.authentication.userPasswordSuccessfullyUpdated(); + this.ctx.user.updateInfo({ passwordChangeSinceLastSignIn: true }); } this.setPageStatus('READY'); diff --git a/src/modules/feature-modules/admin/pages/innovation/overview/overview.component.ts b/src/modules/feature-modules/admin/pages/innovation/overview/overview.component.ts index 1abe05690..e74cb94a7 100644 --- a/src/modules/feature-modules/admin/pages/innovation/overview/overview.component.ts +++ b/src/modules/feature-modules/admin/pages/innovation/overview/overview.component.ts @@ -73,8 +73,8 @@ export class InnovationOverviewComponent extends CoreComponent implements OnInit innovationProgress: this.innovationsService.getInnovationProgress(this.innovationId, true) }).subscribe(({ innovation, innovationCollaborators, innovationProgress }) => { this.innovationSupport = { - organisationUnit: this.stores.authentication.getAccessorOrganisationUnitName(), - status: this.innovation.support?.status || InnovationSupportStatusEnum.UNASSIGNED + organisationUnit: this.ctx.user.getAccessorUnitName() ?? '', + status: this.innovation.support?.status ?? InnovationSupportStatusEnum.UNASSIGNED }; this.innovationSummary = [ diff --git a/src/modules/feature-modules/admin/pages/organisations/organisation-edit.component.spec.ts b/src/modules/feature-modules/admin/pages/organisations/organisation-edit.component.spec.ts index 8895d2cc9..6c5f4988d 100644 --- a/src/modules/feature-modules/admin/pages/organisations/organisation-edit.component.spec.ts +++ b/src/modules/feature-modules/admin/pages/organisations/organisation-edit.component.spec.ts @@ -8,7 +8,7 @@ import { of, throwError } from 'rxjs'; import { AppInjector, CoreModule } from '@modules/core'; import { AdminModule } from '@modules/feature-modules/admin/admin.module'; import { FormEngineComponent } from '@modules/shared/forms'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { PageOrganisationEditComponent } from './organisation-edit.component'; @@ -22,7 +22,7 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationEditComponent let router: Router; let routerSpy: jest.SpyInstance; let activatedRoute: ActivatedRoute; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let usersService: AdminUsersService; let organisationsService: OrganisationsService; let adminOrganisationsService: AdminOrganisationsService; @@ -37,7 +37,7 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationEditComponent router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); activatedRoute = TestBed.inject(ActivatedRoute); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); usersService = TestBed.inject(AdminUsersService); organisationsService = TestBed.inject(OrganisationsService); adminOrganisationsService = TestBed.inject(AdminOrganisationsService); @@ -144,7 +144,7 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationEditComponent it('should run onSubmitWizard() with API success when updating organisation', () => { activatedRoute.snapshot.data = { module: 'Organisation' }; - authenticationStore.initializeAuthentication$ = () => of(true); + ctx.user.initializeAuthentication$ = () => of(true); adminOrganisationsService.updateOrganisation = () => of({ organisationId: 'Org01', status: 'OK' }); fixture = TestBed.createComponent(PageOrganisationEditComponent); @@ -159,7 +159,7 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationEditComponent it('should run onSubmitWizard() with API success when updating unit', () => { activatedRoute.snapshot.params = { organisationId: 'Org01', organisationUnitId: 'Unit01' }; activatedRoute.snapshot.data = { module: 'Unit' }; - authenticationStore.initializeAuthentication$ = () => of(true); + ctx.user.initializeAuthentication$ = () => of(true); adminOrganisationsService.updateUnit = () => of({ unitId: 'Unit01' }); fixture = TestBed.createComponent(PageOrganisationEditComponent); diff --git a/src/modules/feature-modules/admin/pages/organisations/organisation-info.component.spec.ts b/src/modules/feature-modules/admin/pages/organisations/organisation-info.component.spec.ts index c309f5d0d..2dff64a87 100644 --- a/src/modules/feature-modules/admin/pages/organisations/organisation-info.component.spec.ts +++ b/src/modules/feature-modules/admin/pages/organisations/organisation-info.component.spec.ts @@ -7,13 +7,12 @@ import { of, throwError } from 'rxjs'; import { AppInjector, CoreModule } from '@modules/core'; import { AdminModule } from '@modules/feature-modules/admin/admin.module'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { StoresModule } from '@modules/stores'; import { PageOrganisationInfoComponent } from './organisation-info.component'; import { OrganisationsService } from '@modules/shared/services/organisations.service'; import { UsersService } from '@modules/shared/services/users.service'; -import { USER_INFO_ADMIN } from '@tests/data.mocks'; describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationInfoComponent', () => { let component: PageOrganisationInfoComponent; @@ -21,7 +20,6 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationInfoComponent let activatedRoute: ActivatedRoute; let organisationsService: OrganisationsService; let usersService: UsersService; - let authenticationStore: AuthenticationStore; beforeEach(() => { TestBed.configureTestingModule({ @@ -30,12 +28,9 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationInfoComponent AppInjector.setInjector(TestBed.inject(Injector)); - authenticationStore = TestBed.inject(AuthenticationStore); activatedRoute = TestBed.inject(ActivatedRoute); organisationsService = TestBed.inject(OrganisationsService); usersService = TestBed.inject(UsersService); - - authenticationStore.getUserInfo = () => USER_INFO_ADMIN; }); it('should create the component', () => { diff --git a/src/modules/feature-modules/admin/pages/organisations/organisation-new.component.spec.ts b/src/modules/feature-modules/admin/pages/organisations/organisation-new.component.spec.ts index c7f552c68..0e5142888 100644 --- a/src/modules/feature-modules/admin/pages/organisations/organisation-new.component.spec.ts +++ b/src/modules/feature-modules/admin/pages/organisations/organisation-new.component.spec.ts @@ -6,7 +6,7 @@ import { Router, RouterModule } from '@angular/router'; import { AppInjector, CoreModule } from '@modules/core'; import { AdminModule } from '@modules/feature-modules/admin/admin.module'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { StoresModule } from '@modules/stores'; import { AdminOrganisationsService } from '../../services/admin-organisations.service'; import { AdminUsersService } from '../../services/users.service'; @@ -18,7 +18,6 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationNewComponent' let router: Router; let routerSpy: jest.SpyInstance; - let authenticationStore: AuthenticationStore; let adminOrganisationsService: AdminOrganisationsService; let usersService: AdminUsersService; @@ -32,7 +31,6 @@ describe('FeatureModules/Admin/Pages/Organisations/PageOrganisationNewComponent' router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); - authenticationStore = TestBed.inject(AuthenticationStore); usersService = TestBed.inject(AdminUsersService); adminOrganisationsService = TestBed.inject(AdminOrganisationsService); }); diff --git a/src/modules/feature-modules/admin/pages/organisations/organisation-unit-new/organisation-unit-new.component.ts b/src/modules/feature-modules/admin/pages/organisations/organisation-unit-new/organisation-unit-new.component.ts index 6f66a87a2..4a533e667 100644 --- a/src/modules/feature-modules/admin/pages/organisations/organisation-unit-new/organisation-unit-new.component.ts +++ b/src/modules/feature-modules/admin/pages/organisations/organisation-unit-new/organisation-unit-new.component.ts @@ -50,7 +50,7 @@ export class PageOrganisationUnitNewComponent extends CoreComponent implements O switch (action) { case 'previous': if (this.wizard.isFirstStep()) { - this.redirectTo(`${this.stores.authentication.userUrlBasePath()}/organisations/${this.organisationId}`); + this.redirectTo(`${this.ctx.user.userUrlBasePath()}/organisations/${this.organisationId}`); } else { this.wizard.previousStep(); this.setPageTitle(this.wizard.currentStepTitle(), { showPage: false }); @@ -91,7 +91,7 @@ export class PageOrganisationUnitNewComponent extends CoreComponent implements O this.setRedirectAlertSuccess( 'You have successfully created a new organisation unit attached to this organisation' ); - this.redirectTo(`${this.stores.authentication.userUrlBasePath()}/organisations/${this.organisationId}`); + this.redirectTo(`${this.ctx.user.userUrlBasePath()}/organisations/${this.organisationId}`); }, error: () => { this.submitButton = { isActive: true, label: 'Submit' }; diff --git a/src/modules/feature-modules/admin/pages/users/roles/role-activate.component.ts b/src/modules/feature-modules/admin/pages/users/roles/role-activate.component.ts index 0aabd29ed..dffe0bcb5 100644 --- a/src/modules/feature-modules/admin/pages/users/roles/role-activate.component.ts +++ b/src/modules/feature-modules/admin/pages/users/roles/role-activate.component.ts @@ -62,8 +62,8 @@ export class PageUsersRoleActivateComponent extends CoreComponent implements OnI .map(r => ({ id: r.id, description: r.displayTeam - ? `${this.stores.authentication.getRoleDescription(r.role).toLowerCase()} (${r.displayTeam})` - : `${this.stores.authentication.getRoleDescription(r.role).toLowerCase()}` + ? `${this.ctx.user.getRoleDescription(r.role).toLowerCase()} (${r.displayTeam})` + : `${this.ctx.user.getRoleDescription(r.role).toLowerCase()}` }))[0] ?? { id: '', description: '' } }; diff --git a/src/modules/feature-modules/admin/pages/users/roles/role-change.component.ts b/src/modules/feature-modules/admin/pages/users/roles/role-change.component.ts index aebe6bb0f..22822ef93 100644 --- a/src/modules/feature-modules/admin/pages/users/roles/role-change.component.ts +++ b/src/modules/feature-modules/admin/pages/users/roles/role-change.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { CoreComponent } from '@app/base'; -import { AccessorOrganisationRoleEnum, UserRoleEnum } from '@app/base/enums'; +import { UserRoleEnum } from '@app/base/enums'; import { UserInfo } from '@modules/shared/dtos/users.dto'; import { AdminUsersService, changeUserRoleDTO, GetInnovationsByInnovatorIdDTO } from '../../../services/users.service'; @@ -57,7 +57,7 @@ export class PageUsersRoleChangeComponent extends CoreComponent implements OnIni this.user = { ...userInfo, rolesDescription: userInfo.roles.map(r => { - let roleDescription = this.stores.authentication.getRoleDescription(r.role); + let roleDescription = this.ctx.user.getRoleDescription(r.role); if (r.displayTeam) { roleDescription += ` (${r.displayTeam})`; } @@ -95,8 +95,8 @@ export class PageUsersRoleChangeComponent extends CoreComponent implements OnIni role: { name: this.user.roles[0].role === UserRoleEnum.QUALIFYING_ACCESSOR - ? AccessorOrganisationRoleEnum.ACCESSOR - : AccessorOrganisationRoleEnum.QUALIFYING_ACCESSOR, + ? UserRoleEnum.ACCESSOR + : UserRoleEnum.QUALIFYING_ACCESSOR, organisationId: this.user.roles[0].organisation?.id ?? '' } }; diff --git a/src/modules/feature-modules/admin/pages/users/roles/role-inactivate.component.ts b/src/modules/feature-modules/admin/pages/users/roles/role-inactivate.component.ts index 3aa92e980..794a92a72 100644 --- a/src/modules/feature-modules/admin/pages/users/roles/role-inactivate.component.ts +++ b/src/modules/feature-modules/admin/pages/users/roles/role-inactivate.component.ts @@ -61,8 +61,8 @@ export class PageUsersRoleInactivateComponent extends CoreComponent implements O .map(r => ({ id: r.id, description: r.displayTeam - ? `${this.stores.authentication.getRoleDescription(r.role).toLowerCase()} (${r.displayTeam})` - : `${this.stores.authentication.getRoleDescription(r.role).toLowerCase()}` + ? `${this.ctx.user.getRoleDescription(r.role).toLowerCase()} (${r.displayTeam})` + : `${this.ctx.user.getRoleDescription(r.role).toLowerCase()}` }))[0] ?? { id: '', description: '' } }; diff --git a/src/modules/feature-modules/admin/pages/users/roles/role-new.config.ts b/src/modules/feature-modules/admin/pages/users/roles/role-new.config.ts index 0ae3f6b88..a7df48e25 100644 --- a/src/modules/feature-modules/admin/pages/users/roles/role-new.config.ts +++ b/src/modules/feature-modules/admin/pages/users/roles/role-new.config.ts @@ -3,7 +3,7 @@ import { AppInjector } from '@modules/core'; import { UserRoleEnum } from '@app/base/enums'; import { FormEngineModel, WizardEngineModel, WizardStepType, WizardSummaryType } from '@modules/shared/forms'; -import { AuthenticationStore } from '@modules/stores'; +import { CtxStore } from '@modules/stores'; // Labels. const stepsLabels = { @@ -54,7 +54,7 @@ export type OutboundPayloadType = CreateRolesType; // consts. const injector = AppInjector.getInjector(); -const authenticationStore = injector?.get(AuthenticationStore); +const ctx = injector?.get(CtxStore); export const WIZARD_ADD_ROLE: WizardEngineModel = new WizardEngineModel({ steps: [], @@ -77,7 +77,7 @@ function wizardRuntimeRules(steps: WizardStepType[], data: StepPayloadType): voi dataType: 'radio-group', label: stepsLabels.l1.label, validations: { isRequired: [true, 'Choose one role'] }, - items: data.availableRoles.map(r => ({ value: r, label: authenticationStore?.getRoleDescription(r) })) + items: data.availableRoles.map(r => ({ value: r, label: ctx.user?.getRoleDescription(r) })) } ] }) @@ -202,7 +202,7 @@ function summaryParsing(data: StepPayloadType): WizardSummaryType[] { toReturn.push({ label: 'Email', value: data.email }, { label: 'Name', value: data.name }); - const role = authenticationStore.getRoleDescription(data.role!); // Reaching this point role will be defined + const role = ctx.user.getRoleDescription(data.role!); // Reaching this point role will be defined if (data.role === UserRoleEnum.ASSESSMENT) { toReturn.push({ label: 'Role', value: role, editStepNumber: editStepNumber++ }); diff --git a/src/modules/feature-modules/admin/pages/users/user-find.component.ts b/src/modules/feature-modules/admin/pages/users/user-find.component.ts index 86de01f95..0cc4cd5e3 100644 --- a/src/modules/feature-modules/admin/pages/users/user-find.component.ts +++ b/src/modules/feature-modules/admin/pages/users/user-find.component.ts @@ -49,9 +49,7 @@ export class PageUserFindComponent extends CoreComponent implements OnInit { next: response => { this.searchUser = { ...response, - rolesDescription: [...new Set(response.roles.map(r => r.role))].map(r => - this.stores.authentication.getRoleDescription(r) - ) + rolesDescription: [...new Set(response.roles.map(r => r.role))].map(r => this.ctx.user.getRoleDescription(r)) }; this.setPageStatus('READY'); }, diff --git a/src/modules/feature-modules/admin/pages/users/user-info.component.ts b/src/modules/feature-modules/admin/pages/users/user-info.component.ts index 072c66706..f4e922a08 100644 --- a/src/modules/feature-modules/admin/pages/users/user-info.component.ts +++ b/src/modules/feature-modules/admin/pages/users/user-info.component.ts @@ -84,7 +84,7 @@ export class PageUserInfoComponent extends CoreComponent implements OnInit { this.user = { ...userInfo, rolesDescription: userInfo.roles.map(r => { - let roleDescription = this.stores.authentication.getRoleDescription(r.role); + let roleDescription = this.ctx.user.getRoleDescription(r.role); if (r.displayTeam) { roleDescription += ` (${r.displayTeam})`; } diff --git a/src/modules/feature-modules/admin/pages/users/user-manage.component.ts b/src/modules/feature-modules/admin/pages/users/user-manage.component.ts index 68d1dee5f..1b7d078ad 100644 --- a/src/modules/feature-modules/admin/pages/users/user-manage.component.ts +++ b/src/modules/feature-modules/admin/pages/users/user-manage.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { CoreComponent } from '@app/base'; import { UsersService } from '@modules/shared/services/users.service'; -import { MFAInfoDTO } from '@modules/stores/authentication/authentication.service'; +import { MFAInfo } from '@modules/stores/ctx/user/user.service'; @Component({ selector: 'app-admin-pages-users-user-manage', @@ -13,7 +13,7 @@ export class PageUserManageComponent extends CoreComponent implements OnInit { isInnovator: boolean; userId: string; - MFAInfo: MFAInfoDTO | null = null; + MFAInfo: MFAInfo | null = null; constructor( private route: ActivatedRoute, diff --git a/src/modules/feature-modules/admin/pages/users/user-new.component.spec.ts b/src/modules/feature-modules/admin/pages/users/user-new.component.spec.ts index a4a93e44e..8c61734f3 100644 --- a/src/modules/feature-modules/admin/pages/users/user-new.component.spec.ts +++ b/src/modules/feature-modules/admin/pages/users/user-new.component.spec.ts @@ -1,17 +1,18 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { Router, RouterModule } from '@angular/router'; import { of } from 'rxjs'; import { AppInjector, CoreModule } from '@modules/core'; import { AdminModule } from '@modules/feature-modules/admin/admin.module'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { AdminUsersService } from '@modules/feature-modules/admin/services/users.service'; import { OrganisationsService } from '@modules/shared/services/organisations.service'; import { PageUserNewComponent } from './user-new.component'; +import { UserContextStore } from '@modules/stores/ctx/user/user.store'; describe('FeatureModules/Admin/Pages/AdminUsers/PageAdminUserNewComponent', () => { let component: PageUserNewComponent; @@ -19,7 +20,8 @@ describe('FeatureModules/Admin/Pages/AdminUsers/PageAdminUserNewComponent', () = let router: Router; let routerSpy: jest.SpyInstance; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; + let userCtx: UserContextStore; let usersService: AdminUsersService; let organisationsService: OrganisationsService; @@ -33,9 +35,12 @@ describe('FeatureModules/Admin/Pages/AdminUsers/PageAdminUserNewComponent', () = router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); - authenticationStore = TestBed.inject(AuthenticationStore); usersService = TestBed.inject(AdminUsersService); organisationsService = TestBed.inject(OrganisationsService); + ctx = TestBed.inject(CtxStore); + userCtx = TestBed.inject(UserContextStore); + userCtx.getRoleDescription = signal('ADMIN'); + ctx.user.getRoleDescription = userCtx.getRoleDescription; organisationsService.getOrganisationsList = () => of([ diff --git a/src/modules/feature-modules/admin/pages/users/user-new.component.ts b/src/modules/feature-modules/admin/pages/users/user-new.component.ts index 464370a83..53bf8c538 100644 --- a/src/modules/feature-modules/admin/pages/users/user-new.component.ts +++ b/src/modules/feature-modules/admin/pages/users/user-new.component.ts @@ -118,7 +118,7 @@ export class PageUserNewComponent extends CoreComponent implements OnInit { this.user = { ...response, rolesDescription: response.roles.map(r => { - let roleDescription = this.stores.authentication.getRoleDescription(r.role); + let roleDescription = this.ctx.user.getRoleDescription(r.role); if (r.displayTeam) { roleDescription += ` (${r.displayTeam})`; } diff --git a/src/modules/feature-modules/admin/pages/users/user-new.config.ts b/src/modules/feature-modules/admin/pages/users/user-new.config.ts index e2191aa60..b2545ad97 100644 --- a/src/modules/feature-modules/admin/pages/users/user-new.config.ts +++ b/src/modules/feature-modules/admin/pages/users/user-new.config.ts @@ -3,7 +3,9 @@ import { AppInjector } from '@modules/core'; import { UserRoleEnum } from '@app/base/enums'; import { FormEngineModel, WizardEngineModel, WizardStepType, WizardSummaryType } from '@modules/shared/forms'; -import { AuthenticationStore } from '@modules/stores'; +import { CtxStore } from '@modules/stores'; +import { inject } from '@angular/core'; +import { UserContextStore } from '@modules/stores/ctx/user/user.store'; // Labels. const stepsLabels = { @@ -55,10 +57,10 @@ export type OutboundPayloadType = CreateUserType; // consts. const injector = AppInjector.getInjector(); -const authenticationStore = injector?.get(AuthenticationStore); +const userCtx = injector?.get(UserContextStore); const roles = [UserRoleEnum.QUALIFYING_ACCESSOR, UserRoleEnum.ACCESSOR, UserRoleEnum.ASSESSMENT, UserRoleEnum.ADMIN]; -const roleItems = roles.map(r => ({ value: r, label: authenticationStore?.getRoleDescription(r) })); +const roleItems = roles.map(r => ({ value: r, label: userCtx?.getRoleDescription(r) })); export const WIZARD_CREATE_USER: WizardEngineModel = new WizardEngineModel({ steps: [ @@ -204,7 +206,7 @@ function summaryParsing(data: StepPayloadType): WizardSummaryType[] { { label: 'Name', value: data.name, editStepNumber: editStepNumber++ } ); - const role = authenticationStore.getRoleDescription(data.role ?? UserRoleEnum.ASSESSMENT); // Reaching this point role will be defined + const role = userCtx.getRoleDescription(data.role ?? UserRoleEnum.ASSESSMENT); // Reaching this point role will be defined if (data.role === UserRoleEnum.ADMIN || data.role === UserRoleEnum.ASSESSMENT) { toReturn.push({ diff --git a/src/modules/feature-modules/admin/resolvers/organisation-data.resolver.spec.ts b/src/modules/feature-modules/admin/resolvers/organisation-data.resolver.spec.ts index 65c0a2de6..8eff0743a 100644 --- a/src/modules/feature-modules/admin/resolvers/organisation-data.resolver.spec.ts +++ b/src/modules/feature-modules/admin/resolvers/organisation-data.resolver.spec.ts @@ -6,7 +6,7 @@ import { ActivatedRouteSnapshot, RouterModule } from '@angular/router'; import { of, throwError } from 'rxjs'; import { AppInjector, CoreModule } from '@modules/core'; -import { StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { AdminModule } from '@modules/feature-modules/admin/admin.module'; import { OrganisationsService } from '@modules/shared/services/organisations.service'; import { OrganisationDataResolver } from './organisation-data.resolver'; diff --git a/src/modules/feature-modules/admin/services/admin-organisations.service.ts b/src/modules/feature-modules/admin/services/admin-organisations.service.ts index da14557fa..c13dbc0a9 100644 --- a/src/modules/feature-modules/admin/services/admin-organisations.service.ts +++ b/src/modules/feature-modules/admin/services/admin-organisations.service.ts @@ -6,8 +6,6 @@ import { CoreService } from '@app/base'; import { UrlModel } from '@app/base/models'; import { MappedObjectType } from '@app/base/types'; -import { AccessorOrganisationRoleEnum } from '@modules/stores/authentication/authentication.enums'; - export type updateOrganisationDTO = { organisationId: string; }; @@ -16,13 +14,6 @@ export type updateOrganisationUnitDTO = { unitId: string; }; -export type organisationUsersInDTO = { - id: string; - name: string; - role: AccessorOrganisationRoleEnum; -}; -export type organisationUsersOutDTO = organisationUsersInDTO & { roleDescription: string }; - export type CreateOrganisationBodyDTO = { name: string; acronym: string; diff --git a/src/modules/feature-modules/admin/services/users.service.ts b/src/modules/feature-modules/admin/services/users.service.ts index 5460ef446..caf177924 100644 --- a/src/modules/feature-modules/admin/services/users.service.ts +++ b/src/modules/feature-modules/admin/services/users.service.ts @@ -3,7 +3,7 @@ import { Observable, throwError } from 'rxjs'; import { catchError, map, take } from 'rxjs/operators'; import { CoreService } from '@app/base'; -import { AccessorOrganisationRoleEnum, TermsOfUseTypeEnum, UserRoleEnum } from '@app/base/enums'; +import { TermsOfUseTypeEnum, UserRoleEnum } from '@app/base/enums'; import { UrlModel } from '@app/base/models'; import { APIQueryParamsType, DateISOType, MappedObjectType } from '@app/base/types'; import { UserInfo } from '@modules/shared/dtos/users.dto'; @@ -15,7 +15,7 @@ export type changeUserTypeDTO = { export type changeUserRoleDTO = { role: { - name: AccessorOrganisationRoleEnum; + name: UserRoleEnum.ACCESSOR | UserRoleEnum.QUALIFYING_ACCESSOR; organisationId: string; }; }; diff --git a/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.spec.ts b/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.spec.ts index 340ba4814..069b838d1 100644 --- a/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.spec.ts +++ b/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.spec.ts @@ -1,5 +1,4 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Injector } from '@angular/core'; @@ -7,14 +6,14 @@ import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { of } from 'rxjs'; import { CoreModule, AppInjector } from '@modules/core'; -import { StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { AdminModule } from '@modules/feature-modules/admin/admin.module'; import { WizardOrganisationUnitActivateComponent } from './organisation-unit-activate.component'; -import { WizardOrganisationUnitActivateUsersStepComponent } from './steps/users-step.component'; -import { WizardSummaryWithConfirmStepComponent } from '@modules/shared/wizards/steps/summary-with-confirm-step.component'; import { OrganisationsService } from '@modules/shared/services/organisations.service'; +import { UserContextStore } from '@modules/stores/ctx/user/user.store'; +import { UserContextService } from '@modules/stores/ctx/user/user.service'; describe('FeatureModules/Admin/Wizards//WizardOrganisationUnitActivateComponent', () => { let activatedRoute: ActivatedRoute; @@ -28,7 +27,8 @@ describe('FeatureModules/Admin/Wizards//WizardOrganisationUnitActivateComponent' beforeEach(() => { TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterModule.forRoot([]), CoreModule, StoresModule, AdminModule] + imports: [HttpClientTestingModule, RouterModule.forRoot([]), CoreModule, StoresModule, AdminModule], + providers: [CtxStore, UserContextStore, UserContextService] }); AppInjector.setInjector(TestBed.inject(Injector)); diff --git a/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.ts b/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.ts index 7eea69d77..46fe4a3c8 100644 --- a/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.ts +++ b/src/modules/feature-modules/admin/wizards/organisation-unit-activate/organisation-unit-activate.component.ts @@ -137,7 +137,7 @@ export class WizardOrganisationUnitActivateComponent extends CoreComponent imple { label: 'Users', value: this.wizard.data.usersStep.users - .map(item => `${item.name} (${this.stores.authentication.getRoleDescription(item.organisationRole)})`) + .map(item => `${item.name} (${this.ctx.user.getRoleDescription(item.organisationRole)})`) .join('\n') } ], diff --git a/src/modules/feature-modules/admin/wizards/organisation-unit-activate/steps/users-step.component.ts b/src/modules/feature-modules/admin/wizards/organisation-unit-activate/steps/users-step.component.ts index c3140cc8d..aaf67ea95 100644 --- a/src/modules/feature-modules/admin/wizards/organisation-unit-activate/steps/users-step.component.ts +++ b/src/modules/feature-modules/admin/wizards/organisation-unit-activate/steps/users-step.component.ts @@ -8,9 +8,9 @@ import { MappedObjectType, WizardStepComponentType, WizardStepEventType } from ' import { UsersStepInputType, UsersStepOutputType } from './users-step.types'; -import { UserRoleEnum } from '@modules/stores/authentication/authentication.enums'; import { UserListFiltersType, UsersService } from '@modules/shared/services/users.service'; import { UsersListDTO } from '@modules/shared/dtos/users.dto'; +import { UserRoleEnum } from '@app/base/enums'; @Component({ selector: 'app-admin-wizards-organisation-unit-activate-users-step', diff --git a/src/modules/feature-modules/announcements/guards/announcements-access.guard.ts b/src/modules/feature-modules/announcements/guards/announcements-access.guard.ts index ebd7dcafc..62324f54a 100644 --- a/src/modules/feature-modules/announcements/guards/announcements-access.guard.ts +++ b/src/modules/feature-modules/announcements/guards/announcements-access.guard.ts @@ -1,31 +1,30 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; - -import { AuthenticationStore } from '@modules/stores/authentication/authentication.store'; +import { CtxStore } from '@modules/stores'; @Injectable() export class AnnouncementsAccessGuard { constructor( private router: Router, - private authentication: AuthenticationStore + private ctx: CtxStore ) {} canActivate(): boolean { - const userContext = this.authentication.getUserContextInfo(); + const userContext = this.ctx.user.getUserContext(); if (!userContext) { this.router.navigate(['/switch-user-context']); return false; } - if (!this.authentication.isTermsOfUseAccepted()) { - const path = this.authentication.userUrlBasePath() + '/terms-of-use'; + if (!this.ctx.user.isTermsOfUseAccepted()) { + const path = this.ctx.user.userUrlBasePath() + '/terms-of-use'; this.router.navigateByUrl(path); return false; } - if (!this.authentication.hasAnnouncements()) { - this.router.navigateByUrl(this.authentication.userUrlBasePath()); + if (!this.ctx.user.hasAnnouncements()) { + this.router.navigateByUrl(this.ctx.user.userUrlBasePath()); return false; } diff --git a/src/modules/feature-modules/assessment/pages/dashboard/dashboard.component.ts b/src/modules/feature-modules/assessment/pages/dashboard/dashboard.component.ts index fea589b80..0880a81cb 100644 --- a/src/modules/feature-modules/assessment/pages/dashboard/dashboard.component.ts +++ b/src/modules/feature-modules/assessment/pages/dashboard/dashboard.component.ts @@ -39,13 +39,13 @@ export class DashboardComponent extends CoreComponent implements OnInit { private announcementsService: AnnouncementsService ) { super(); - this.setPageTitle('Home', { hint: `Hello ${this.stores.authentication.getUserInfo().displayName}` }); + this.setPageTitle('Home', { hint: `Hello ${this.ctx.user.getDisplayName()}` }); this.user = { - displayName: this.stores.authentication.getUserInfo().displayName, + displayName: this.ctx.user.getDisplayName(), organisation: 'Needs assessment team', - passwordResetAt: this.stores.authentication.getUserInfo().passwordResetAt || '', - firstTimeSignInAt: this.stores.authentication.getUserInfo().firstTimeSignInAt + passwordResetAt: this.ctx.user.getUserInfo().passwordResetAt ?? '', + firstTimeSignInAt: this.ctx.user.getUserInfo().firstTimeSignInAt }; this.latestInnovations = new TableModel({ pageSize: 5 }); @@ -57,7 +57,7 @@ export class DashboardComponent extends CoreComponent implements OnInit { const newState = history.state; delete newState.alert; history.replaceState(newState, ''); - this.stores.authentication.userPasswordSuccessfullyUpdated(); + this.ctx.user.updateInfo({ passwordChangeSinceLastSignIn: true }); } const qp: { statistics: UserStatisticsTypeEnum[] } = { diff --git a/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-info.component.ts b/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-info.component.ts index 48eb511fa..a4a541ec1 100644 --- a/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-info.component.ts +++ b/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-info.component.ts @@ -26,10 +26,7 @@ export class InnovationAssessmentExemptionInfoComponent extends CoreComponent im this.innovationId = this.activatedRoute.snapshot.params.innovationId; this.assessmentId = this.activatedRoute.snapshot.params.assessmentId; - this.setBackLink( - 'Go back', - `${this.stores.authentication.userUrlBasePath()}/innovations/${this.innovationId}/overview` - ); + this.setBackLink('Go back', `${this.ctx.user.userUrlBasePath()}/innovations/${this.innovationId}/overview`); this.setPageTitle('Innovation exempt from key performance indicator (KPI) reports'); } diff --git a/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-upsert.component.ts b/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-upsert.component.ts index 685cbb3eb..da26c2bc2 100644 --- a/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-upsert.component.ts +++ b/src/modules/feature-modules/assessment/pages/innovation/assessment/exemption-upsert.component.ts @@ -32,7 +32,7 @@ export class InnovationAssessmentExemptionUpsertComponent extends CoreComponent this.innovationId = this.activatedRoute.snapshot.params.innovationId; this.assessmentId = this.activatedRoute.snapshot.params.assessmentId; - this.baseUrl = `${this.stores.authentication.userUrlBasePath()}/innovations/${this.innovationId}/overview`; + this.baseUrl = `${this.ctx.user.userUrlBasePath()}/innovations/${this.innovationId}/overview`; this.setBackLink(); this.setPageTitle('Exempt this innovation from KPI reports'); diff --git a/src/modules/feature-modules/assessment/services/assessment.service.spec.ts b/src/modules/feature-modules/assessment/services/assessment.service.spec.ts index 3ec386fb2..a02e0d099 100644 --- a/src/modules/feature-modules/assessment/services/assessment.service.spec.ts +++ b/src/modules/feature-modules/assessment/services/assessment.service.spec.ts @@ -3,10 +3,10 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { ENV } from '@tests/app.mocks'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { AppInjector, CoreModule, EnvironmentVariablesStore } from '@modules/core'; -import { StoresModule, AuthenticationStore } from '@modules/stores'; +import { StoresModule, CtxStore } from '@modules/stores'; import { AssessmentModule } from '@modules/feature-modules/assessment/assessment.module'; import { AssessmentService } from './assessment.service'; @@ -15,7 +15,7 @@ describe('FeatureModules/Assessment/Services/AssessmentService', () => { let httpMock: HttpTestingController; let envVariablesStore: EnvironmentVariablesStore; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let service: AssessmentService; @@ -30,11 +30,11 @@ describe('FeatureModules/Assessment/Services/AssessmentService', () => { httpMock = TestBed.inject(HttpTestingController); envVariablesStore = TestBed.inject(EnvironmentVariablesStore); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); service = TestBed.inject(AssessmentService); - authenticationStore.getUserId = () => 'UserId01'; + ctx.user.getUserId = signal('UserId01'); }); afterEach(() => { diff --git a/src/modules/feature-modules/innovator/guards/check-role.guard.ts b/src/modules/feature-modules/innovator/guards/check-role.guard.ts index 77656da7d..04a95dfe9 100644 --- a/src/modules/feature-modules/innovator/guards/check-role.guard.ts +++ b/src/modules/feature-modules/innovator/guards/check-role.guard.ts @@ -1,14 +1,14 @@ import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { UserRoleEnum } from '@app/base/enums'; -import { AuthenticationStore } from '@modules/stores'; +import { CtxStore } from '@modules/stores'; export function checkRoleGuard(roles: UserRoleEnum[]): CanActivateFn { return () => { const router: Router = inject(Router); - const authenticationStore: AuthenticationStore = inject(AuthenticationStore); + const ctx: CtxStore = inject(CtxStore); - const userType: UserRoleEnum | undefined = authenticationStore.getUserType(); + const userType: UserRoleEnum | undefined = ctx.user.getUserType(); if (userType !== undefined && roles.includes(userType)) { return true; diff --git a/src/modules/feature-modules/innovator/guards/check-status.guard.ts b/src/modules/feature-modules/innovator/guards/check-status.guard.ts index 1467a7344..6486d5eea 100644 --- a/src/modules/feature-modules/innovator/guards/check-status.guard.ts +++ b/src/modules/feature-modules/innovator/guards/check-status.guard.ts @@ -1,5 +1,5 @@ import { inject } from '@angular/core'; -import { AuthenticationStore, CtxStore, InnovationStatusEnum } from '@modules/stores'; +import { CtxStore, InnovationStatusEnum } from '@modules/stores'; import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; import { catchError, map } from 'rxjs/operators'; import { of } from 'rxjs'; @@ -8,27 +8,24 @@ export function checkStatusGuard(statusList: InnovationStatusEnum[], blockList = return (route: ActivatedRouteSnapshot) => { const router: Router = inject(Router); const ctx: CtxStore = inject(CtxStore); - const authenticationStore: AuthenticationStore = inject(AuthenticationStore); - return ctx.innovation - .getOrLoadInnovation$(route.params.innovationId, authenticationStore.getUserContextInfo()) - .pipe( - map(contextInfo => { - const allowStatusCheck = blockList - ? !statusList.includes(contextInfo.status) - : statusList.includes(contextInfo.status); + return ctx.innovation.getOrLoadInnovation$(route.params.innovationId, ctx.user.getUserContext()).pipe( + map(contextInfo => { + const allowStatusCheck = blockList + ? !statusList.includes(contextInfo.status) + : statusList.includes(contextInfo.status); - if (allowStatusCheck) { - return true; - } else { - router.navigateByUrl('error/forbidden-innovation'); - return false; - } - }), - catchError(() => { - router.navigateByUrl('error/generic'); - return of(false); - }) - ); + if (allowStatusCheck) { + return true; + } else { + router.navigateByUrl('error/forbidden-innovation'); + return false; + } + }), + catchError(() => { + router.navigateByUrl('error/generic'); + return of(false); + }) + ); }; } diff --git a/src/modules/feature-modules/innovator/guards/first-time-signin.guard.spec.ts b/src/modules/feature-modules/innovator/guards/first-time-signin.guard.spec.ts index 3ce1e32ac..c35f59c3d 100644 --- a/src/modules/feature-modules/innovator/guards/first-time-signin.guard.spec.ts +++ b/src/modules/feature-modules/innovator/guards/first-time-signin.guard.spec.ts @@ -1,17 +1,17 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { ActivatedRouteSnapshot, Router, RouterModule, RouterStateSnapshot } from '@angular/router'; import { AppInjector, CoreModule } from '@modules/core'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; import { FirstTimeSigninGuard } from './first-time-signin.guard'; describe('FeatureModules/Innovator/Guards/FirstTimeSigninGuard', () => { let guard: FirstTimeSigninGuard; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let routerStateSnapshopMock: Partial; @@ -24,7 +24,7 @@ describe('FeatureModules/Innovator/Guards/FirstTimeSigninGuard', () => { AppInjector.setInjector(TestBed.inject(Injector)); guard = TestBed.inject(FirstTimeSigninGuard); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); routerStateSnapshopMock = { url: '' }; }); @@ -62,7 +62,7 @@ describe('FeatureModules/Innovator/Guards/FirstTimeSigninGuard', () => { const routerSpy = jest.spyOn(TestBed.inject(Router), 'navigate'); let expected: null | boolean = null; - authenticationStore.hasInnovationTransfers = () => true; + ctx.user.hasInnovationTransfers = signal(true); guard.canActivateChild(routeMock as any, routerStateSnapshopMock as any).subscribe(response => { expected = response; @@ -76,7 +76,7 @@ describe('FeatureModules/Innovator/Guards/FirstTimeSigninGuard', () => { const routeMock: Partial = { routeConfig: { path: 'first-time-signin' } }; let expected: null | boolean = null; - authenticationStore.hasInnovationTransfers = () => false; + ctx.user.hasInnovationTransfers = signal(false); guard.canActivateChild(routeMock as any, routerStateSnapshopMock as any).subscribe(response => { expected = response; @@ -89,7 +89,7 @@ describe('FeatureModules/Innovator/Guards/FirstTimeSigninGuard', () => { const routerSpy = jest.spyOn(TestBed.inject(Router), 'navigate'); let expected: null | boolean = null; - authenticationStore.hasInnovationTransfers = () => false; + ctx.user.hasInnovationTransfers = signal(false); guard.canActivateChild(routeMock as any, routerStateSnapshopMock as any).subscribe(response => { expected = response; @@ -105,7 +105,7 @@ describe('FeatureModules/Innovator/Guards/FirstTimeSigninGuard', () => { const routerStateSnapshopMock: Partial = { url: 'terms-of-use' }; let expected: null | boolean = null; - authenticationStore.hasInnovationTransfers = () => false; + ctx.user.hasInnovationTransfers = signal(false); guard.canActivateChild(routeMock as any, routerStateSnapshopMock as any).subscribe(response => { expected = response; diff --git a/src/modules/feature-modules/innovator/guards/first-time-signin.guard.ts b/src/modules/feature-modules/innovator/guards/first-time-signin.guard.ts index 9eaa72f35..598ff571b 100644 --- a/src/modules/feature-modules/innovator/guards/first-time-signin.guard.ts +++ b/src/modules/feature-modules/innovator/guards/first-time-signin.guard.ts @@ -2,13 +2,13 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { Observable, of } from 'rxjs'; -import { AuthenticationStore } from '@modules/stores/authentication/authentication.store'; +import { CtxStore } from '@modules/stores'; @Injectable() export class FirstTimeSigninGuard { constructor( private router: Router, - private authenticationStore: AuthenticationStore + private ctx: CtxStore ) {} canActivateChild(activatedRouteSnapshot: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { @@ -16,7 +16,7 @@ export class FirstTimeSigninGuard { return of(true); } - if (this.authenticationStore.isFirstTimeSignInDone()) { + if (this.ctx.user.isFirstTimeSignInDone()) { // Don't allow to access First Time Signin, if already has been done. if (!['first-time-signin', ':id'].includes(activatedRouteSnapshot.routeConfig?.path || '')) { return of(true); diff --git a/src/modules/feature-modules/innovator/guards/manage.guard.ts b/src/modules/feature-modules/innovator/guards/manage.guard.ts index 126dbd176..08e13d696 100644 --- a/src/modules/feature-modules/innovator/guards/manage.guard.ts +++ b/src/modules/feature-modules/innovator/guards/manage.guard.ts @@ -2,14 +2,14 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { catchError, map, Observable, of } from 'rxjs'; -import { AuthenticationStore } from '@modules/stores'; +import { CtxStore } from '@modules/stores'; import { InnovationsService } from '@modules/shared/services/innovations.service'; @Injectable() export class ManageGuard { constructor( private router: Router, - private authenticationStore: AuthenticationStore, + private ctx: CtxStore, private innovationsService: InnovationsService ) {} @@ -19,7 +19,7 @@ export class ManageGuard { // For now, it must be like this as guards run always before resolvers on refresh (even if on children like this one) return this.innovationsService.getInnovationInfo(route.params.innovationId).pipe( map(response => { - const userContext = this.authenticationStore.getUserContextInfo(); + const userContext = this.ctx.user.getUserContext(); const loggedUser = { isOwner: response.owner ? response.owner.id === userContext?.id : false }; if (state.url.includes('manage/innovation')) { diff --git a/src/modules/feature-modules/innovator/pages/account/account-delete.component.spec.ts b/src/modules/feature-modules/innovator/pages/account/account-delete.component.spec.ts index a9fad68cc..e3ede2e91 100644 --- a/src/modules/feature-modules/innovator/pages/account/account-delete.component.spec.ts +++ b/src/modules/feature-modules/innovator/pages/account/account-delete.component.spec.ts @@ -4,15 +4,13 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Injector } from '@angular/core'; import { CoreModule, AppInjector } from '@modules/core'; -import { StoresModule, AuthenticationStore } from '@modules/stores'; +import { StoresModule } from '@modules/stores'; import { InnovatorModule } from '@modules/feature-modules/innovator/innovator.module'; import { PageAccountDeleteComponent } from './account-delete.component'; import { RouterModule } from '@angular/router'; describe('FeatureModules/Innovator/Pages/Account/PageAccountDeleteComponent', () => { - let authenticationStore: AuthenticationStore; - let component: PageAccountDeleteComponent; let fixture: ComponentFixture; @@ -22,8 +20,6 @@ describe('FeatureModules/Innovator/Pages/Account/PageAccountDeleteComponent', () }); AppInjector.setInjector(TestBed.inject(Injector)); - - authenticationStore = TestBed.inject(AuthenticationStore); }); it('should create the component', () => { diff --git a/src/modules/feature-modules/innovator/pages/account/account-delete.component.ts b/src/modules/feature-modules/innovator/pages/account/account-delete.component.ts index 948a4221d..68f5d525f 100644 --- a/src/modules/feature-modules/innovator/pages/account/account-delete.component.ts +++ b/src/modules/feature-modules/innovator/pages/account/account-delete.component.ts @@ -48,13 +48,13 @@ export class PageAccountDeleteComponent extends CoreComponent implements OnInit this.setBackLink('Go back', this.onSubmitStep.bind(this, 'previous')); - const email = this.stores.authentication.getUserInfo().email; - const roleId = this.stores.authentication.getUserContextInfo()?.roleId; + const email = this.ctx.user.getUserInfo().email; + const roleId = this.ctx.user.getUserContext()?.roleId; this.innovator = { email: email, roleId: roleId, isOwner: false, - isCollaborator: this.stores.authentication.hasInnovationCollaborations(), + isCollaborator: this.ctx.user.hasInnovationCollaborations(), hasCollaborators: false, hasPendingTransfer: false, hasOnlyPendingTransfers: false, @@ -125,7 +125,7 @@ export class PageAccountDeleteComponent extends CoreComponent implements OnInit this.redirectTo(previousUrl); } } else { - this.redirectTo(`/${this.stores.authentication.userUrlBasePath()}/dashboard`); + this.redirectTo(`/${this.ctx.user.userUrlBasePath()}/dashboard`); } return; } else if (this.stepNumber === 3 && !this.innovator.hasPendingTransfer) { diff --git a/src/modules/feature-modules/innovator/pages/dashboard/dashboard.component.ts b/src/modules/feature-modules/innovator/pages/dashboard/dashboard.component.ts index 4131e057d..333d820d0 100644 --- a/src/modules/feature-modules/innovator/pages/dashboard/dashboard.component.ts +++ b/src/modules/feature-modules/innovator/pages/dashboard/dashboard.component.ts @@ -63,7 +63,7 @@ export class PageDashboardComponent extends CoreComponent implements OnInit { ) { super(); - const user = this.stores.authentication.getUserInfo(); + const user = this.ctx.user.getUserInfo(); this.user = { displayName: user.displayName, innovationsOwner: [], @@ -82,7 +82,7 @@ export class PageDashboardComponent extends CoreComponent implements OnInit { const newState = history.state; delete newState.alert; history.replaceState(newState, ''); - this.stores.authentication.userPasswordSuccessfullyUpdated(); + this.ctx.user.updateInfo({ passwordChangeSinceLastSignIn: true }); } forkJoin([ @@ -162,7 +162,7 @@ export class PageDashboardComponent extends CoreComponent implements OnInit { } }), concatMap( - () => this.stores.authentication.initializeAuthentication$() // Initialize authentication in order to update First Time SignIn information. + () => this.ctx.user.initializeAuthentication$() // Initialize authentication in order to update First Time SignIn information. ), concatMap(() => forkJoin([ diff --git a/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.spec.ts b/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.spec.ts index 181c061e0..a8e119787 100644 --- a/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.spec.ts +++ b/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.spec.ts @@ -6,7 +6,7 @@ import { Router, RouterModule } from '@angular/router'; import { AppInjector, CoreModule } from '@modules/core'; import { InnovatorModule } from '@modules/feature-modules/innovator/innovator.module'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { StoresModule } from '@modules/stores'; import { FirstTimeSigninComponent } from './first-time-signin.component'; @@ -16,7 +16,6 @@ describe('FeatureModules/Innovator/Pages/FirstTimeSignin/FirstTimeSigninComponen let router: Router; let routerSpy: jest.SpyInstance; - let authenticationStore: AuthenticationStore; let innovatorService: InnovatorService; let component: FirstTimeSigninComponent; @@ -32,7 +31,6 @@ describe('FeatureModules/Innovator/Pages/FirstTimeSignin/FirstTimeSigninComponen router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); - authenticationStore = TestBed.inject(AuthenticationStore); innovatorService = TestBed.inject(InnovatorService); }); diff --git a/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.ts b/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.ts index f0dd2352b..0be78be5b 100644 --- a/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.ts +++ b/src/modules/feature-modules/innovator/pages/first-time-signin/first-time-signin.component.ts @@ -68,13 +68,13 @@ export class FirstTimeSigninComponent extends CoreComponent implements OnInit { of(true) .pipe( concatMap(() => - this.stores.authentication.updateUserInfo$({ + this.ctx.user.updateUserInfo$({ displayName: wizardData.innovatorName, mobilePhone: UtilsHelper.isEmpty(wizardData.mobilePhone) ? null : wizardData.mobilePhone, organisation: wizardData.organisation ? { - id: this.stores.authentication.getUserInfo().organisations[0].id, + id: this.ctx.user.getUserInfo().organisations[0].id, isShadow: false, name: wizardData.organisation.name, size: wizardData.organisation.size, @@ -82,7 +82,7 @@ export class FirstTimeSigninComponent extends CoreComponent implements OnInit { registrationNumber: wizardData.organisation.registrationNumber } : { - id: this.stores.authentication.getUserInfo().organisations[0].id, + id: this.ctx.user.getUserInfo().organisations[0].id, isShadow: true }, howDidYouFindUsAnswers: wizardData.howDidYouFindUsAnswers @@ -90,7 +90,8 @@ export class FirstTimeSigninComponent extends CoreComponent implements OnInit { ), // Initialize authentication in order to update First Time SignIn information. - concatMap(() => this.stores.authentication.initializeAuthentication$()) + // TODO: try to remove this by updating the state when calling updateUserInfo$ + concatMap(() => this.ctx.user.initializeAuthentication$()) ) .subscribe({ next: () => { diff --git a/src/modules/feature-modules/innovator/pages/innovation-new/innovation-new.component.ts b/src/modules/feature-modules/innovator/pages/innovation-new/innovation-new.component.ts index d6ab226bf..784ea734a 100644 --- a/src/modules/feature-modules/innovator/pages/innovation-new/innovation-new.component.ts +++ b/src/modules/feature-modules/innovator/pages/innovation-new/innovation-new.component.ts @@ -65,7 +65,7 @@ export class InnovationNewComponent extends CoreComponent implements OnInit { .createInnovation(body) .pipe( concatMap(response => { - this.stores.authentication.initializeAuthentication$(); // Initialize authentication in order to update innovations information. + this.ctx.user.initializeAuthentication$(); // Initialize authentication in order to update innovations information. return of(response); }) ) diff --git a/src/modules/feature-modules/innovator/pages/innovation/manage/manage-collaborators-overview.component.ts b/src/modules/feature-modules/innovator/pages/innovation/manage/manage-collaborators-overview.component.ts index 5b3c9c428..ff7ce4c88 100644 --- a/src/modules/feature-modules/innovator/pages/innovation/manage/manage-collaborators-overview.component.ts +++ b/src/modules/feature-modules/innovator/pages/innovation/manage/manage-collaborators-overview.component.ts @@ -31,7 +31,7 @@ export class PageInnovationManageCollaboratorsOverviewComponent extends CoreComp this.innovation = this.ctx.innovation.info(); - const user = this.stores.authentication.getUserInfo(); + const user = this.ctx.user.getUserInfo(); this.user = { id: user.id, name: user.displayName, email: user.email }; this.setPageTitle('Invite or manage collaborators'); diff --git a/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.spec.ts b/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.spec.ts index 3b1cee20c..ecc588673 100644 --- a/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.spec.ts +++ b/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.spec.ts @@ -3,10 +3,9 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Injector } from '@angular/core'; import { Router, RouterModule } from '@angular/router'; -import { of, throwError } from 'rxjs'; import { CoreModule, AppInjector } from '@modules/core'; -import { StoresModule, AuthenticationStore } from '@modules/stores'; +import { StoresModule } from '@modules/stores'; import { InnovatorModule } from '@modules/feature-modules/innovator/innovator.module'; import { InnovationsService } from '@modules/shared/services/innovations.service'; @@ -17,7 +16,6 @@ describe('FeatureModules/Innovator/Pages/Account/ManageInnovations/PageAccountIn let router: Router; let routerSpy: jest.SpyInstance; - let authenticationStore: AuthenticationStore; let innovationsService: InnovationsService; let innovatorService: InnovatorService; @@ -34,7 +32,6 @@ describe('FeatureModules/Innovator/Pages/Account/ManageInnovations/PageAccountIn router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); - authenticationStore = TestBed.inject(AuthenticationStore); innovationsService = TestBed.inject(InnovationsService); innovatorService = TestBed.inject(InnovatorService); }); diff --git a/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.ts b/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.ts index f5c519c01..394e1d2ad 100644 --- a/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.ts +++ b/src/modules/feature-modules/innovator/pages/innovation/manage/manage-transfer.component.ts @@ -54,7 +54,7 @@ export class PageInnovationManageTransferComponent extends CoreComponent impleme } ngOnInit(): void { - const myEmail = this.stores.authentication.getUserInfo().email; + const myEmail = this.ctx.user.getUserInfo().email; this.wizard = cloneDeep(NO_COLLABORATORS_TRANSFERS(myEmail)); this.innovationsService.getInnovationCollaboratorsList(this.innovationId, ['active']).subscribe(response => { diff --git a/src/modules/feature-modules/innovator/pages/innovation/manage/wizard-manage-archive/steps/confirmation-step.component.ts b/src/modules/feature-modules/innovator/pages/innovation/manage/wizard-manage-archive/steps/confirmation-step.component.ts index 0f86830a6..aba089a49 100644 --- a/src/modules/feature-modules/innovator/pages/innovation/manage/wizard-manage-archive/steps/confirmation-step.component.ts +++ b/src/modules/feature-modules/innovator/pages/innovation/manage/wizard-manage-archive/steps/confirmation-step.component.ts @@ -44,7 +44,7 @@ export class WizardInnovationManageArchiveConfirmationStepComponent super(); this.innovationId = this.activatedRoute.snapshot.params.innovationId; - this.userEmail = this.stores.authentication.getUserInfo().email; + this.userEmail = this.ctx.user.getUserInfo().email; this.form.controls.email.addValidators(CustomValidators.equalTo(this.userEmail)); diff --git a/src/modules/feature-modules/innovator/pages/innovation/needs-reassessment/needs-reassessment-send.component.ts b/src/modules/feature-modules/innovator/pages/innovation/needs-reassessment/needs-reassessment-send.component.ts index 86ca0cbcd..8f32d7bd0 100644 --- a/src/modules/feature-modules/innovator/pages/innovation/needs-reassessment/needs-reassessment-send.component.ts +++ b/src/modules/feature-modules/innovator/pages/innovation/needs-reassessment/needs-reassessment-send.component.ts @@ -91,7 +91,7 @@ export class PageInnovationNeedsReassessmentSendComponent extends CoreComponent if (previousUrl) { this.redirectTo(previousUrl); } else { - this.redirectTo(`/${this.stores.authentication.userUrlBasePath()}/dashboard`); + this.redirectTo(`/${this.ctx.user.userUrlBasePath()}/dashboard`); } } else { this.wizard.previousStep(); diff --git a/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.html b/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.html index 6314a2c9a..27cd53740 100644 --- a/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.html +++ b/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.html @@ -1,4 +1,5 @@ -
+ +
@@ -25,7 +26,7 @@
diff --git a/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.ts b/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.ts index 0e85d0d78..2d9af0e50 100644 --- a/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.ts +++ b/src/modules/feature-modules/innovator/pages/innovation/record/section-edit.component.ts @@ -42,9 +42,6 @@ export class InnovationSectionEditComponent extends CoreComponent implements OnI displayChangeButtonList: number[] = []; - // Flags - isInnovatorType: boolean; - constructor(private activatedRoute: ActivatedRoute) { super(); @@ -60,9 +57,6 @@ export class InnovationSectionEditComponent extends CoreComponent implements OnI this.isArchived = this.ctx.innovation.isArchived(); - // Flags - this.isInnovatorType = this.stores.authentication.isInnovatorType(); - this.setBackLink('Go back', this.onSubmitStep.bind(this, 'previous')); } diff --git a/src/modules/feature-modules/innovator/services/innovator.service.spec.ts b/src/modules/feature-modules/innovator/services/innovator.service.spec.ts index 373a422ab..9f4683952 100644 --- a/src/modules/feature-modules/innovator/services/innovator.service.spec.ts +++ b/src/modules/feature-modules/innovator/services/innovator.service.spec.ts @@ -3,10 +3,10 @@ import { TestBed } from '@angular/core/testing'; import { ENV } from '@tests/app.mocks'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { AppInjector, CoreModule, EnvironmentVariablesStore } from '@modules/core'; -import { AuthenticationStore, StoresModule, InnovationTransferStatusEnum } from '@modules/stores'; +import { StoresModule, InnovationTransferStatusEnum, CtxStore } from '@modules/stores'; import { InnovatorService } from './innovator.service'; @@ -14,7 +14,7 @@ describe('FeatureModules/Innovator/InnovatorService', () => { let httpMock: HttpTestingController; let envVariablesStore: EnvironmentVariablesStore; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let service: InnovatorService; beforeEach(() => { @@ -28,10 +28,10 @@ describe('FeatureModules/Innovator/InnovatorService', () => { httpMock = TestBed.inject(HttpTestingController); envVariablesStore = TestBed.inject(EnvironmentVariablesStore); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); service = TestBed.inject(InnovatorService); - authenticationStore.getUserId = () => 'UserId01'; + ctx.user.getUserId = signal('UserId01'); }); afterEach(() => { diff --git a/src/modules/feature-modules/innovator/services/innovator.service.ts b/src/modules/feature-modules/innovator/services/innovator.service.ts index b6130473e..60a710998 100644 --- a/src/modules/feature-modules/innovator/services/innovator.service.ts +++ b/src/modules/feature-modules/innovator/services/innovator.service.ts @@ -85,7 +85,7 @@ export class InnovatorService extends CoreService { submitOrganisationSharing(innovationId: string, body: MappedObjectType): Observable<{ id: string }> { const url = new UrlModel(this.API_INNOVATIONS_URL) .addPath('v1/:innovationId/shares') - .setPathParams({ userId: this.stores.authentication.getUserId(), innovationId }); + .setPathParams({ userId: this.ctx.user.getUserId(), innovationId }); return this.http.put<{ id: string }>(url.buildUrl(), body).pipe( take(1), map(response => response) diff --git a/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.html b/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.html index 633b4db74..b95e31eb4 100644 --- a/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.html +++ b/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.html @@ -1,12 +1,13 @@ -
-
+ + +
Important: You could miss time sensitive service reminders
-

+

If you do not select 'innovator submits innovation record' or 'assigned needs assessor' notifications, you could miss time sensitive service reminders.

-

If you do not select 'suggestions to support', you could miss time sensitive service reminders.

+

If you do not select 'suggestions to support', you could miss time sensitive service reminders.

diff --git a/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.spec.ts b/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.spec.ts index 7eaf83f50..1190b7c54 100644 --- a/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.spec.ts +++ b/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.spec.ts @@ -1,14 +1,14 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { AppInjector, CoreModule } from '@modules/core'; import { SharedModule } from '@modules/shared/shared.module'; -import { AuthenticationStore, StoresModule } from '@modules/stores'; +import { CtxStore, StoresModule } from '@modules/stores'; -import { NotificationCategoryTypeEnum, NotificationsService } from '@modules/shared/services/notifications.service'; +import { NotificationCategoryTypeEnum } from '@modules/shared/services/notifications.service'; import { PageAccountEmailNotificationsEditComponent } from './email-notifications-edit.component'; @@ -17,8 +17,7 @@ describe('Shared/Pages/Account/EmailNotifications/PageAccountEmailNotificationsE let router: Router; let routerSpy: jest.SpyInstance; - let authenticationStore: AuthenticationStore; - let notificationsService: NotificationsService; + let ctx: CtxStore; let component: PageAccountEmailNotificationsEditComponent; let fixture: ComponentFixture; @@ -34,10 +33,9 @@ describe('Shared/Pages/Account/EmailNotifications/PageAccountEmailNotificationsE router = TestBed.inject(Router); routerSpy = jest.spyOn(router, 'navigate'); - authenticationStore = TestBed.inject(AuthenticationStore); - notificationsService = TestBed.inject(NotificationsService); + ctx = TestBed.inject(CtxStore); - authenticationStore.userUrlBasePath = () => 'innovator'; + ctx.user.userUrlBasePath = signal('innovator'); activatedRoute.snapshot.params = { notificationType: NotificationCategoryTypeEnum.SUPPORT }; }); diff --git a/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.ts b/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.ts index db4d505d1..53702e7c5 100644 --- a/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.ts +++ b/src/modules/shared/pages/account/email-notifications/email-notifications-edit.component.ts @@ -9,8 +9,7 @@ import { NotificationPreferenceEnum, NotificationsService } from '@modules/shared/services/notifications.service'; -import { AuthenticationStore } from '@modules/stores'; -import { AuthenticationModel } from '@modules/stores/authentication/authentication.models'; +import { UserContextType } from '@modules/stores/ctx/user/user.types'; @Component({ selector: 'shared-pages-account-email-notifications-edit', @@ -19,11 +18,7 @@ import { AuthenticationModel } from '@modules/stores/authentication/authenticati export class PageAccountEmailNotificationsEditComponent extends CoreComponent implements OnInit { notificationListLink: string; - // Flags - isAssessmentType: boolean; - isQualifyingAccessorRole: boolean; - - currentUserContext: AuthenticationModel['userContext']; + currentUserContext: UserContextType['domainContext']; formPreferencesList: { value: string; label: string; description: string }[] = []; preferencesResponse: EmailNotificationPreferencesDTO = {}; @@ -35,18 +30,12 @@ export class PageAccountEmailNotificationsEditComponent extends CoreComponent im { updateOn: 'blur' } ); - constructor( - private notificationsService: NotificationsService, - private authenticationStore: AuthenticationStore - ) { + constructor(private notificationsService: NotificationsService) { super(); - this.notificationListLink = `/${this.stores.authentication.userUrlBasePath()}/account/email-notifications`; - - this.isAssessmentType = this.stores.authentication.isAssessmentType(); - this.isQualifyingAccessorRole = this.stores.authentication.isQualifyingAccessorRole(); + this.notificationListLink = `/${this.ctx.user.userUrlBasePath()}/account/email-notifications`; - this.currentUserContext = this.authenticationStore.getUserContextInfo(); + this.currentUserContext = this.ctx.user.getUserContext(); this.setPageTitle('Select the email notifications you want to receive', { width: '2.thirds', size: 'l' }); diff --git a/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.html b/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.html index 9736328de..2ff6eec25 100644 --- a/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.html +++ b/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.html @@ -1,8 +1,9 @@ -

Email notification preferences by category

+ +

Email notification preferences by category

-
+

If you update your email preferences they will only apply to the profile you are logged in with.

You are logged in as {{ this.displayName }}, {{ currentRole.description }}.

diff --git a/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.ts b/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.ts index 85c4666df..9bbf52dff 100644 --- a/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.ts +++ b/src/modules/shared/pages/account/email-notifications/email-notifications-list.component.ts @@ -7,8 +7,7 @@ import { NotificationPreferenceEnum, NotificationsService } from '@modules/shared/services/notifications.service'; -import { AuthenticationStore } from '@modules/stores'; -import { AuthenticationModel } from '@modules/stores/authentication/authentication.models'; +import { UserContextType } from '@modules/stores/ctx/user/user.types'; @Component({ selector: 'app-assessment-account-email-notifications-list', @@ -20,34 +19,29 @@ export class PageAccountEmailNotificationsListComponent extends CoreComponent im currentRole: null | { id: string; description: string }; displayName: string; - currentUserContext: AuthenticationModel['userContext']; + currentUserContext: UserContextType['domainContext']; formPreferencesList: { value: string; cssClass: string; preference: string; title: string; description: string }[] = []; preferencesResponse: EmailNotificationPreferencesDTO; - constructor( - private notificationsService: NotificationsService, - private authenticationStore: AuthenticationStore - ) { + constructor(private notificationsService: NotificationsService) { super(); this.setPageTitle('Email preferences'); - this.displayName = this.authenticationStore.getUserInfo().displayName; + this.displayName = this.ctx.user.getDisplayName(); - this.currentUserContext = this.authenticationStore.getUserContextInfo(); + this.currentUserContext = this.ctx.user.getUserContext(); if (!this.currentUserContext) { this.currentRole = null; } else { this.currentRole = { id: this.currentUserContext.roleId, - description: `${this.authenticationStore.getRoleDescription(this.currentUserContext.type)}${ - this.authenticationStore.isAccessorType() - ? ` (${this.currentUserContext.organisationUnit?.name.trimEnd()})` - : '' + description: `${this.ctx.user.getRoleDescription(this.currentUserContext.type)}${ + this.ctx.user.isAccessorType() ? ` (${this.currentUserContext.organisationUnit?.name.trimEnd()})` : '' }` }; } @@ -57,7 +51,6 @@ export class PageAccountEmailNotificationsListComponent extends CoreComponent im ngOnInit(): void { this.getEmailNotificationTypes(); - this.checkMultipleRoles(); } private getEmailNotificationTypes(): void { @@ -104,14 +97,6 @@ export class PageAccountEmailNotificationsListComponent extends CoreComponent im }); } - private checkMultipleRoles(): void { - this.setPageStatus('LOADING'); - - const user = this.authenticationStore.getUserInfo(); - - this.hasMultipleRoles = user.roles.length > 1; - } - private getCategoryMessages(category: string): { title: string; description: string } { const role = this.currentUserContext?.type; diff --git a/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.html b/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.html index 774440ae0..6dfb1e391 100644 --- a/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.html +++ b/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.html @@ -11,7 +11,7 @@

Change your password

-
+

Delete your account

You will need to confirm your email address to delete your account.

diff --git a/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.ts b/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.ts index a5c1700e5..414921f52 100644 --- a/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.ts +++ b/src/modules/shared/pages/account/manage-account-info/manage-account-info.component.ts @@ -2,8 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { CoreComponent } from '@app/base'; import { DateISOType } from '@app/base/types'; -import { AuthenticationService } from '@modules/stores'; -import { MFAInfoDTO } from '@modules/stores/authentication/authentication.service'; +import { MFAInfo, UserContextService } from '@modules/stores/ctx/user/user.service'; @Component({ selector: 'shared-pages-account-manage-account-info', @@ -16,22 +15,21 @@ export class PageSharedAccountManageAccountInfoComponent extends CoreComponent i passwordResetAt: null | DateISOType; }; - MFAInfo: MFAInfoDTO | null = null; + MFAInfo: MFAInfo | null = null; - isInnovator: boolean = this.stores.authentication.isInnovatorType(); - - constructor(private authenticationService: AuthenticationService) { + constructor(private userCtxService: UserContextService) { super(); this.setPageTitle('Manage account'); - const user = this.stores.authentication.getUserInfo(); + // TODO: Check this component, can problem remove all of this calls and just use the state. + const user = this.ctx.user.getUserInfo(); this.user = { passwordResetAt: user.passwordResetAt }; if (user.passwordChangeSinceLastSignIn) { - this.authenticationService.getUserInfo(true).subscribe({ + this.userCtxService.getUserInfo(true).subscribe({ next: updatedUser => { this.user = { passwordResetAt: updatedUser.passwordResetAt @@ -45,7 +43,7 @@ export class PageSharedAccountManageAccountInfoComponent extends CoreComponent i } ngOnInit(): void { - this.authenticationService.getUserMFAInfo().subscribe({ + this.userCtxService.getUserMFAInfo().subscribe({ next: response => { this.MFAInfo = response; this.setPageStatus('READY'); diff --git a/src/modules/shared/pages/account/manage-details/manage-details-edit-accessor.config.ts b/src/modules/shared/pages/account/manage-details/manage-details-edit-accessor.config.ts index a135b79c1..6842136a6 100644 --- a/src/modules/shared/pages/account/manage-details/manage-details-edit-accessor.config.ts +++ b/src/modules/shared/pages/account/manage-details/manage-details-edit-accessor.config.ts @@ -1,9 +1,8 @@ -import { AuthenticationModel } from '@modules/stores/authentication/authentication.models'; - import { FormEngineModel, WizardSummaryType, WizardEngineModel } from '@modules/shared/forms'; +import { UserContextType } from '@modules/stores'; // Types. -type InboundPayloadType = Required['user']; +type InboundPayloadType = Required['user']; type StepPayloadType = { displayName: string; diff --git a/src/modules/shared/pages/account/manage-details/manage-details-edit-admin.config.ts b/src/modules/shared/pages/account/manage-details/manage-details-edit-admin.config.ts index 967e737ba..56ab607a3 100644 --- a/src/modules/shared/pages/account/manage-details/manage-details-edit-admin.config.ts +++ b/src/modules/shared/pages/account/manage-details/manage-details-edit-admin.config.ts @@ -1,9 +1,8 @@ -import { AuthenticationModel } from '@modules/stores/authentication/authentication.models'; - import { FormEngineModel, WizardSummaryType, WizardEngineModel } from '@modules/shared/forms'; +import { UserContextType } from '@modules/stores'; // Types. -type InboundPayloadType = Required['user']; +type InboundPayloadType = Required['user']; type StepPayloadType = { displayName: string; diff --git a/src/modules/shared/pages/account/manage-details/manage-details-edit-innovator.config.ts b/src/modules/shared/pages/account/manage-details/manage-details-edit-innovator.config.ts index ee48dbb3e..4a227207a 100644 --- a/src/modules/shared/pages/account/manage-details/manage-details-edit-innovator.config.ts +++ b/src/modules/shared/pages/account/manage-details/manage-details-edit-innovator.config.ts @@ -1,11 +1,6 @@ -import { AuthenticationModel } from '@modules/stores/authentication/authentication.models'; - import { UtilsHelper } from '@app/base/helpers'; import { FormEngineModel, FormEngineParameterModel, WizardEngineModel, WizardSummaryType } from '@modules/shared/forms'; -import { - ContactUserPreferenceEnum, - PhoneUserPreferenceEnum -} from '@modules/stores/authentication/authentication.service'; +import { ContactUserPreferenceEnum, PhoneUserPreferenceEnum, UserContextType } from '@modules/stores'; const organisationDescriptions = [ 'Sole trader', @@ -22,7 +17,7 @@ const organisationDescriptions = [ ] as const; // Types. -type InboundPayloadType = Required['user']; +type InboundPayloadType = Required['user']; type StepPayloadType = { displayName: string; diff --git a/src/modules/shared/pages/account/manage-details/manage-details-edit.component.spec.ts b/src/modules/shared/pages/account/manage-details/manage-details-edit.component.spec.ts index 41c64994b..d3eabe020 100644 --- a/src/modules/shared/pages/account/manage-details/manage-details-edit.component.spec.ts +++ b/src/modules/shared/pages/account/manage-details/manage-details-edit.component.spec.ts @@ -1,7 +1,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Injector } from '@angular/core'; +import { Injector, signal } from '@angular/core'; import { ActivatedRoute, RouterModule } from '@angular/router'; import { of } from 'rxjs'; @@ -11,8 +11,6 @@ import { AppInjector, CoreModule } from '@modules/core'; import { FormEngineComponent } from '@modules/shared/forms'; import { SharedModule } from '@modules/shared/shared.module'; import { - AuthenticationService, - AuthenticationStore, CtxStore, InnovationContextService, InnovationContextStore, @@ -30,10 +28,12 @@ import { PageAccountManageDetailsEditComponent } from './manage-details-edit.com import { ACCOUNT_DETAILS_ACCESSOR } from './manage-details-edit-accessor.config'; import { ACCOUNT_DETAILS_INNOVATOR } from './manage-details-edit-innovator.config'; import { ENV } from '@tests/app.mocks'; +import { UserContextService } from '@modules/stores/ctx/user/user.service'; +import { UserContextStore } from '@modules/stores/ctx/user/user.store'; describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditComponent', () => { let activatedRoute: ActivatedRoute; - let authenticationStore: AuthenticationStore; + let ctx: CtxStore; let component: PageAccountManageDetailsEditComponent; let fixture: ComponentFixture; @@ -42,8 +42,6 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone TestBed.configureTestingModule({ imports: [HttpClientTestingModule, RouterModule.forRoot([]), CoreModule, SharedModule], providers: [ - AuthenticationStore, - AuthenticationService, CtxStore, InnovationContextStore, InnovationContextService, @@ -54,16 +52,18 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone LayoutContextStore, NotificationsContextStore, NotificationsContextService, + UserContextStore, + UserContextService, { provide: 'APP_SERVER_ENVIRONMENT_VARIABLES', useValue: ENV } ] }); AppInjector.setInjector(TestBed.inject(Injector)); - authenticationStore = TestBed.inject(AuthenticationStore); + ctx = TestBed.inject(CtxStore); activatedRoute = TestBed.inject(ActivatedRoute); - authenticationStore.getUserInfo = () => USER_INFO_ACCESSOR; + ctx.user.getUserInfo = signal(USER_INFO_ACCESSOR); }); it('should create the component', () => { @@ -75,7 +75,7 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone it('should be a question step', () => { activatedRoute.snapshot.params = { stepId: 1 }; - authenticationStore.isInnovatorType = () => true; + ctx.user.isInnovator = signal(true); fixture = TestBed.createComponent(PageAccountManageDetailsEditComponent); component = fixture.componentInstance; @@ -87,7 +87,7 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone it('should be summary step', () => { activatedRoute.snapshot.params = { stepId: 'summary' }; activatedRoute.params = of({ stepId: 'summary' }); // Simulate activatedRoute.params subscription. - authenticationStore.isInnovatorType = () => true; + ctx.user.isInnovator = signal(true); fixture = TestBed.createComponent(PageAccountManageDetailsEditComponent); component = fixture.componentInstance; @@ -99,7 +99,7 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone it('should load innovator information', () => { activatedRoute.snapshot.params = { stepId: 1 }; activatedRoute.params = of({ stepId: 1 }); // Simulate activatedRoute.params subscription. - authenticationStore.isInnovatorType = () => true; + ctx.user.isInnovator = signal(true); fixture = TestBed.createComponent(PageAccountManageDetailsEditComponent); component = fixture.componentInstance; @@ -111,7 +111,7 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone it('should load accessor information', () => { activatedRoute.snapshot.params = { stepId: 1 }; activatedRoute.params = of({ stepId: 1 }); // Simulate activatedRoute.params subscription. - authenticationStore.isAccessorType = () => true; + ctx.user.isAccessorOrAssessment = signal(true); fixture = TestBed.createComponent(PageAccountManageDetailsEditComponent); component = fixture.componentInstance; @@ -123,7 +123,7 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone it('should load assessment information', () => { activatedRoute.snapshot.params = { stepId: 1 }; activatedRoute.params = of({ stepId: 1 }); // Simulate activatedRoute.params subscription. - authenticationStore.isAssessmentType = () => true; + ctx.user.isAccessorOrAssessment = signal(true); fixture = TestBed.createComponent(PageAccountManageDetailsEditComponent); component = fixture.componentInstance; @@ -135,7 +135,7 @@ describe('Shared/Pages/Account/ManageDetails/PageAccountManageDetailsEditCompone it('should do nothing when submitting a step and form not is valid', () => { activatedRoute.snapshot.params = { stepId: 1 }; activatedRoute.params = of({ stepId: 1 }); // Simulate activatedRoute.params subscription. - authenticationStore.isInnovatorType = () => true; + ctx.user.isInnovator = signal(true); const expected = { displayName: 'Test qualifying Accessor', diff --git a/src/modules/shared/pages/account/manage-details/manage-details-edit.component.ts b/src/modules/shared/pages/account/manage-details/manage-details-edit.component.ts index 13a2e04d0..625599a13 100644 --- a/src/modules/shared/pages/account/manage-details/manage-details-edit.component.ts +++ b/src/modules/shared/pages/account/manage-details/manage-details-edit.component.ts @@ -11,7 +11,7 @@ import { WizardSummaryType } from '@modules/shared/forms'; import { ACCOUNT_DETAILS_INNOVATOR } from './manage-details-edit-innovator.config'; import { ACCOUNT_DETAILS_ACCESSOR } from './manage-details-edit-accessor.config'; import { ACCOUNT_DETAILS_ADMIN } from './manage-details-edit-admin.config'; -import { UpdateUserInfoDTO } from '@modules/stores/authentication/authentication.service'; +import { UpdateUserInfo } from '@modules/stores/ctx/user/user.service'; @Component({ selector: 'shared-pages-account-manage-details-edit', @@ -40,15 +40,15 @@ export class PageAccountManageDetailsEditComponent extends CoreComponent impleme } ngOnInit(): void { - if (this.stores.authentication.isInnovatorType()) { + if (this.ctx.user.isInnovator()) { this.wizard = ACCOUNT_DETAILS_INNOVATOR; - } else if (this.stores.authentication.isAccessorType() || this.stores.authentication.isAssessmentType()) { + } else if (this.ctx.user.isAccessorOrAssessment()) { this.wizard = ACCOUNT_DETAILS_ACCESSOR; - } else if (this.stores.authentication.isAdminRole()) { + } else if (this.ctx.user.isAdmin()) { this.wizard = ACCOUNT_DETAILS_ADMIN; } - const user = this.stores.authentication.getUserInfo(); + const user = this.ctx.user.getUserInfo(); this.wizard.setAnswers(this.wizard.runInboundParsing(user)).runRules(); this.subscriptions.push( @@ -93,11 +93,11 @@ export class PageAccountManageDetailsEditComponent extends CoreComponent impleme onSubmitWizard(): void { const wizardData = this.wizard.runOutboundParsing(); - let body: UpdateUserInfoDTO = { + let body: UpdateUserInfo = { displayName: wizardData.displayName }; - if (this.stores.authentication.isInnovatorType()) { + if (this.ctx.user.isInnovator()) { body = { displayName: wizardData.displayName, contactByPhone: wizardData.contactByPhone, @@ -110,10 +110,11 @@ export class PageAccountManageDetailsEditComponent extends CoreComponent impleme }; } - this.stores.authentication + this.ctx.user .updateUserInfo$(body) .pipe( - concatMap(() => this.stores.authentication.initializeAuthentication$()) // Fetch all new information. + // TODO: try to remove this by updating the state when calling updateUserInfo$ + concatMap(() => this.ctx.user.initializeAuthentication$()) ) .subscribe({ next: () => { diff --git a/src/modules/shared/pages/account/manage-details/manage-details-info.component.ts b/src/modules/shared/pages/account/manage-details/manage-details-info.component.ts index ebdefd282..ce77d15e0 100644 --- a/src/modules/shared/pages/account/manage-details/manage-details-info.component.ts +++ b/src/modules/shared/pages/account/manage-details/manage-details-info.component.ts @@ -22,9 +22,9 @@ export class PageAccountManageDetailsInfoComponent extends CoreComponent impleme } ngOnInit(): void { - const user = this.stores.authentication.getUserInfo(); + const user = this.ctx.user.getUserInfo(); - if (this.stores.authentication.isInnovatorType()) { + if (this.ctx.user.isInnovator()) { this.summaryList = [ { label: 'Name', value: user.displayName, editStepNumber: 1 }, { label: 'Email address', value: user.email }, @@ -55,12 +55,12 @@ export class PageAccountManageDetailsInfoComponent extends CoreComponent impleme editStepNumber: 8 }); } - } else if (this.stores.authentication.isAccessorType() || this.stores.authentication.isAssessmentType()) { + } else if (this.ctx.user.isAccessorOrAssessment()) { // this assumes that the user only has one organisation as it's currently the business case const organisation = user.roles.find( (r): r is UserRoleType & { organisation: { name: string } } => r.organisation !== undefined )?.organisation?.name; - const roles = [...new Set(user.roles.map(r => this.stores.authentication.getRoleDescription(r.role)))].join('\n'); + const roles = [...new Set(user.roles.map(r => this.ctx.user.getRoleDescription(r.role)))].join('\n'); this.summaryList = [ { label: 'Name', value: user.displayName, editStepNumber: 1 }, @@ -68,11 +68,11 @@ export class PageAccountManageDetailsInfoComponent extends CoreComponent impleme ...(organisation ? [{ label: 'Organisation', value: organisation }] : []), { label: 'Service roles', value: roles } ]; - } else if (this.stores.authentication.isAdminRole()) { + } else if (this.ctx.user.isAdmin()) { this.summaryList = [ { label: 'Name', value: user.displayName, editStepNumber: 1 }, { label: 'Email address', value: user.email }, - { label: 'User type', value: this.stores.authentication.getRoleDescription(user.roles[0].role as 'ADMIN') } + { label: 'User type', value: this.ctx.user.getRoleDescription(user.roles[0].role as 'ADMIN') } ]; } diff --git a/src/modules/shared/pages/account/mfa/mfa-edit.component.html b/src/modules/shared/pages/account/mfa/mfa-edit.component.html index bf70734f5..1fc0dd3e0 100644 --- a/src/modules/shared/pages/account/mfa/mfa-edit.component.html +++ b/src/modules/shared/pages/account/mfa/mfa-edit.component.html @@ -1,11 +1,12 @@ -
+ +

{{ wizard.currentStep().description }}{{ this.userEmail }}

-

Enter {{isAdmin ? 'the user\'s' : 'your'}} email to confirm

+

Enter {{ ctx.user.isAdmin() ? "the user's" : "your" }} email to confirm

{{ wizard.currentStep().description }}

diff --git a/src/modules/shared/pages/account/mfa/mfa-edit.component.ts b/src/modules/shared/pages/account/mfa/mfa-edit.component.ts index 5578c1d13..d02a1cb54 100644 --- a/src/modules/shared/pages/account/mfa/mfa-edit.component.ts +++ b/src/modules/shared/pages/account/mfa/mfa-edit.component.ts @@ -4,10 +4,9 @@ import { ActivatedRoute } from '@angular/router'; import { CoreComponent } from '@app/base'; import { FormEngineComponent, WizardEngineModel } from '@modules/shared/forms'; import { UsersService } from '@modules/shared/services/users.service'; -import { AuthenticationService } from '@modules/stores'; -import { MFAInfoDTO } from '@modules/stores/authentication/authentication.service'; import { combineLatest, Observable } from 'rxjs'; import { MFA_EMAIL, MFA_PHONE, MFA_SET_UP, MFA_TURN_OFF, MFAWizardModeType } from './mfa-edit.config'; +import { MFAInfo, UserContextService } from '@modules/stores/ctx/user/user.service'; export type CurrentMFAModeType = 'phone' | 'email' | 'none'; @@ -30,14 +29,14 @@ export class PageAccountMFAEditComponent extends CoreComponent implements OnInit manageAccountPageUrl: string; // Configurations - getUserMFAInfo: () => Observable; - updateUserMFAInfo: (mfaInfo: MFAInfoDTO) => Observable; + getUserMFAInfo: () => Observable; + updateUserMFAInfo: (mfaInfo: MFAInfo) => Observable; - isAdmin = this.stores.authentication.isAdminRole(); + isAdmin = this.ctx.user.isAdmin(); constructor( private activatedRoute: ActivatedRoute, - private authenticationService: AuthenticationService, + private userCtxService: UserContextService, private usersService: UsersService ) { super(); @@ -56,10 +55,10 @@ export class PageAccountMFAEditComponent extends CoreComponent implements OnInit this.getUserMFAInfo = this.usersService.getUserMFAInfo(user.id).bind(this.usersService); this.updateUserMFAInfo = this.usersService.updateUserMFAInfo(user.id).bind(this.usersService); } else { - this.userEmail = this.stores.authentication.getUserInfo().email; - this.manageAccountPageUrl = `${this.stores.authentication.userUrlBasePath()}/account/manage-account`; - this.getUserMFAInfo = this.authenticationService.getUserMFAInfo.bind(this.authenticationService); - this.updateUserMFAInfo = this.authenticationService.updateUserMFAInfo.bind(this.authenticationService); + this.userEmail = this.ctx.user.getUserInfo().email; + this.manageAccountPageUrl = `${this.ctx.user.userUrlBasePath()}/account/manage-account`; + this.getUserMFAInfo = this.userCtxService.getUserMFAInfo.bind(this.userCtxService); + this.updateUserMFAInfo = this.userCtxService.updateUserMFAInfo.bind(this.userCtxService); } } @@ -150,7 +149,7 @@ export class PageAccountMFAEditComponent extends CoreComponent implements OnInit } onSubmitWizard() { - const wizardData = this.wizard.runOutboundParsing() as { mfaInfo: MFAInfoDTO; turnOff: boolean }; + const wizardData = this.wizard.runOutboundParsing() as { mfaInfo: MFAInfo; turnOff: boolean }; this.formButton.isActive = false; diff --git a/src/modules/shared/pages/account/mfa/mfa-edit.config.ts b/src/modules/shared/pages/account/mfa/mfa-edit.config.ts index 612db01b6..83daf6827 100644 --- a/src/modules/shared/pages/account/mfa/mfa-edit.config.ts +++ b/src/modules/shared/pages/account/mfa/mfa-edit.config.ts @@ -1,9 +1,9 @@ import { FormEngineModel, WizardEngineModel } from '@modules/shared/forms'; import { CustomFormGroupValidators } from '@modules/shared/forms/validators/custom-validators'; -import { MFAInfoDTO } from '@modules/stores/authentication/authentication.service'; import { SelectComponentInputType } from '@modules/theme/components/search/select.component'; import { fullCountryCodeList } from './mfa-country-lists'; import { CurrentMFAModeType } from './mfa-edit.component'; +import { MFAInfo } from '@modules/stores/ctx/user/user.service'; // Payloads definitions @@ -263,7 +263,7 @@ function inboundParsing(data: InboundPayloadType): StepPayloadType { }; } -function outboundParsing(data: StepPayloadType): { mfaInfo: MFAInfoDTO; turnOff: boolean } { +function outboundParsing(data: StepPayloadType): { mfaInfo: MFAInfo; turnOff: boolean } { const parsedPhone = `${data.countryCode} ${data.phoneNumber}`; return { diff --git a/src/modules/shared/pages/account/mfa/mfa-list.component.ts b/src/modules/shared/pages/account/mfa/mfa-list.component.ts index f87f71abf..a654e0a94 100644 --- a/src/modules/shared/pages/account/mfa/mfa-list.component.ts +++ b/src/modules/shared/pages/account/mfa/mfa-list.component.ts @@ -1,15 +1,15 @@ import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { CoreComponent } from '@app/base'; -import { MFAInfoDTO } from '@modules/stores/authentication/authentication.service'; import { getCensoredPhoneNumber } from './mfa-edit.component'; +import { MFAInfo } from '@modules/stores/ctx/user/user.service'; @Component({ selector: 'app-account-mfa-list', templateUrl: './mfa-list.component.html' }) export class AccountMFAListComponent extends CoreComponent implements OnInit { - @Input({ required: true }) MFAInfo!: MFAInfoDTO; + @Input({ required: true }) MFAInfo!: MFAInfo; isMFAOn = false; currentCensoredPhoneNumber = ''; userEmail: string; @@ -17,10 +17,8 @@ export class AccountMFAListComponent extends CoreComponent implements OnInit { constructor(private activatedRoute: ActivatedRoute) { super(); - const isAdmin = this.stores.authentication.isAdminRole(); - this.userEmail = isAdmin - ? this.activatedRoute.snapshot.data.user.email - : this.stores.authentication.getUserInfo().email; + const isAdmin = this.ctx.user.isAdmin(); + this.userEmail = isAdmin ? this.activatedRoute.snapshot.data.user.email : this.ctx.user.getUserInfo().email; this.description = isAdmin ? 'Two-step verification adds a layer of security to the account.' : 'Two-step verification adds a layer of security to your account. We will send you a security code to your phone or email for you to use when logging in.'; diff --git a/src/modules/shared/pages/innovation/activity-log/innovation-activity-log.component.spec.ts b/src/modules/shared/pages/innovation/activity-log/innovation-activity-log.component.spec.ts index b971555ad..3ecee7083 100644 --- a/src/modules/shared/pages/innovation/activity-log/innovation-activity-log.component.spec.ts +++ b/src/modules/shared/pages/innovation/activity-log/innovation-activity-log.component.spec.ts @@ -29,11 +29,8 @@ describe('Shared/Pages/Innovation/PageInnovationActivityLogComponent', () => { activatedRoute = TestBed.inject(ActivatedRoute); - // authenticationStore = TestBed.inject(AuthenticationStore); organisationsService = TestBed.inject(OrganisationsService); - // authenticationStore.getUserInfo = () => USER_INFO_INNOVATOR; - // activatedRoute.snapshot.params = { innovationId: 'Inno01' }; activatedRoute.snapshot.data = { innovationData: { id: 'Inno01', name: 'Innovation 01', assessment: {} } }; // activatedRoute.snapshot.queryParams = { alert: 'actionCreationSuccess' }; diff --git a/src/modules/shared/pages/innovation/assessment/assessment-overview.component.html b/src/modules/shared/pages/innovation/assessment/assessment-overview.component.html index cf4dcbd16..ac70462b7 100644 --- a/src/modules/shared/pages/innovation/assessment/assessment-overview.component.html +++ b/src/modules/shared/pages/innovation/assessment/assessment-overview.component.html @@ -1,9 +1,10 @@ -
+ +
- +
-
+

Updated: {{ assessment?.updatedAt | date: ("app.date_formats.long_date" | translate) }}

{{ assessment?.updatedBy?.name }}

@@ -15,13 +16,13 @@

Needs assessment team

- +

{{ assessment?.finishedAt | date: ("app.date_formats.long_date" | translate) }}

{{ assessment?.assignTo?.name }}

Needs assessment team

- +

Updated: {{ assessment?.updatedAt | date: ("app.date_formats.long_date" | translate) }}

{{ assessment?.updatedBy?.name }}

Needs assessment team

@@ -48,7 +49,7 @@
-
+ diff --git a/src/modules/shared/pages/innovation/assessment/assessment-overview.component.ts b/src/modules/shared/pages/innovation/assessment/assessment-overview.component.ts index 2abae5f1c..e6c158fce 100644 --- a/src/modules/shared/pages/innovation/assessment/assessment-overview.component.ts +++ b/src/modules/shared/pages/innovation/assessment/assessment-overview.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, signal } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { CoreComponent } from '@app/base'; @@ -29,12 +29,6 @@ export class PageInnovationAssessmentOverviewComponent extends CoreComponent imp innovatorSummary: { label?: string; value: null | string; comment: string }[] = []; // Flags - isAdminType: boolean; - isAssessmentType: boolean; - isAccessorType: boolean; - isInnovatorType: boolean; - isQualifyingAccessorRole: boolean; - isInProgress: boolean; assessmentHasBeenSubmitted = false; @@ -58,12 +52,6 @@ export class PageInnovationAssessmentOverviewComponent extends CoreComponent imp this.innovation = this.ctx.innovation.info(); - this.isAdminType = this.stores.authentication.isAdminRole(); - this.isAssessmentType = this.stores.authentication.isAssessmentType(); - this.isAccessorType = this.stores.authentication.isAccessorType(); - this.isInnovatorType = this.stores.authentication.isInnovatorType(); - this.isQualifyingAccessorRole = this.isAccessorType && this.stores.authentication.isQualifyingAccessorRole(); - this.isInProgress = this.innovation.status === 'IN_PROGRESS'; } @@ -128,7 +116,7 @@ export class PageInnovationAssessmentOverviewComponent extends CoreComponent imp } ]; - if (this.isAccessorType) { + if (this.ctx.user.isAccessorType()) { this.updateSupportUrlNewOrSupport = this.innovation.support && [InnovationSupportStatusEnum.WAITING, InnovationSupportStatusEnum.ENGAGING].includes( @@ -155,7 +143,7 @@ export class PageInnovationAssessmentOverviewComponent extends CoreComponent imp } setGoBackLink(): void { - if (this.isAssessmentType) { + if (this.ctx.user.isAssessment()) { let goBackUrl = undefined; const assessmentEditUrl = `/assessment/innovations/${this.innovationId}/assessments/${this.innovation.assessment?.id}/edit`; switch (this.assessmentQueryParam) { diff --git a/src/modules/shared/pages/innovation/data-sharing-and-support/data-sharing-and-support.component.html b/src/modules/shared/pages/innovation/data-sharing-and-support/data-sharing-and-support.component.html index ef567e3af..f8c2011cc 100644 --- a/src/modules/shared/pages/innovation/data-sharing-and-support/data-sharing-and-support.component.html +++ b/src/modules/shared/pages/innovation/data-sharing-and-support/data-sharing-and-support.component.html @@ -1,6 +1,7 @@ -
+ +
- +
@@ -9,7 +10,7 @@
- +
Important: User Locked @@ -20,7 +21,7 @@ -

+

You can suggest organisations to help support this innovation. You cannot suggest your own organisation, or an organisation that is already engaging with this innovation.

@@ -33,7 +34,7 @@ Organisations that do not have access to the innovation.

-
    +
    • What does each organisation do? (opens in a new window)
    • @@ -49,7 +50,7 @@
      Support status
      Support status key @@ -71,7 +72,7 @@
      {{ organisation.info.name }}
      {{ organisation.info.suggestedByPhrase }} @@ -109,7 +110,7 @@
      {{ organisationUnit.name }}
      -
      +
      {{ organisationUnit.suggestedByPhrase }}
      @@ -133,21 +134,17 @@
      - - -
      +
      Information:

      {{ "features.accessor.cant_do_while_in_assessment" | translate }}

      -