From 52b01563eced1ca9330a4395455a80e1464feb43 Mon Sep 17 00:00:00 2001 From: domoberzin <74132255+domoberzin@users.noreply.github.com> Date: Sat, 23 Sep 2023 02:05:46 +0800 Subject: [PATCH] [#12329] Refactoring of sortable tables - Extension Confirm Modal (#12556) * fix: refactor extension confirm modal to utilise sortable tables * fix: color scheme * fix: lint issues * fix: utilise display value field for transformed data * fix: add element for table name * fix: differentiate header class for student and instructor data * fix: update snapshot * fix: lint whitespace fixes * fix: more lint fixes * fix: hide empty tables --------- Co-authored-by: Jason Qiu --- ...nsion-confirm-modal.component.spec.ts.snap | 327 ++++++++++-------- .../extension-confirm-modal.component.html | 157 ++------- .../extension-confirm-modal.component.spec.ts | 2 +- .../extension-confirm-modal.component.ts | 187 +++++++++- .../extension-confirm-modal.module.ts | 2 + 5 files changed, 383 insertions(+), 292 deletions(-) diff --git a/src/web/app/components/extension-confirm-modal/__snapshots__/extension-confirm-modal.component.spec.ts.snap b/src/web/app/components/extension-confirm-modal/__snapshots__/extension-confirm-modal.component.spec.ts.snap index ce3fa400dc7..5820c11b56e 100644 --- a/src/web/app/components/extension-confirm-modal/__snapshots__/extension-confirm-modal.component.spec.ts.snap +++ b/src/web/app/components/extension-confirm-modal/__snapshots__/extension-confirm-modal.component.spec.ts.snap @@ -7,18 +7,28 @@ exports[`ExtensionConfirmModalComponent should snap with the extended students a __ngContext__={[Function Number]} activeModal={[Function NgbActiveModal]} confirmExtensionCallbackEvent={[Function EventEmitter_]} + dateDetailPipe={[Function FormatDateDetailPipe]} extensionTimestamp={[Function Number]} feedbackSessionTimeZone={[Function String]} + headerColorScheme={[Function Number]} + instructorColumnsData={[Function Array]} + instructorRoleNamePipe={[Function InstructorRoleNamePipe]} + instructorRowsData={[Function Array]} isNotifyDeadlines="false" isSubmitting="false" modalType="0" selectedInstructors={[Function Array]} selectedStudents={[Function Array]} + sortInstructorListEvent={[Function EventEmitter_]} sortInstructorOrder="0" sortInstructorsBy={[Function Number]} + sortStudentListEvent={[Function EventEmitter_]} sortStudentOrder="0" sortStudentsBy={[Function Number]} + studentColumnsData={[Function Array]} + studentRowsData={[Function Array]} tableComparatorService={[Function TableComparatorService]} + timeZoneService={[Function TimezoneService]} >
instructor(s):
-
+

Students

- - - - + + + + + + + + + + + + + + + + + + + + + + + + + +
- +
+ Test Section 1 + + Test Section 1 + + Test Student 1 + + testStudent1@gmail.com + + 5 Apr 2000 2:00:00 +
+ Test Section 2 + + Test Section 2 + + Test Student 2 + + testStudent2@gmail.com + + 5 Apr 2000 2:00:00 +
+ Test Section 3 + + Test Section 3 + + Test Student 3 + + testStudent3@gmail.com + + 5 Apr 2000 2:00:00 +
+
Confir {{ extensionTimestamp | formatDateDetail: feedbackSessionTimeZone }}:
-
+

Students

- - - - - - - - - - - - - - - - - -
- - - - - - - - - -
{{ student.sectionName }}{{ student.teamName }}{{ student.name }}{{ student.email }}{{ student.extensionDeadline | formatDateDetail: feedbackSessionTimeZone }}
+
-
+

Instructors

- - - - - - - - - - - - - - - -
- - - - - - - -
{{ instructor.name }}{{ instructor.email }}{{ instructor.role | instructorRoleName }}{{ instructor.extensionDeadline | formatDateDetail: feedbackSessionTimeZone }}
+
diff --git a/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.spec.ts b/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.spec.ts index 1f0b0e3f2f9..9f859d63cd3 100644 --- a/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.spec.ts +++ b/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.spec.ts @@ -89,7 +89,7 @@ describe('ExtensionConfirmModalComponent', () => { }); it('should snap with the extended students and instructors', () => { - component.selectedStudents = [studentModel1, studentModel2, studentModel3]; + component.studentData = [studentModel1, studentModel2, studentModel3]; component.extensionTimestamp = testFeedbackSession.submissionEndTimestamp; fixture.detectChanges(); expect(fixture).toMatchSnapshot(); diff --git a/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.ts b/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.ts index 8ef0eeaf32a..5ca6bf28f42 100644 --- a/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.ts +++ b/src/web/app/components/extension-confirm-modal/extension-confirm-modal.component.ts @@ -1,11 +1,20 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { TableComparatorService } from '../../../services/table-comparator.service'; +import { TimezoneService } from '../../../services/timezone.service'; import { SortBy, SortOrder } from '../../../types/sort-properties'; import { StudentExtensionTableColumnModel, InstructorExtensionTableColumnModel, } from '../../pages-instructor/instructor-session-individual-extension-page/extension-table-column-model'; +import { + ColumnData, + SortableEvent, + SortableTableCellData, + SortableTableHeaderColorScheme, + } from '../sortable-table/sortable-table.component'; +import { FormatDateDetailPipe } from '../teammates-common/format-date-detail.pipe'; +import { InstructorRoleNamePipe } from '../teammates-common/instructor-role-name.pipe'; export enum ExtensionModalType { EXTEND, @@ -18,7 +27,7 @@ export enum ExtensionModalType { templateUrl: './extension-confirm-modal.component.html', styleUrls: ['./extension-confirm-modal.component.scss'], }) -export class ExtensionConfirmModalComponent { +export class ExtensionConfirmModalComponent implements OnInit { @Input() modalType: ExtensionModalType = ExtensionModalType.EXTEND; @@ -34,10 +43,41 @@ export class ExtensionConfirmModalComponent { @Input() feedbackSessionTimeZone: string = ''; + @Input() + headerColorScheme: SortableTableHeaderColorScheme = SortableTableHeaderColorScheme.WHITE; + + @Input() set studentData(studentData: StudentExtensionTableColumnModel[]) { + this.selectedStudents = studentData; + if (this.selectedStudents.length > 0) { + this.setStudentTableData(); + } + } + + @Input() set instructorData(instructorData: InstructorExtensionTableColumnModel[]) { + this.selectedInstructors = instructorData; + if (this.selectedInstructors.length > 0) { + this.setInstructorTableData(); + } + } + @Output() confirmExtensionCallbackEvent: EventEmitter = new EventEmitter(); - constructor(public activeModal: NgbActiveModal, private tableComparatorService: TableComparatorService) {} + @Output() + sortStudentListEvent: EventEmitter = new EventEmitter(); + + @Output() + sortInstructorListEvent: EventEmitter = new EventEmitter(); + + studentColumnsData : ColumnData[] = []; + studentRowsData : SortableTableCellData[][] = []; + instructorColumnsData : ColumnData[] = []; + instructorRowsData : SortableTableCellData[][] = []; + dateDetailPipe = new FormatDateDetailPipe(this.timeZoneService); + instructorRoleNamePipe = new InstructorRoleNamePipe(); + + constructor(public activeModal: NgbActiveModal, private tableComparatorService: TableComparatorService, + private timeZoneService: TimezoneService) {} SortBy: typeof SortBy = SortBy; SortOrder: typeof SortOrder = SortOrder; @@ -49,6 +89,135 @@ export class ExtensionConfirmModalComponent { isSubmitting: boolean = false; isNotifyDeadlines: boolean = false; + ngOnInit(): void { + if (this.selectedStudents.length > 0) { + this.setStudentTableData(); + } + + if (this.selectedInstructors.length > 0) { + this.setInstructorTableData(); + } + } + + setStudentTableData(): void { + this.setStudentColumnData(); + this.setStudentRowData(); + } + + setInstructorTableData(): void { + this.setInstructorColumnData(); + this.setInstructorRowData(); + } + + setStudentColumnData(): void { + this.studentColumnsData = [ + { + header: 'Section', + sortBy: SortBy.SECTION_NAME, + headerClass: 'student-sort-by-section', + }, + { + header: 'Team', + sortBy: SortBy.TEAM_NAME, + headerClass: 'student-sort-by-team', + }, + { + header: 'Name', + sortBy: SortBy.RESPONDENT_NAME, + headerClass: 'student-sort-by-name', + }, + { + header: 'Email', + sortBy: SortBy.RESPONDENT_EMAIL, + headerClass: 'student-sort-by-email', + }, + { + header: this.isDeleteModal() || this.isSessionDeleteModal() ? 'Current Deadline' : 'Original Deadline', + sortBy: SortBy.SESSION_END_DATE, + headerClass: 'student-sort-by-deadline', + }, + ]; + } + + setStudentRowData(): void { + this.studentRowsData = this.selectedStudents + .map((studentData: StudentExtensionTableColumnModel) => { + const rowData: SortableTableCellData[] = [ + { + value: studentData.sectionName, + }, + { + value: studentData.teamName, + }, + { + value: studentData.name, + }, + { + value: studentData.email, + }, + { + value: studentData.extensionDeadline, + displayValue: this.dateDetailPipe.transform( + studentData.extensionDeadline, + this.feedbackSessionTimeZone), + }, + ]; + return rowData; + }); + } + + setInstructorColumnData(): void { + this.instructorColumnsData = [ + { + header: 'Name', + sortBy: SortBy.RESPONDENT_NAME, + headerClass: 'instructor-sort-by-name', + }, + { + header: 'Email', + sortBy: SortBy.RESPONDENT_EMAIL, + headerClass: 'instructor-sort-by-email', + }, + { + header: 'Role', + sortBy: SortBy.INSTRUCTOR_PERMISSION_ROLE, + headerClass: 'instructor-sort-by-role', + }, + { + header: this.isDeleteModal() || this.isSessionDeleteModal() ? 'Current Deadline' : 'Original Deadline', + sortBy: SortBy.SESSION_END_DATE, + headerClass: 'instructor-sort-by-deadline', + }, + ]; + } + + setInstructorRowData(): void { + this.instructorRowsData = this.selectedInstructors + .map((instructorData: InstructorExtensionTableColumnModel) => { + const rowData: SortableTableCellData[] = [ + { + value: instructorData.name, + }, + { + value: instructorData.email, + }, + { + value: instructorData.role, + displayValue: instructorData.role + ? this.instructorRoleNamePipe.transform(instructorData.role) + : instructorData.role, + }, + { + value: instructorData.extensionDeadline, + displayValue: this.dateDetailPipe.transform( + instructorData.extensionDeadline, + this.feedbackSessionTimeZone), + }, + ]; + return rowData; + }); + } + onConfirm(): void { this.isSubmitting = true; this.confirmExtensionCallbackEvent.emit(this.isNotifyDeadlines); @@ -66,10 +235,8 @@ export class ExtensionConfirmModalComponent { return this.modalType === ExtensionModalType.SESSION_DELETE; } - sortStudentColumnsBy(by: SortBy): void { - this.sortStudentsBy = by; - this.sortStudentOrder = this.sortStudentOrder === SortOrder.DESC ? SortOrder.ASC : SortOrder.DESC; - this.selectedStudents.sort(this.sortStudentPanelsBy(by)); + sortStudentColumnsByEventHandler(event: { sortBy: SortBy, sortOrder: SortOrder }): void { + this.sortStudentListEvent.emit(event); } getAriaSortStudent(by: SortBy): String { @@ -114,10 +281,8 @@ export class ExtensionConfirmModalComponent { }; } - sortInstructorsColumnsBy(by: SortBy): void { - this.sortInstructorsBy = by; - this.sortInstructorOrder = this.sortInstructorOrder === SortOrder.DESC ? SortOrder.ASC : SortOrder.DESC; - this.selectedInstructors.sort(this.sortInstructorPanelsBy(by)); + sortInstructorsColumnsByEventHandler(event: { sortBy: SortBy, sortOrder: SortOrder }): void { + this.sortInstructorListEvent.emit(event); } getAriaSortInstructor(by: SortBy): String { diff --git a/src/web/app/components/extension-confirm-modal/extension-confirm-modal.module.ts b/src/web/app/components/extension-confirm-modal/extension-confirm-modal.module.ts index 28b7b4bff2d..0da808f31fe 100644 --- a/src/web/app/components/extension-confirm-modal/extension-confirm-modal.module.ts +++ b/src/web/app/components/extension-confirm-modal/extension-confirm-modal.module.ts @@ -1,6 +1,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; +import { SortableTableModule } from '../sortable-table/sortable-table.module'; import { TeammatesCommonModule } from '../teammates-common/teammates-common.module'; import { ExtensionConfirmModalComponent } from './extension-confirm-modal.component'; @@ -15,6 +16,7 @@ import { ExtensionConfirmModalComponent } from './extension-confirm-modal.compon CommonModule, FormsModule, TeammatesCommonModule, + SortableTableModule, ], exports: [ ExtensionConfirmModalComponent,