Skip to content

Commit eec5cf4

Browse files
edgardavid2015Edgar Guamanscastillo-jp
authored
TT-331 redesign of the sidebar (#750)
* refactor: TT-331 Redesign of the sidebar resolve merge conflicts * fix: TT-331 css resolving merge conflicts * code-smell: TT-331 Fixing bugs and code-smells resolving merge conflicts * fix: TT-331 Changes in user and sidebar components resolving merge conflicts * fix: TT-331 Creating unit test for toggleSidebar method * fix: TT-331 Rebase from master and use of dark mode * code-smell: TT-331 Deleting bugs and fixing code smells * style: TT-331 Removing unused icons and scss styles Co-authored-by: Edgar Guaman <[email protected]> Co-authored-by: Sandro Castillo <[email protected]>
1 parent 777051e commit eec5cf4

File tree

14 files changed

+141
-100
lines changed

14 files changed

+141
-100
lines changed

src/app/modules/customer-management/components/customer-info/components/customer-list/customer-list.component.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,6 @@ export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {
7070
},
7171
];
7272

73-
this.dtOptions = {
74-
scrollY: '325px',
75-
paging: false,
76-
responsive: true,
77-
};
78-
7973
const customerIdToEdit$ = this.store.pipe(select(customerIdtoEdit));
8074
this.customerIdToEditSubscription = customerIdToEdit$.subscribe((customerId: string) => {
8175
this.currentCustomerIdToEdit = customerId;
Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,50 @@
1-
<div class="d-flex bg-grayTW-lightest dark:bg-grayTW-darker dark:text-whiteTW" id="wrapper">
2-
<div class="border-right bg-whiteTW dark:bg-grayTW-dark" id="sidebar-wrapper">
3-
<div class="sidebar-heading" style="text-align: center">
4-
<img src="assets/img/ioet.png" width="90" height="auto" style="padding-top: 2rem; padding-bottom: 2rem;" alt="logo" />
5-
</div>
1+
<div id="wrapper" class="d-flex bg-grayTW-lightest dark:bg-grayTW-darker dark:text-whiteTW">
2+
<div id="sidebar-wrapper" class="table-row border-r border-grayTW-lighter shadow-sm bg-whiteTW dark:bg-grayTW-dark dark:border-grayTW">
3+
<div class="table-cell">
4+
<div class="relative flex items-center border-b border-grayTW-lighter dark:border-grayTW sidebar-heading">
5+
<img src="assets/img/ioet-logo-without-letters.png" alt="ioet-logo" width="50" height="auto" style="padding-top: 0.5rem; padding-left: 1rem;"/>
6+
<h1 class="pl-2 pt-2" style="font-family:spinnaker,sans-serif">ioet</h1>
7+
</div>
8+
<app-user></app-user>
69
<div class="list-group list-group-flush bg-whiteTW dark:bg-grayTW-darker">
7-
<a
8-
*ngFor="let item of itemsSidebar"
9-
[routerLink]="item.route"
10-
routerLinkActive=""
11-
class="list-group-item list-group-item-action bg-whiteTW dark:bg-grayTW-dark dark:text-whiteTW"
12-
[ngClass]="{active: item.active}"
13-
>
14-
<i class="{{ item.icon }}"></i> {{ item.text }}
15-
</a>
10+
<a
11+
*ngFor="let item of itemsSidebar"
12+
[routerLink]="item.route"
13+
routerLinkActive=""
14+
class="font-poppins relative pl-4 py-3 bg-whiteTW dark:bg-grayTW-dark dark:text-whiteTW"
15+
[ngClass]="{active: item.active}"
16+
>
17+
<em class="{{ item.icon }}"></em>
18+
<h3 class="font-poppins text-base ml-4 pl-3 -mt-6 text-left" >{{ item.text }}</h3>
19+
</a>
20+
<div class="bg-whiteTW pt-2 pr-24 absolute bottom-0 -mb-10 dark:bg-grayTW-dark">
21+
<a class="flex pl-4 mb-4 text-blackTW hover:text-grayTW dark:text-whiteTW" href="#">
22+
<em class="fas fa-sign-out-alt"></em>
23+
<span class="font-poppins pl-3 font-medium -mt-1 dark:text-whiteTW" (click)="logout()">Sign out</span>
24+
</a>
25+
<app-dark-mode class="relative left-40 -top-14"></app-dark-mode>
26+
</div>
1627
</div>
1728
</div>
29+
<div class="table-cell relative">
30+
<span class="absolute cursor-pointer inset-y-0 right-0 min-h-screen w-0.5 hover:z-0 hover:bg-primaryTW-light" (click)="toggleSideBar()"></span>
31+
<span class="group cursor-pointer absolute w-5 top-28 -right-3">
32+
<img src="assets/icons/left-chevron.svg" alt="left-chevron" id="hide-sidebar" (click)="toggleSideBar()" width="20" height="20" class="bg-whiteTW rounded-full hover:bg-opacity-50 hover:bg-primaryTW-light sm:hidden md:block lg:block"/>
33+
<div class="opacity-0 w-12 bg-blackTW text-whiteTW text-center text-xs rounded-lg py-2 absolute z-10 group-hover:opacity-100 bottom-full left-1/4 ml-4 -mb-6 px-1 pointer-events-none">Hide</div>
34+
</span>
35+
<span class="group cursor-pointer absolute top-28 -right-5">
36+
<img src="assets/icons/right-chevron.svg" alt="right-chevron" id="show-sidebar" (click)="toggleSideBar()" width="20" height="20" class="bg-whiteTW rounded-full hover:bg-opacity-50 hover:bg-primaryTW-light sm:block md:hidden lg:hidden"/>
37+
<div class="opacity-0 w-12 bg-blackTW text-whiteTW text-center text-xs rounded-lg py-2 absolute z-10 group-hover:opacity-100 bottom-full left-1/4 ml-4 -mb-6 px-1 pointer-events-none">Show</div>
38+
</span>
39+
</div>
40+
</div>
1841
<div id="page-content-wrapper">
19-
<nav class="navbar navbar-expand-lg navbar-light border-bottom bg-whiteTW dark:bg-grayTW-dark">
20-
<button class="btn bg-primaryTW hover:bg-primaryTW-dark text-whiteTW hover:text-whiteTW" id="menu-toggle">
21-
Toggle Menu
22-
</button>
23-
<div class="dark-mode-toggle">
24-
<app-dark-mode></app-dark-mode>
25-
</div>
26-
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
27-
<span class="navbar-toggler-icon"></span>
28-
</button>
29-
<div class="collapse navbar-collapse" id="navbarSupportedContent">
30-
<ul class="navbar-nav ml-auto mt-2 mt-lg-0">
31-
<app-user></app-user>
32-
</ul>
33-
</div>
34-
</nav>
3542
<div class="container-fluid px-0 full-height">
3643
<div class="content_app h-100">
3744
<div class="m-1 p-5 rounded-md bg-whiteTW dark:bg-grayTW-dark">
3845
<router-outlet></router-outlet>
3946
</div>
4047
</div>
48+
</div>
4149
</div>
42-
</div>
43-
</div>
50+
</div>

src/app/modules/shared/components/sidebar/sidebar.component.scss

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ body {
77
#sidebar-wrapper {
88
min-height: 100vh;
99
margin-left: -15rem;
10-
-webkit-transition: margin .25s ease-out;
11-
-moz-transition: margin .25s ease-out;
12-
-o-transition: margin .25s ease-out;
13-
transition: margin .25s ease-out;
10+
-webkit-transition: margin 0.25s ease-out;
11+
-moz-transition: margin 0.25s ease-out;
12+
-o-transition: margin 0.25s ease-out;
13+
transition: margin 0.25s ease-out;
1414
}
1515

1616
#sidebar-wrapper .sidebar-heading {
@@ -30,7 +30,7 @@ body {
3030
margin-left: 0;
3131
}
3232

33-
@media (min-width: 883px) {
33+
@media (min-width: 769px) {
3434
#sidebar-wrapper {
3535
margin-left: 0;
3636
}
@@ -41,6 +41,21 @@ body {
4141
#wrapper.toggled #sidebar-wrapper {
4242
margin-left: -15rem;
4343
}
44+
#hide-sidebar {
45+
display: block;
46+
}
47+
#show-sidebar {
48+
display: none;
49+
}
50+
}
51+
52+
@media (max-width: 768px) {
53+
#hide-sidebar {
54+
display: none;
55+
}
56+
#show-sidebar {
57+
display: block;
58+
}
4459
}
4560

