Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/admin/admin-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const adminRoutes: Routes = [
{
path: 'users', component: UsersComponent, children: [
{ path: '', component: UserListComponent },
{ path: 'organization/:organization-id', component: UserListComponent },
{ path: 'new-user', component: UserEditComponent },
{ path: ':user-id', component: UserDetailComponent },
{ path: ':user-id/edit-user', component: UserEditComponent },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,134 +1,149 @@
import { AfterViewInit, Component, Input, ViewChild } from '@angular/core';
import {
RejectUserDto,
UserGetManyResponse,
UserResponse,
UserResponsePerRequestedOrganization,
} from '../../user.model';
import { UserService } from '../../user.service';
import { SharedVariableService } from '@shared/shared-variable/shared-variable.service';
import { environment } from '@environments/environment';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { TranslateService } from '@ngx-translate/core';
import { merge, Observable, of as observableOf } from 'rxjs';
import { catchError, map, startWith, switchMap } from 'rxjs/operators';
import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service';
import { DefaultPageSizeOptions } from '@shared/constants/page.constants';

@Component({
selector: 'app-awaiting-users-table',
templateUrl: './awaiting-users-table.component.html',
styleUrls: ['./awaiting-users-table.component.scss'],
})
export class AwaitingUsersTableComponent implements AfterViewInit {
displayedColumns: string[] = ['name', 'email', 'menu'];
users: UserResponsePerRequestedOrganization[];

public pageSize = environment.tablePageSize;
pageSizeOptions = DefaultPageSizeOptions;

resultsLength = 0;
public errorMessage: string;
isLoadingResults = true;
message: string;
infoTitle: string;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;

@Input() permissionId?: number;
@Input() canSort = true;

constructor(
public translate: TranslateService,
private userService: UserService,
private sharedService: SharedVariableService,
private deleteDialogService: DeleteDialogService
) {}

ngAfterViewInit() {
// If the user changes the sort order, reset back to the first page.
this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0));

merge(this.sort.sortChange, this.paginator.page)
.pipe(
startWith({}),
switchMap(() => {
this.isLoadingResults = true;
return this.getUsers(this.sort.active, this.sort.direction);
}),
map((data) => {
// Flip flag to show that loading has finished.
this.isLoadingResults = false;
this.resultsLength = data.count;

return data.data;
}),
catchError(() => {
this.isLoadingResults = false;
return observableOf([] as UserResponse[]);
})
)
.subscribe((userResponses) => {
this.users = [];

// Flatten users so each table row is exactly one request
for (const response of userResponses) {
const { requestedOrganizations, ...user} = response;

for (const organizationId of response.requestedOrganizations) {
this.users.push({
...user,
requestedOrganization: organizationId,
});
}
}
});

this.translate
.get(['USERS.DIALOG.QUESTION-REJECT', 'USERS.DIALOG.HEAD-REJECT'])
.subscribe((translations) => {
this.message = translations['USERS.DIALOG.QUESTION-REJECT'];
this.infoTitle = translations['USERS.DIALOG.HEAD-REJECT'];
});
}

getUsers(
orderByColumn: string,
orderByDirection: string
): Observable<UserGetManyResponse> {
return this.userService.getAwaitingUsers(
this.paginator.pageSize,
this.paginator.pageIndex * this.paginator.pageSize,
orderByColumn,
orderByDirection
);
}

rejectUser(userId: number, organizationId: number) {
this.deleteDialogService
.showSimpleDialog(this.message, false, true, false, this.infoTitle, true)
.subscribe((response) => {
if (response) {
const rejectUserOrgDto: RejectUserDto = {
orgId: organizationId,
userIdToReject: userId,
};

this.userService
.rejectUser(rejectUserOrgDto)
.subscribe((response) => {
if (response) {
this.paginator.page.emit({
pageIndex: this.paginator.pageIndex,
pageSize: this.paginator.pageSize,
length: this.resultsLength,
});
} else {
this.errorMessage = response?.name;
}
});
}
});
}
}
import { AfterViewInit, Component, Input, ViewChild } from '@angular/core';
import {
RejectUserDto,
UserGetManyResponse,
UserResponse,
UserResponsePerRequestedOrganization,
} from '../../user.model';
import { UserService } from '../../user.service';
import { SharedVariableService } from '@shared/shared-variable/shared-variable.service';
import { environment } from '@environments/environment';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { TranslateService } from '@ngx-translate/core';
import { merge, Observable, of as observableOf } from 'rxjs';
import { catchError, map, startWith, switchMap } from 'rxjs/operators';
import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service';
import { DefaultPageSizeOptions } from '@shared/constants/page.constants';
import { MeService } from '@shared/services/me.service';

@Component({
selector: 'app-awaiting-users-table',
templateUrl: './awaiting-users-table.component.html',
styleUrls: ['./awaiting-users-table.component.scss'],
})
export class AwaitingUsersTableComponent implements AfterViewInit {
displayedColumns: string[] = ['name', 'email', 'menu'];
users: UserResponsePerRequestedOrganization[];

public pageSize = environment.tablePageSize;
pageSizeOptions = DefaultPageSizeOptions;

resultsLength = 0;
public errorMessage: string;
isLoadingResults = true;
message: string;
infoTitle: string;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;

@Input() permissionId?: number;
@Input() canSort = true;
organizationId: number;

constructor(
public translate: TranslateService,
private userService: UserService,
private sharedService: SharedVariableService,
private deleteDialogService: DeleteDialogService,
private meService: MeService
) {
this.organizationId = this.sharedService.getSelectedOrganisationId();
}

ngAfterViewInit() {
// If the user changes the sort order, reset back to the first page.
this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0));

merge(this.sort.sortChange, this.paginator.page)
.pipe(
startWith({}),
switchMap(() => {
this.isLoadingResults = true;
return this.getUsers(this.sort.active, this.sort.direction);
}),
map((data) => {
// Flip flag to show that loading has finished.
this.isLoadingResults = false;
this.resultsLength = data.count;

return data.data;
}),
catchError(() => {
this.isLoadingResults = false;
return observableOf([] as UserResponse[]);
})
)
.subscribe((userResponses) => {
this.users = [];

// Flatten users so each table row is exactly one request
for (const response of userResponses) {
const { requestedOrganizations, ...user} = response;

for (const organizationId of response.requestedOrganizations) {
this.users.push({
...user,
requestedOrganization: organizationId,
});
}
}
});

this.translate
.get(['USERS.DIALOG.QUESTION-REJECT', 'USERS.DIALOG.HEAD-REJECT'])
.subscribe((translations) => {
this.message = translations['USERS.DIALOG.QUESTION-REJECT'];
this.infoTitle = translations['USERS.DIALOG.HEAD-REJECT'];
});
}

