Skip to content

Commit 30c1cc0

Browse files
authored
Merge pull request #523 from bcgov/oleks
DSS-530: Sort on page view
2 parents ac1a913 + f2833a7 commit 30c1cc0

File tree

4 files changed

+114
-33
lines changed

4 files changed

+114
-33
lines changed

frontend/src/app/features/components/user-management/user-details/user-details.component.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ export class UserDetailsComponent implements OnInit {
123123
]).subscribe({
124124
next: ([user, roles, orgTypes, organizations]) => {
125125
this.user = user;
126-
this.orgTypes = orgTypes;
127-
this.organizations = organizations;
128-
this.organizationsRaw = organizations;
126+
this.orgTypes = orgTypes.sort((a, b) => this.sortHandler(a.label, b.label));
127+
this.organizations = organizations.sort((a, b) => this.sortHandler(a.label, b.label));
128+
this.organizationsRaw = organizations.sort((a, b) => this.sortHandler(a.label, b.label));
129129
this.selectedOrg = this.organizationsRaw.find(x => (x as any)['organizationCd'] === this.user.representedByOrganization.organizationCd)?.value || '';
130130
this.selectedOrgType = this.user.representedByOrganization.organizationType;
131131
this.roles = roles.map((role) => ({ label: role.userRoleNm, value: role.userRoleCd, selected: user.roleCds.some(x => role.userRoleCd === x) }));
@@ -138,4 +138,10 @@ export class UserDetailsComponent implements OnInit {
138138
}
139139
});
140140
}
141+
142+
private sortHandler(a: string, b: string): number {
143+
if (a > b) return 1;
144+
if (a < b) return -1;
145+
return 0
146+
}
141147
}

frontend/src/app/features/components/user-management/user-management.component.html

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,66 @@
3636
<p-table [id]="'user-table'" [styleClass]="'p-datatable-sm'" [value]="accessRequests" [rows]="10">
3737
<ng-template pTemplate="header">
3838
<tr id="table-header">
39-
<th id="accessRequestDtm_th" pSortableColumn="accessRequestDtm">Requested Date<p-sortIcon
40-
field="accessRequestDtm"></p-sortIcon></th>
41-
<th id="identityProviderNm_th" pSortableColumn="identityProviderNm">ID Provider<p-sortIcon
42-
field="givenNm"></p-sortIcon></th>
43-
<th id="givenNm_th" pSortableColumn="givenNm">First Name<p-sortIcon field="givenNm"></p-sortIcon>
39+
<th [class.sorted]="this.sort && this.sort.prop === 'accessRequestDtm'"
40+
(click)="onSort('accessRequestDtm')" class="sortable-header" id="accessRequestDtm_th">Requested
41+
Date
42+
<i class="pi pi-angle-down"
43+
*ngIf="this.sort && this.sort.prop === 'accessRequestDtm' && this.sort.dir === 'desc'"></i>
44+
<i class="pi pi-angle-up"
45+
*ngIf="this.sort && this.sort.prop === 'accessRequestDtm' && this.sort.dir === 'asc'"></i>
4446
</th>
45-
<th id="familyNm_th" pSortableColumn="familyNm">Last Name<p-sortIcon field="familyNm"></p-sortIcon>
47+
<th [class.sorted]="this.sort && this.sort.prop === 'identityProviderNm'"
48+
(click)="onSort('identityProviderNm')" class="sortable-header" id="identityProviderNm_th">ID
49+
Provider
50+
<i class="pi pi-angle-down"
51+
*ngIf="this.sort && this.sort.prop === 'identityProviderNm' && this.sort.dir === 'desc'"></i>
52+
<i class="pi pi-angle-up"
53+
*ngIf="this.sort && this.sort.prop === 'identityProviderNm' && this.sort.dir === 'asc'"></i>
4654
</th>
47-
<th id="orgType_th" pSortableColumn="code1">Org Type<p-sortIcon field="code1"></p-sortIcon></th>
48-
<th id="emailAddressDsc_th" pSortableColumn="emailAddressDsc">Email Address<p-sortIcon
49-
field="emailAddressDsc"></p-sortIcon>
55+
<th [class.sorted]="this.sort && this.sort.prop === 'givenNm'" (click)="onSort('givenNm')"
56+
class="sortable-header" id="givenNm_th">First Name
57+
<i class="pi pi-angle-down"
58+
*ngIf="this.sort && this.sort.prop === 'givenNm' && this.sort.dir === 'desc'"></i>
59+
<i class="pi pi-angle-up"
60+
*ngIf="this.sort && this.sort.prop === 'givenNm' && this.sort.dir === 'asc'"></i>
5061
</th>
51-
<th id="orgName_th" pSortableColumn="code2">Organization<p-sortIcon field="code2"></p-sortIcon></th>
52-
<th id="Status_th" pSortableColumn="code2">Status<p-sortIcon field="code2"></p-sortIcon></th>
53-
<th id="action_th" pSortableColumn="action" class="action">Action<p-sortIcon
54-
field="action"></p-sortIcon></th>
62+
<th [class.sorted]="this.sort && this.sort.prop === 'familyNm'" (click)="onSort('familyNm')"
63+
class="sortable-header" id="familyNm_th">Last Name
64+
<i class="pi pi-angle-down"
65+
*ngIf="this.sort && this.sort.prop === 'familyNm' && this.sort.dir === 'desc'"></i>
66+
<i class="pi pi-angle-up"
67+
*ngIf="this.sort && this.sort.prop === 'familyNm' && this.sort.dir === 'asc'"></i>
68+
</th>
69+
<th [class.sorted]="this.sort && this.sort.prop === 'organizationType'"
70+
(click)="onSort('organizationType')" class="sortable-header" id="orgType_th">Org Type
71+
<i class="pi pi-angle-down"
72+
*ngIf="this.sort && this.sort.prop === 'organizationType' && this.sort.dir === 'desc'"></i>
73+
<i class="pi pi-angle-up"
74+
*ngIf="this.sort && this.sort.prop === 'organizationType' && this.sort.dir === 'asc'"></i>
75+
</th>
76+
<th [class.sorted]="this.sort && this.sort.prop === 'emailAddressDsc'"
77+
(click)="onSort('emailAddressDsc')" class="sortable-header" id="emailAddressDsc_th">Email
78+
Address
79+
<i class="pi pi-angle-down"
80+
*ngIf="this.sort && this.sort.prop === 'emailAddressDsc' && this.sort.dir === 'desc'"></i>
81+
<i class="pi pi-angle-up"
82+
*ngIf="this.sort && this.sort.prop === 'emailAddressDsc' && this.sort.dir === 'asc'"></i>
83+
</th>
84+
<th [class.sorted]="this.sort && this.sort.prop === 'organizationNm'"
85+
(click)="onSort('organizationNm')" class="sortable-header" id="orgName_th">Organization
86+
<i class="pi pi-angle-down"
87+
*ngIf="this.sort && this.sort.prop === 'organizationNm' && this.sort.dir === 'desc'"></i>
88+
<i class="pi pi-angle-up"
89+
*ngIf="this.sort && this.sort.prop === 'organizationNm' && this.sort.dir === 'asc'"></i>
90+
</th>
91+
<th [class.sorted]="this.sort && this.sort.prop === 'accessRequestStatusCd'"
92+
(click)="onSort('accessRequestStatusCd')" class="sortable-header" id="Status_th">Status
93+
<i class="pi pi-angle-down"
94+
*ngIf="this.sort && this.sort.prop === 'accessRequestStatusCd' && this.sort.dir === 'desc'"></i>
95+
<i class="pi pi-angle-up"
96+
*ngIf="this.sort && this.sort.prop === 'accessRequestStatusCd' && this.sort.dir === 'asc'"></i>
97+
</th>
98+
<th id="action_th" class="action">Action</th>
5599
</tr>
56100
</ng-template>
57101
<ng-template pTemplate="body" let-accessRequest let-index="rowIndex">