4661
.content_app {
@@ -51,7 +66,6 @@ body {
5166
.active {
5267
color: $primary;
5368
font-weight: bold;
54-
text-decoration: underline;
5569
border-color: $primary;
5670
background-color: transparent;
5771
}
@@ -63,9 +77,3 @@ body {
6377
height: -o-calc(100vh - 12vh);
6478
height: calc(100vh - 12vh);
6579
}
66-
67-
.dark-mode-toggle {
68-
position: absolute;
69-
left: 50%;
70-
transform: translateX(-50%);
71-
}

src/app/modules/shared/components/sidebar/sidebar.component.spec.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ describe('SidebarComponent', () => {
2222
isAdmin() {
2323
return true;
2424
},
25+
logout(){
26+
return true;
27+
}
2528
};
2629

2730
const userInfoServiceStub = {
@@ -50,19 +53,19 @@ describe('SidebarComponent', () => {
5053
fixture.detectChanges();
5154
});
5255

53-
it('should be created', () => {
56+
it('component should be created', () => {
5457
spyOn(azureAdB2CServiceStubInjected, 'isAdmin').and.returnValue(false);
5558
expect(component).toBeTruthy();
5659
});
5760

58-
it('admin users have six menu items', () => {
61+
it('admin users should have six menu items', () => {
5962
component.getSidebarItems().subscribe(() => {
6063
const menuItems = component.itemsSidebar;
6164
expect(menuItems.length).toBe(6);
6265
});
6366
});
6467

65-
it('non admin users have two menu items', () => {
68+
it('non admin users should have two menu items', () => {
6669
spyOn(userInfoServiceStub, 'isAdmin').and.returnValue(of(false));
6770

6871
component.getSidebarItems().subscribe(() => {
@@ -71,7 +74,7 @@ describe('SidebarComponent', () => {
7174
});
7275
});
7376

74-
it('when item is selected is should be set as active and the others as inactive', () => {
77+
it('when item is selected should be set as active and the others as inactive', () => {
7578
const route = 'time-clock';
7679
router.navigate([route]);
7780

@@ -83,4 +86,16 @@ describe('SidebarComponent', () => {
8386
});
8487
});
8588

89+
it('should toggle the sidebar', () => {
90+
component.toggleSideBar();
91+
fixture.detectChanges();
92+
const sidebarElement = fixture.debugElement.nativeElement.querySelector('#wrapper');
93+
expect(sidebarElement.classList.contains('toggled')).toBeTrue();
94+
});
95+
96+
it('should use the Azure service on logout', () => {
97+
spyOn(azureAdB2CServiceStubInjected, 'logout');
98+
component.logout();
99+
expect(azureAdB2CServiceStubInjected.logout).toHaveBeenCalled();
100+
});
86101
});

src/app/modules/shared/components/sidebar/sidebar.component.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { NavigationStart, Router } from '@angular/router';
44
import { Observable, Subscription } from 'rxjs';
55
import { filter, map } from 'rxjs/operators';
66
import { UserInfoService } from 'src/app/modules/user/services/user-info.service';
7-
7+
import { AzureAdB2CService } from '../../../login/services/azure.ad.b2c.service';
88
@Component({
99
selector: 'app-sidebar',
1010
templateUrl: './sidebar.component.html',
@@ -15,17 +15,13 @@ export class SidebarComponent implements OnInit, OnDestroy {
1515
navStart;
1616
sidebarItems$: Subscription;
1717

18-
constructor(
19-
private router: Router,
20-
private userInfoService: UserInfoService,
21-
) {
18+
constructor(private router: Router, private userInfoService: UserInfoService, private azureAdB2CService: AzureAdB2CService) {
2219
this.navStart = this.router.events.pipe(
2320
filter((evt) => evt instanceof NavigationStart)
2421
) as Observable<NavigationStart>;
2522
}
2623

2724
ngOnInit(): void {
28-
this.toggleSideBar();
2925
const currentRouting = this.router.routerState.snapshot.url;
3026
this.sidebarItems$ = this.getSidebarItems().subscribe(() => this.highlightMenuOption(currentRouting));
3127
this.navStart.subscribe((evt) => {
@@ -38,28 +34,27 @@ export class SidebarComponent implements OnInit, OnDestroy {
3834
}
3935

4036
toggleSideBar() {
41-
$('#menu-toggle').on('click', (e) => {
42-
e.preventDefault();
43-
$('#wrapper').toggleClass('toggled');
44-
});
37+
$('#wrapper').toggleClass('toggled');
38+
$('#show-sidebar').toggle();
39+
$('#hide-sidebar').toggle();
4540
}
4641

4742
getSidebarItems(): Observable<void> {
4843
return this.userInfoService.isAdmin().pipe(
4944
map((isAdmin) => {
5045
if (isAdmin) {
5146
this.itemsSidebar = [
52-
{ route: '/time-clock', icon: 'fas fa-clock', text: 'Time Clock', active: false },
53-
{ route: '/time-entries', icon: 'fas fa-list-alt', text: 'Time Entries', active: false },
54-
{ route: '/reports', icon: 'fas fa-chart-pie', text: 'Reports', active: false },
55-
{ route: '/activities-management', icon: 'fas fa-file-alt', text: 'Activities', active: false },
56-
{ route: '/customers-management', icon: 'fas fa-user', text: 'Customers', active: false },
57-
{ route: '/users', icon: 'fas fa-user', text: 'Users', active: false },
47+
{ route: '/time-clock', icon: 'far fa-clock', text: 'Time Clock', active: false },
48+
{ route: '/time-entries', icon: 'far fa-file-alt', text: 'Time Entries', active: false },
49+
{ route: '/reports', icon: 'fas fa-chart-bar', text: 'Reports', active: false },
50+
{ route: '/activities-management', icon: 'fas fa-list-ol', text: 'Activities', active: false },
51+
{ route: '/customers-management', icon: 'fas fa-users', text: 'Customers', active: false },
52+
{ route: '/users', icon: 'fas fa-user-friends', text: 'Users', active: false },
5853
];
5954
} else {
6055
this.itemsSidebar = [
61-
{ route: '/time-clock', icon: 'fas fa-clock', text: 'Time Clock', active: false },
62-
{ route: '/time-entries', icon: 'fas fa-list-alt', text: 'Time Entries', active: false },
56+
{ route: '/time-clock', icon: 'far fa-clock', text: 'Time Clock', active: false },
57+
{ route: '/time-entries', icon: 'far fa-file-alt', text: 'Time Entries', active: false },
6358
];
6459
}
6560
})
@@ -70,4 +65,8 @@ export class SidebarComponent implements OnInit, OnDestroy {
7065
this.itemsSidebar.map((item) => (item.active = false));
7166
this.itemsSidebar.filter((item) => item.route === route).map((item) => (item.active = true));
7267
}
68+
69+
logout() {
70+
this.azureAdB2CService.logout();
71+
}
7372
}
Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
<li class="nav-item active dropdown">
2-
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
3-
aria-haspopup="true" aria-expanded="false">
4-
<i class="far fa-user-circle"></i>
5-
{{name}}
6-
</a>
7-
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
8-
<a class="dropdown-item" href="#" (click)="logout()">Sign Out</a>
9-
</div>
10-
</li>
1+
<div class=" py-8 flex items-center pl-3">
2+
<img src="assets/icons/user.svg" alt="user-icon" width="40" height="40"/>
3+
<span class="pl-1">
4+
<h2 class="font-poppins text-base font-semibold pl-2 dark:text-whiteTW">{{userName}}</h2>
5+
<p class="font-poppins mt-1 text-xs font-medium pl-2 text-grayTW dark:text-whiteTW">{{userEmail}}</p>
6+
</span>
7+
</div>

src/app/modules/shared/components/user/user.component.spec.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,24 @@ describe('UserComponent', () => {
4040
it('onInit checks if isLogin and gets the name and set tenantIn in the storage', () => {
4141
spyOn(azureAdB2CService, 'isLogin').and.returnValue(true);
4242
spyOn(azureAdB2CService, 'getName').and.returnValue('Name');
43+
spyOn(azureAdB2CService, 'getUserEmail').and.returnValue('Email');
4344
spyOn(azureAdB2CService, 'setTenantId');
4445
component.ngOnInit();
4546
expect(azureAdB2CService.isLogin).toHaveBeenCalled();
4647
expect(azureAdB2CService.getName).toHaveBeenCalled();
48+
expect(azureAdB2CService.getUserEmail).toHaveBeenCalled();
4749
expect(azureAdB2CService.setTenantId).toHaveBeenCalled();
4850
});
4951

5052
it('onInit does not get the name if isLogin false', () => {
5153
spyOn(azureAdB2CService, 'isLogin').and.returnValue(false);
5254
spyOn(azureAdB2CService, 'getName').and.returnValue('Name');
55+
spyOn(azureAdB2CService, 'getUserEmail').and.returnValue('Email');
5356
spyOn(azureAdB2CService, 'setTenantId');
5457
component.ngOnInit();
5558
expect(azureAdB2CService.isLogin).toHaveBeenCalled();
5659
expect(azureAdB2CService.getName).toHaveBeenCalledTimes(0);
60+
expect(azureAdB2CService.getUserEmail).toHaveBeenCalledTimes(0);
5761
expect(azureAdB2CService.setTenantId).not.toHaveBeenCalled();
5862
});
59-
60-
it('uses the Azure service on logout', () => {
61-
spyOn(azureAdB2CService, 'logout');
62-
63-
component.logout();
64-
65-
expect(azureAdB2CService.logout).toHaveBeenCalled();
66-
});
6763
});

src/app/modules/shared/components/user/user.component.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,16 @@ import { AzureAdB2CService } from '../../../login/services/azure.ad.b2c.service'
77
styleUrls: ['./user.component.scss'],
88
})
99
export class UserComponent implements OnInit {
10-
name: string;
10+
userName: string;
11+
userEmail: string;
1112

1213
constructor(private azureAdB2CService: AzureAdB2CService) {}
1314

1415
ngOnInit(): void {
1516
if (this.azureAdB2CService.isLogin()) {
16-
this.name = this.azureAdB2CService.getName();
17+
this.userName = this.azureAdB2CService.getName();
18+
this.userEmail = this.azureAdB2CService.getUserEmail();
1719
this.azureAdB2CService.setTenantId();
1820
}
1921
}
20-
21-
logout() {
22-
this.azureAdB2CService.logout();
23-
}
2422
}

src/app/modules/time-clock/components/time-entries-summary/time-entries-summary.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<h6 class="text-left"><strong>Summary</strong></h6>
2-
<hr />
2+
<hr class="mb-4" />
33
<div class ="container px-0">
44
<div class="row pb-4">
55
<div class="col-12 col-sm-3">

src/assets/icons/left-chevron.svg

Lines changed: 5 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)