Skip to content

Commit

Permalink
[#11878] Update Admin Home Page UI for ARF (#12933)
Browse files Browse the repository at this point in the history
* create component for account request table

* cherry pick admin home page changes

* remove testing code

* fix lint and css issues

* fix admin home page snaps

* update admin home snaps

* remove edit approve and reject components

* modify css

* delete edit and reject modal components

* revert spec file changes

* integrate new types

* fix lint

* use enum for status

* fix lint

* fix css lint

* fix lint

* fix lint

* use enum and remove infinite scroll

* remove approve account request code

* remove extra div

* fix url

* modify comments

* revert extra formatting

* remove plural form and use date pipe

* fix naming

* fix spec file and update institute formatting

* fix lint

* combine institute and country columns
  • Loading branch information
domoberzin authored Mar 27, 2024
1 parent f7eaa61 commit 40613df
Show file tree
Hide file tree
Showing 14 changed files with 408 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Model for the row entries in the account requests table.
*/
export interface AccountRequestTableRowModel {
name: string;
email: string;
status: string;
instituteAndCountry: string;
createdAtText: string;
registeredAtText: string;
comments: string;
registrationLink: string;
showLinks: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<div class="card bg-light top-padded" *ngIf="accountRequests.length">
<div class="card-header bg-primary text-white">
<div *ngIf="searchString; else pendingRequests">
<strong>Account Requests Found</strong>
</div>
<ng-template #pendingRequests>
<strong>Pending Account Requests</strong>
</ng-template>
<div *ngIf="searchString" class="card-header-btn-toolbar">
<button id="show-account-request-links" class="btn btn-light btn-sm" style="margin-right: 10px;" type="button" (click)="showAllAccountRequestsLinks()">Expand All</button>
<button id="hide-account-request-links" class="btn btn-light btn-sm" type="button" (click)="hideAllAccountRequestsLinks()">Collapse All</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped data-table" id="search-table-account-request">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Status</th>
<th>Institute, Country</th>
<th>Created At</th>
<th *ngIf="searchString">Registered At</th>
<th>Comments</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let accountRequest of accountRequests; let i = index">
<tr>
<td [innerHtml]="accountRequest.name | highlighter:searchString:true">
<br>
<div class="col-sm-1">
<button *ngIf="!accountRequest.showLinks" class="btn" aria-label="Expand">
<i class="fas fa-chevron-circle-down" style="color: blue;"></i>
</button>
<button *ngIf="accountRequest.showLinks" class="btn" aria-label="Collapse">
<i class="fas fa-chevron-circle-up" style="color: blue;"></i>
</button>
</div>
</td>
<td [innerHtml]="accountRequest.email | highlighter:searchString:true">{{ accountRequest.email }}</td>
<td>{{ accountRequest.status }}</td>
<td [innerHtml]="accountRequest.instituteAndCountry | highlighter:searchString:true">{{ accountRequest.instituteAndCountry }}</td>
<td id="timestamp-box">{{ accountRequest.createdAtText }}</td>
<td *ngIf="searchString" id="timestamp-box">{{ accountRequest.registeredAtText || 'Not Registered Yet' }}</td>
<td>
<div id="comment-box">
{{ accountRequest.comments }}
</div>
</td>
<td class="align-middle">
<div class="d-flex flex-row align-items-center justify-content-center gap-2">
<div class="ngb-tooltip-class" [ngbTooltip]="accountRequest.registeredAtText && 'Account requests of registered instructors cannot be deleted'">
<a id="delete-account-request-{{i}}" href="javascript:;" (click)="$event.stopPropagation(); deleteAccountRequest(accountRequest)">
<i class="fa-solid fa-trash"></i>
</a>
</div>
<div>
<a id="view-account-request-{{i}}" href="javascript:;" (click)="$event.stopPropagation(); viewAccountRequest(accountRequest)">
<i class="fa-solid fa-eye"></i>
</a>
</div>
<div *ngIf="searchString" class="ngb-tooltip-class" [ngbTooltip]="accountRequest.registeredAtText && 'Account requests of registered instructors cannot be deleted'">
<button id="reset-account-request-{{i}}" class="btn btn-primary" [disabled]="!accountRequest.registeredAtText" (click)="$event.stopPropagation(); resetAccountRequest(accountRequest);">Reset</button>
</div>
</div>
</td>
</tr>
<tr *ngIf="accountRequest.showLinks && searchString">
<td colspan="8">
<ul class="list-group" *ngIf="accountRequest.showLinks" @collapseAnim>
<li class="list-group-item list-group-item-info">
<strong>Account Registration Link</strong>
<input [value]="accountRequest.registrationLink" disabled class="form-control">
</li>
</ul>
</td>
</tr>
</ng-container>
</tbody>
</table>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
::ng-deep .highlighted-text {
background-color: yellow;
}

.table-responsive {
overflow: -moz-scrollbars-horizontal;
}

.table-responsive > table > thead > tr > th {
white-space: nowrap;
}

/* stylelint-disable property-no-vendor-prefix */
::-webkit-scrollbar {
-webkit-appearance: none;
width: 1px;
}

::-webkit-scrollbar-thumb {
border-radius: 0;
background-color: rgb(0 0 0 / 50%);
box-shadow: 0 0 1px rgb(255 255 255 / 50%);
}


#search-table-account-request {
border-collapse: collapse;
}


#search-table-account-request th:last-child,
#search-table-account-request td:last-child {
min-width: 10vw;
position: sticky;
right: 0;
z-index: 1;
background-color: #F8F9FA;
}