frontend/src/app/features/components/user-management/user-management.component.scss

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
padding: 22px;
55
background-color: #FFFFFF;
66

7-
* {
8-
font-family: 'BcSans-regular';
9-
}
10-
117
.bold-text {
128
font-family: 'BcSans-bold';
139
}
@@ -69,6 +65,21 @@
6965
th {
7066
font-size: 14px;
7167
font-family: 'BcSans-bold';
68+
69+
&.sortable-header {
70+
-webkit-user-select: none;
71+
-ms-user-select: none;
72+
user-select: none;
73+
74+
&:hover {
75+
text-decoration: underline;
76+
cursor: pointer;
77+
}
78+
79+
i {
80+
vertical-align: middle;
81+
}
82+
}
7283
}
7384

7485
.action {

frontend/src/app/features/components/user-management/user-management.component.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
1+
import { Component, OnInit, ViewChild } from '@angular/core';
22
import { Dropdown, DropdownModule } from 'primeng/dropdown';
33
import { DropdownOption } from '../../../common/models/dropdown-option';
44
import { CommonModule } from '@angular/common';
@@ -18,7 +18,7 @@ import { UserDataService } from '../../../common/services/user-data.service';
1818
import { InputTextModule } from 'primeng/inputtext';
1919
import { ToastModule } from 'primeng/toast';
2020
import { GlobalLoaderService } from '../../../common/services/global-loader.service';
21-
import { Router, RouterModule } from '@angular/router';
21+
import { RouterModule } from '@angular/router';
2222

2323
@Component({
2424
selector: 'app-user-management',
@@ -50,6 +50,7 @@ export class UserManagementComponent implements OnInit {
5050
organizations = new Array<DropdownOption>();
5151
filteredOrganizations = new Array<DropdownOption>();
5252
organizationDropdown = new Array<DropdownOption>();
53+
sort!: { prop: string, dir: 'asc' | 'desc' }
5354

5455
accessRequests = new Array<AccessRequestTableItem>();
5556
currentPage!: PagingResponsePageInfo;
@@ -77,7 +78,6 @@ export class UserManagementComponent implements OnInit {
7778
private confirmationService: ConfirmationService,
7879
private messageService: MessageService,
7980
private loaderService: GlobalLoaderService,
80-
private router: Router,
8181
) { }
8282

8383
ngOnInit(): void {
@@ -232,6 +232,22 @@ export class UserManagementComponent implements OnInit {
232232
});
233233
}
234234

235+
onSort(property: string): void {
236+
if (this.sort) {
237+
if (this.sort.prop === property) {
238+
this.sort.dir = this.sort.dir === 'asc' ? 'desc' : 'asc';
239+
} else {
240+
this.sort.prop = property;
241+
this.sort.dir = 'asc';
242+
}
243+
}
244+
else {
245+
this.sort = { prop: property, dir: 'asc' };
246+
}
247+
248+
this.getUsers(this.currentPage.pageNumber);
249+
}
250+
235251
private handleConcurrencyError(errorMsg: any): void {
236252
let details = `${errorMsg.error.errors.entity[0]} Instance: ${errorMsg.error.instance}`;
237253
this.showErrorToast(errorMsg.error.title, details);
@@ -248,7 +264,7 @@ export class UserManagementComponent implements OnInit {
248264
this.loaderService.loadingStart();
249265
this.userDataService.getStatuses().subscribe({
250266
next: (data: Array<DropdownOption>) => {
251-
this.statuses = [{ label: 'All', value: '' }, ...data];
267+
this.statuses = [{ label: 'All', value: '' }, ...data.sort((a, b) => this.sortHandler(a.label, b.label))];
252268
},
253269
error: (error) => {
254270
this.showErrorToast('Error', 'Unable to retrieve Statuses. Check console for additional details')
@@ -262,9 +278,9 @@ export class UserManagementComponent implements OnInit {
262278
this.loaderService.loadingStart();
263279
this.requestAccessService.getOrganizations().subscribe({
264280
next: (data) => {
265-
this.organizations = data;
266-
this.filteredOrganizations = data;
267-
this.organizationDropdown = [{ label: 'All', value: '' }, ...data];
281+
this.organizations = data.sort((a, b) => this.sortHandler(a.label, b.label));
282+
this.filteredOrganizations = data.sort((a, b) => this.sortHandler(a.label, b.label));
283+
this.organizationDropdown = [{ label: 'All', value: '' }, ...data.sort((a, b) => this.sortHandler(a.label, b.label))];
268284
},
269285
error: (error: any) => {
270286
this.showErrorToast('Error', 'Unable to retrieve Organizations. Check console for additional details')
@@ -278,10 +294,10 @@ export class UserManagementComponent implements OnInit {
278294
this.loaderService.loadingStart();
279295
this.requestAccessService.getOrganizationTypes().subscribe({
280296
next: (data) => {
281-
this.organizationTypes = data;
297+
this.organizationTypes = data.sort((a, b) => this.sortHandler(a.label, b.label));
282298
},
283299
error: (error: any) => {
284-
this.showErrorToast('Error', 'Unable to retrieve Organization Types. Check console for additional details')
300+
this.showErrorToast('Error', 'Unable to retrieve Organization Types. Check console for additional details');
285301
console.error(error);
286302
},
287303
complete: () => {
@@ -292,26 +308,30 @@ export class UserManagementComponent implements OnInit {
292308
this.getUsers();
293309
}
294310

311+
private sortHandler(a: string, b: string): number {
312+
if (a > b) return 1;
313+
if (a < b) return -1;
314+
return 0
315+
}
316+
295317
private getUsers(selectedPageNumber?: number): void {
296318
const status = this.searchParams.searchStatus;
297319
const search = this.searchParams.searchTerm;
298320
const organizationId = this.searchParams.searchOrganization;
299321
const pageSize = this.currentPage?.pageSize || 10;
300322
const pageNumber = selectedPageNumber ?? (this.currentPage?.pageNumber || 0);
301-
const orderBy = '';
302-
const direction = 'desc';
323+
const orderBy = this.sort ? this.sort.prop : '';
324+
const direction = this.sort ? this.sort.dir : 'asc';;
303325
this.loaderService.loadingStart();
304326

305327
this.userDataService.getUsers(status, search, organizationId, pageSize, pageNumber, orderBy, direction).subscribe({
306328
next: (response: PagingResponse<AccessRequestTableItem>) => {
307329
this.accessRequests = response.sourceList;
308330
this.currentPage = response.pageInfo;
309-
310331
},
311332
error: (error: any) => {
312333
this.showErrorToast('Error', 'Unable to retrieve users. Check console for additional details')
313334
console.error(error);
314-
315335
},
316336
complete: () => {
317337
this.loaderService.loadingEnd();

0 commit comments

Comments
 (0)