getUsers(
orderByColumn: string,
orderByDirection: string
): Observable<UserGetManyResponse> {
if(this.meService.hasGlobalAdmin()) {
return this.userService.getAwaitingUsers(
this.paginator.pageSize,
this.paginator.pageIndex * this.paginator.pageSize,
orderByColumn,
orderByDirection
);
} else {
return this.userService.getAwaitingUsersForOrganization(
this.paginator.pageSize,
this.paginator.pageIndex * this.paginator.pageSize,
this.organizationId,
orderByColumn,
orderByDirection
);
}
}

rejectUser(userId: number, organizationId: number) {
this.deleteDialogService
.showSimpleDialog(this.message, false, true, false, this.infoTitle, true)
.subscribe((response) => {
if (response) {
const rejectUserOrgDto: RejectUserDto = {
orgId: organizationId,
userIdToReject: userId,
};

this.userService
.rejectUser(rejectUserOrgDto)
.subscribe((response) => {
if (response) {
this.paginator.page.emit({
pageIndex: this.paginator.pageIndex,
pageSize: this.paginator.pageSize,
length: this.resultsLength,
});
} else {
this.errorMessage = response?.name;
}
});
}
});
}
}
2 changes: 1 addition & 1 deletion src/app/admin/users/user-list/user-list.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
[component]="true"
[title]="'USERS.EXISTING-USERS' | translate"
></app-top-bar-table>
<app-user-table></app-user-table>
<app-user-table [organizationId]="organizationId" *ngIf="organizationId"></app-user-table>
</div>
</mat-tab>
<mat-tab label="{{ 'USERS.AWAITING-USERS' | translate }}">
Expand Down
56 changes: 33 additions & 23 deletions src/app/admin/users/user-list/user-list.component.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { OrganizationAccessScope } from '@shared/enums/access-scopes';
import { MeService } from '@shared/services/me.service';

@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html',
styleUrls: ['./user-list.component.scss'],
})
export class UserListComponent implements OnInit {
canEdit: boolean;
constructor(private titleService: Title, private translate: TranslateService, private meService: MeService) {}

ngOnInit(): void {
this.translate.get(['TITLE.USER'])
.subscribe(translations => {
this.titleService.setTitle(translations['TITLE.USER']);
});
this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite);
}
}
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { OrganizationAccessScope } from '@shared/enums/access-scopes';
import { MeService } from '@shared/services/me.service';
import { SharedVariableService } from '@shared/shared-variable/shared-variable.service';

@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html',
styleUrls: ['./user-list.component.scss'],
})
export class UserListComponent implements OnInit {
canEdit: boolean;
organizationId: number;

constructor(
private titleService: Title,
private translate: TranslateService,
private meService: MeService,
private globalService: SharedVariableService
) {
this.organizationId = this.globalService.getSelectedOrganisationId();
}

ngOnInit(): void {
this.translate.get(['TITLE.USER'])
.subscribe(translations => {
this.titleService.setTitle(translations['TITLE.USER']);
});
this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite);
}
}
Loading