#search-table-account-request th:last-child::after,
#search-table-account-request td:last-child::after {
content: "";
position: absolute;
left: -1px;
top: 0;
bottom: 0;
width: 1px;
background: #c8c7c7;
z-index: 1;
}

#comment-box {
min-height: 5vh;
width: max(800px, 35vw);
max-width: max-content;
word-break: break-word;
word-wrap: break-all;

}

.dropdown-item {
border: none;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Component, Input } from '@angular/core';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { AccountRequestTableRowModel } from './account-request-table-model';
import { AccountService } from '../../../services/account.service';
import { SimpleModalService } from '../../../services/simple-modal.service';
import { StatusMessageService } from '../../../services/status-message.service';
import { MessageOutput } from '../../../types/api-output';
import { ErrorMessageOutput } from '../../error-message-output';
import { SimpleModalType } from '../simple-modal/simple-modal-type';
import { collapseAnim } from '../teammates-common/collapse-anim';

/**
* Account requests table component.
*/
@Component({
selector: 'tm-account-request-table',
templateUrl: './account-request-table.component.html',
styleUrls: ['./account-request-table.component.scss'],
animations: [collapseAnim],
})

export class AccountRequestTableComponent {

@Input()
accountRequests: AccountRequestTableRowModel[] = [];

@Input()
searchString = '';

constructor(
private statusMessageService: StatusMessageService,
private simpleModalService: SimpleModalService,
private accountService: AccountService,
) {}

/**
* Shows all account requests' links in the page.
*/
showAllAccountRequestsLinks(): void {
for (const accountRequest of this.accountRequests) {
accountRequest.showLinks = true;
}
}

/**
* Hides all account requests' links in the page.
*/
hideAllAccountRequestsLinks(): void {
for (const accountRequest of this.accountRequests) {
accountRequest.showLinks = false;
}
}

resetAccountRequest(accountRequest: AccountRequestTableRowModel): void {
const modalContent = `Are you sure you want to reset the account request for
<strong>${accountRequest.name}</strong> with email <strong>${accountRequest.email}</strong> from
<strong>${accountRequest.instituteAndCountry}</strong>?
An email with the account registration link will also be sent to the instructor.`;
const modalRef: NgbModalRef = this.simpleModalService.openConfirmationModal(
`Reset account request for <strong>${accountRequest.name}</strong>?`, SimpleModalType.WARNING, modalContent);

modalRef.result.then(() => {
this.accountService.resetAccountRequest(accountRequest.email, accountRequest.instituteAndCountry)
.subscribe({
next: () => {
this.statusMessageService
.showSuccessToast(`Reset successful. An email has been sent to ${accountRequest.email}.`);
accountRequest.registeredAtText = '';
},
error: (resp: ErrorMessageOutput) => {
this.statusMessageService.showErrorToast(resp.error.message);
},
});
}, () => {});
}

deleteAccountRequest(accountRequest: AccountRequestTableRowModel): void {
const modalContent: string = `Are you sure you want to <strong>delete</strong> the account request for
<strong>${accountRequest.name}</strong> with email <strong>${accountRequest.email}</strong> from
<strong>${accountRequest.instituteAndCountry}</strong>?`;
const modalRef: NgbModalRef = this.simpleModalService.openConfirmationModal(
`Delete account request for <strong>${accountRequest.name}</strong>?`, SimpleModalType.DANGER, modalContent);

modalRef.result.then(() => {
this.accountService.deleteAccountRequest(accountRequest.email, accountRequest.instituteAndCountry)
.subscribe({
next: (resp: MessageOutput) => {
this.statusMessageService.showSuccessToast(resp.message);
this.accountRequests = this.accountRequests.filter((x: AccountRequestTableRowModel) => x !== accountRequest);
},
error: (resp: ErrorMessageOutput) => {
this.statusMessageService.showErrorToast(resp.error.message);
},
});
}, () => {});
}

viewAccountRequest(accountRequest: AccountRequestTableRowModel): void {
const modalContent: string = `<strong>Comment:</strong> ${accountRequest.comments || ''}`;
const modalRef: NgbModalRef = this.simpleModalService.openInformationModal(
`Comments for <strong>${accountRequest.name}</strong> Request`, SimpleModalType.INFO, modalContent);

modalRef.result.then(() => {}, () => {});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbTooltipModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { AccountRequestTableComponent } from './account-request-table.component';
import { Pipes } from '../../pipes/pipes.module';

/**
* Module for account requests table.
*/
@NgModule({
declarations: [
AccountRequestTableComponent,
],
exports: [
AccountRequestTableComponent,
],
imports: [
CommonModule,
FormsModule,
NgbTooltipModule,
NgbDropdownModule,
Pipes,
],
})
export class AccountRequestTableModule { }
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@

exports[`AdminHomePageComponent should snap with default view 1`] = `
<tm-admin-home-page
accountReqs={[Function Array]}
accountService={[Function AccountService]}
activeRequests="0"
courseService={[Function CourseService]}
currentPage={[Function Number]}
formatDateDetailPipe={[Function FormatDateDetailPipe]}
instructorDetails=""
instructorEmail=""
instructorInstitution=""
instructorName=""
instructorsConsolidated={[Function Array]}
isAddingInstructors="false"
isRegisteredInstructorModalLoading="false"
items$={[Function Observable]}
linkService={[Function LinkService]}
ngbModal={[Function _NgbModal]}
pageSize={[Function Number]}
registeredInstructorAccountData={[Function Array]}
registeredInstructorIndex="0"
registeredInstructorModal={[Function TemplateRef2]}
simpleModalService={[Function SimpleModalService]}
statusMessageService={[Function StatusMessageService]}
timezoneService={[Function TimezoneService]}
>
<div
class="card bg-light top-padded"
Expand Down Expand Up @@ -131,23 +137,29 @@ exports[`AdminHomePageComponent should snap with default view 1`] = `

exports[`AdminHomePageComponent should snap with disabled adding instructor button if there are active requests 1`] = `
<tm-admin-home-page
accountReqs={[Function Array]}
accountService={[Function AccountService]}
activeRequests={[Function Number]}
courseService={[Function CourseService]}
currentPage={[Function Number]}
formatDateDetailPipe={[Function FormatDateDetailPipe]}
instructorDetails=""
instructorEmail=""
instructorInstitution=""
instructorName=""
instructorsConsolidated={[Function Array]}
isAddingInstructors={[Function Boolean]}
isRegisteredInstructorModalLoading="false"
items$={[Function Observable]}
linkService={[Function LinkService]}
ngbModal={[Function _NgbModal]}
pageSize={[Function Number]}
registeredInstructorAccountData={[Function Array]}
registeredInstructorIndex="0"
registeredInstructorModal={[Function TemplateRef2]}
simpleModalService={[Function SimpleModalService]}
statusMessageService={[Function StatusMessageService]}
timezoneService={[Function TimezoneService]}
>
<div
class="card bg-light top-padded"
Expand Down Expand Up @@ -424,23 +436,29 @@ exports[`AdminHomePageComponent should snap with disabled adding instructor butt

exports[`AdminHomePageComponent should snap with some instructors details 1`] = `
<tm-admin-home-page
accountReqs={[Function Array]}
accountService={[Function AccountService]}
activeRequests="0"
courseService={[Function CourseService]}
currentPage={[Function Number]}
formatDateDetailPipe={[Function FormatDateDetailPipe]}
instructorDetails=""
instructorEmail=""
instructorInstitution=""
instructorName=""
instructorsConsolidated={[Function Array]}
isAddingInstructors="false"
isRegisteredInstructorModalLoading="false"
items$={[Function Observable]}
linkService={[Function LinkService]}
ngbModal={[Function _NgbModal]}
pageSize={[Function Number]}
registeredInstructorAccountData={[Function Array]}
registeredInstructorIndex="0"
registeredInstructorModal={[Function TemplateRef2]}
simpleModalService={[Function SimpleModalService]}
statusMessageService={[Function StatusMessageService]}
timezoneService={[Function TimezoneService]}
>
<div
class="card bg-light top-padded"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,4 @@ <h6 class="card-title mt-3">Student for the following <b>{{ account.studentCours
</div>
</div>
</ng-template>
<tm-account-request-table *ngIf="accountReqs.length" [accountRequests]="accountReqs" [searchString]=""></tm-account-request-table>
Loading

0 comments on commit 40613df

Please sign in to comment.