Skip to content

Commit 29bdef3

Browse files
feat: TT-191 Validate the new flow for permission management (#661)
* feat: TT-191 add FT switch to sidebar.component * style: TT-191 styling sidebar code
1 parent cfa91aa commit 29bdef3

File tree

2 files changed

+110
-82
lines changed

2 files changed

+110
-82
lines changed
Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,62 @@
1-
import {AzureAdB2CService} from 'src/app/modules/login/services/azure.ad.b2c.service';
2-
import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
3-
4-
import {SidebarComponent} from './sidebar.component';
5-
import {RouterTestingModule} from '@angular/router/testing';
6-
import {Router, Routes} from '@angular/router';
7-
import {TimeClockComponent} from '../../../time-clock/pages/time-clock.component';
8-
import {provideMockStore} from '@ngrx/store/testing';
9-
import {of} from 'rxjs';
10-
import {FeatureManagerService} from '../../feature-toggles/feature-toggle-manager.service';
1+
import { AzureAdB2CService } from 'src/app/modules/login/services/azure.ad.b2c.service';
2+
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
3+
import { SidebarComponent } from './sidebar.component';
4+
import { RouterTestingModule } from '@angular/router/testing';
5+
import { Router, Routes } from '@angular/router';
6+
import { TimeClockComponent } from '../../../time-clock/pages/time-clock.component';
7+
import { of } from 'rxjs';
8+
import { FeatureManagerService } from '../../feature-toggles/feature-toggle-manager.service';
9+
import { FeatureSwitchGroupService } from '../../feature-toggles/switch-group/feature-switch-group.service';
10+
import { UserInfoService } from 'src/app/modules/user/services/user-info.service';
1111

1212
describe('SidebarComponent', () => {
1313
let component: SidebarComponent;
1414
let fixture: ComponentFixture<SidebarComponent>;
1515
let azureAdB2CServiceStubInjected;
1616
let featureManagerServiceStubInjected: FeatureManagerService;
17+
let featureSwitchGroupService: FeatureSwitchGroupService;
18+
let userInfoService: UserInfoService;
1719
let router;
18-
const routes: Routes = [
19-
{path: 'time-clock', component: TimeClockComponent}
20-
];
20+
const routes: Routes = [{ path: 'time-clock', component: TimeClockComponent }];
2121

2222
const azureAdB2CServiceStub = {
2323
isLogin() {
2424
return true;
2525
},
2626
isAdmin() {
2727
return true;
28-
}
28+
},
29+
};
30+
31+
const userInfoServiceStub = {
32+
isAdmin: () => of(true),
33+
};
34+
35+
const featureSwitchGroupServiceStub = {
36+
isActivated: () => of(true),
2937
};
3038

31-
beforeEach(waitForAsync(() => {
32-
TestBed.configureTestingModule({
33-
declarations: [SidebarComponent],
34-
providers: [
35-
{providers: AzureAdB2CService, useValue: azureAdB2CServiceStub},
36-
provideMockStore({initialState: {}})
37-
],
38-
imports: [RouterTestingModule.withRoutes(routes)]
39+
beforeEach(
40+
waitForAsync(() => {
41+
TestBed.configureTestingModule({
42+
declarations: [SidebarComponent],
43+
providers: [
44+
{ provide: AzureAdB2CService, useValue: azureAdB2CServiceStub },
45+
{ provide: FeatureSwitchGroupService, useValue: featureSwitchGroupServiceStub },
46+
{ provide: UserInfoService, useValue: userInfoServiceStub },
47+
],
48+
imports: [RouterTestingModule.withRoutes(routes)],
49+
}).compileComponents();
50+
router = TestBed.inject(Router);
3951
})
40-
.compileComponents();
41-
router = TestBed.inject(Router);
42-
}));
52+
);
4353

4454
beforeEach(() => {
4555
fixture = TestBed.createComponent(SidebarComponent);
4656
azureAdB2CServiceStubInjected = TestBed.inject(AzureAdB2CService);
4757
featureManagerServiceStubInjected = TestBed.inject(FeatureManagerService);
58+
featureSwitchGroupService = TestBed.inject(FeatureSwitchGroupService);
59+
userInfoService = TestBed.inject(UserInfoService);
4860
component = fixture.componentInstance;
4961
fixture.detectChanges();
5062
});
@@ -54,32 +66,33 @@ describe('SidebarComponent', () => {
5466
expect(component).toBeTruthy();
5567
});
5668

57-
it('admin users have five menu items', () => {
58-
spyOn(azureAdB2CServiceStubInjected, 'isAdmin').and.returnValue(true);
69+
it('admin users have six menu items', () => {
70+
spyOn(featureSwitchGroupService, 'isActivated').and.returnValue(of(true));
5971

60-
component.getSidebarItems();
61-
const menuItems = component.itemsSidebar;
62-
63-
expect(menuItems.length).toBe(6);
72+
component.getSidebarItems().subscribe(() => {
73+
const menuItems = component.itemsSidebar;
74+
expect(menuItems.length).toBe(6);
75+
});
6476
});
6577

6678
it('non admin users have two menu items', () => {
67-
spyOn(azureAdB2CServiceStubInjected, 'isAdmin').and.returnValue(false);
79+
spyOn(featureSwitchGroupService, 'isActivated').and.returnValue(of(true));
80+
spyOn(userInfoServiceStub, 'isAdmin').and.returnValue(of(false));
6881

69-
component.getSidebarItems();
70-
const menuItems = component.itemsSidebar;
71-
72-
expect(menuItems.length).toBe(2);
82+
component.getSidebarItems().subscribe(() => {
83+
const menuItems = component.itemsSidebar;
84+
expect(menuItems.length).toBe(2);
85+
});
7386
});
7487

7588
it('when item is selected is should be set as active and the others as inactive', () => {
7689
const route = 'time-clock';
7790
router.navigate([route]);
7891

79-
component.itemsSidebar.filter(item => item.route === `/${route}`).map(item => {
92+
component.itemsSidebar.filter((item) => item.route === `/${route}`).map((item) => {
8093
expect(item.active).toBeTrue();
8194
});
82-
component.itemsSidebar.filter(item => item.route !== `/${route}`).map(item => {
95+
component.itemsSidebar.filter((item) => item.route !== `/${route}`).map((item) => {
8396
expect(item.active).toBeFalse();
8497
});
8598
});
@@ -101,5 +114,4 @@ describe('SidebarComponent', () => {
101114

102115
expect(itemsSidebar.length).toBe(0);
103116
});
104-
105117
});
Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,47 @@
1-
import {AzureAdB2CService} from 'src/app/modules/login/services/azure.ad.b2c.service';
2-
import {Component, OnInit} from '@angular/core';
3-
import {ItemSidebar} from './models/item-sidebar.model';
4-
import {NavigationStart, Router} from '@angular/router';
5-
import {Observable} from 'rxjs';
6-
import {filter} from 'rxjs/operators';
1+
import { AzureAdB2CService } from 'src/app/modules/login/services/azure.ad.b2c.service';
2+
import { Component, OnDestroy, OnInit } from '@angular/core';
3+
import { ItemSidebar } from './models/item-sidebar.model';
4+
import { NavigationStart, Router } from '@angular/router';
5+
import { Observable, of, Subscription } from 'rxjs';
6+
import { filter, map, mergeMap } from 'rxjs/operators';
77
import { FeatureManagerService } from '../../feature-toggles/feature-toggle-manager.service';
8+
import { UserInfoService } from 'src/app/modules/user/services/user-info.service';
9+
import { FeatureSwitchGroupService } from '../../feature-toggles/switch-group/feature-switch-group.service';
810

911
@Component({
1012
selector: 'app-sidebar',
1113
templateUrl: './sidebar.component.html',
1214
styleUrls: ['./sidebar.component.scss'],
1315
})
14-
export class SidebarComponent implements OnInit {
15-
16+
export class SidebarComponent implements OnInit, OnDestroy {
1617
itemsSidebar: ItemSidebar[] = [];
1718
navStart;
19+
FTSwitchGroup$: Subscription;
1820

1921
constructor(
20-
private azureAdB2CService: AzureAdB2CService,
2122
private router: Router,
23+
private userInfoService: UserInfoService,
24+
private azureAdB2CService: AzureAdB2CService,
2225
private featureManagerService: FeatureManagerService,
26+
private featureSwitchGroup: FeatureSwitchGroupService
2327
) {
2428
this.navStart = this.router.events.pipe(
25-
filter(evt => evt instanceof NavigationStart)
29+
filter((evt) => evt instanceof NavigationStart)
2630
) as Observable<NavigationStart>;
2731
}
2832

2933
ngOnInit(): void {
3034
this.toggleSideBar();
31-
this.getSidebarItems();
35+
this.FTSwitchGroup$ = this.getSidebarItems().subscribe();
3236
this.toggleListTechnologies(this.itemsSidebar);
3337
this.highlightMenuOption(this.router.routerState.snapshot.url);
34-
this.navStart.subscribe(evt => {
38+
this.navStart.subscribe((evt) => {
3539
this.highlightMenuOption(evt.url);
3640
});
3741
}
42+
ngOnDestroy(): void {
43+
this.FTSwitchGroup$.unsubscribe();
44+
}
3845

3946
toggleSideBar() {
4047
$('#menu-toggle').on('click', (e) => {
@@ -43,42 +50,51 @@ export class SidebarComponent implements OnInit {
4350
});
4451
}
4552

46-
getSidebarItems() {
47-
if (this.azureAdB2CService.isAdmin()) {
48-
this.itemsSidebar = [
49-
{route: '/time-clock', icon: 'fas fa-clock', text: 'Time Clock', active: false},
50-
{route: '/time-entries', icon: 'fas fa-list-alt', text: 'Time Entries', active: false},
51-
{route: '/reports', icon: 'fas fa-chart-pie', text: 'Reports', active: false},
52-
{route: '/activities-management', icon: 'fas fa-file-alt', text: 'Activities', active: false},
53-
{route: '/customers-management', icon: 'fas fa-user', text: 'Customers', active: false},
54-
{route: '/users', icon: 'fas fa-user', text: 'Users', active: false},
55-
];
56-
} else {
57-
this.itemsSidebar = [
58-
{route: '/time-clock', icon: 'fas fa-clock', text: 'Time Clock', active: false},
59-
{route: '/time-entries', icon: 'fas fa-list-alt', text: 'Time Entries', active: false},
60-
];
61-
}
53+
getSidebarItems(): Observable<void> {
54+
const isAdminBasedInRole = of(this.azureAdB2CService.isAdmin());
55+
const isAdminBasedInGroup = this.userInfoService.isAdmin();
56+
return this.featureSwitchGroup.isActivated().pipe(
57+
mergeMap((enabled) => {
58+
return enabled ? isAdminBasedInGroup : isAdminBasedInRole;
59+
}),
60+
map((isAdmin) => {
61+
if (isAdmin) {
62+
this.itemsSidebar = [
63+
{ route: '/time-clock', icon: 'fas fa-clock', text: 'Time Clock', active: false },
64+
{ route: '/time-entries', icon: 'fas fa-list-alt', text: 'Time Entries', active: false },
65+
{ route: '/reports', icon: 'fas fa-chart-pie', text: 'Reports', active: false },
66+
{ route: '/activities-management', icon: 'fas fa-file-alt', text: 'Activities', active: false },
67+
{ route: '/customers-management', icon: 'fas fa-user', text: 'Customers', active: false },
68+
{ route: '/users', icon: 'fas fa-user', text: 'Users', active: false },
69+
];
70+
} else {
71+
this.itemsSidebar = [
72+
{ route: '/time-clock', icon: 'fas fa-clock', text: 'Time Clock', active: false },
73+
{ route: '/time-entries', icon: 'fas fa-list-alt', text: 'Time Entries', active: false },
74+
];
75+
}
76+
})
77+
);
6278
}
6379

64-
toggleListTechnologies(itemsSidebar: ItemSidebar[]){
80+
toggleListTechnologies(itemsSidebar: ItemSidebar[]) {
6581
this.featureManagerService
66-
.isToggleEnabledForUser('ui-list-technologies')
67-
.subscribe((enabled) => {
68-
if (enabled === true){
69-
const listTechnologiesItem = {
70-
route: '/technology-report',
71-
icon: 'fas fa-user',
72-
text: 'Technology Report',
73-
active: false
74-
};
75-
itemsSidebar.push(listTechnologiesItem);
76-
}
77-
});
82+
.isToggleEnabledForUser('ui-list-technologies')
83+
.subscribe((enabled) => {
84+
if (enabled === true) {
85+
const listTechnologiesItem = {
86+
route: '/technology-report',
87+
icon: 'fas fa-user',
88+
text: 'Technology Report',
89+
active: false,
90+
};
91+
itemsSidebar.push(listTechnologiesItem);
92+
}
93+
});
7894
}
7995

8096
highlightMenuOption(route) {
81-
this.itemsSidebar.map(item => item.active = false);
82-
this.itemsSidebar.filter(item => item.route === route).map(item => item.active = true);
97+
this.itemsSidebar.map((item) => (item.active = false));
98+
this.itemsSidebar.filter((item) => item.route === route).map((item) => (item.active = true));
8399
}
84100
}

0 commit comments

Comments
 (0)