refactor: bind components to api
This commit is contained in:
		| @@ -6,12 +6,13 @@ | |||||||
|       </mat-panel-title> |       </mat-panel-title> | ||||||
|     </mat-expansion-panel-header> |     </mat-expansion-panel-header> | ||||||
|     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseFaculty($event)"> |     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseFaculty($event)"> | ||||||
|       @for (faculty of faculties | async; track $index) { |       @for (faculty of faculties; track $index) { | ||||||
|         <mat-chip-option [value]="faculty.id" color="accent"> |         <mat-chip-option [value]="faculty.id" color="accent"> | ||||||
|           {{ faculty.name }} |           {{ faculty.name }} | ||||||
|         </mat-chip-option> |         </mat-chip-option> | ||||||
|       } @empty { |       } @empty { | ||||||
|         <app-loading-indicator [loading]="facultiesLoaded !== null" (retryFunction)="facultiesLoadRetry.emit()"/> |         <app-loading-indicator [loading]="facultiesLoaded !== null" | ||||||
|  |                                (retryFunction)="loadFaculties()"/> | ||||||
|       } |       } | ||||||
|     </mat-chip-listbox> |     </mat-chip-listbox> | ||||||
|   </mat-expansion-panel> |   </mat-expansion-panel> | ||||||
| @@ -22,14 +23,14 @@ | |||||||
|         Курс |         Курс | ||||||
|       </mat-panel-title> |       </mat-panel-title> | ||||||
|     </mat-expansion-panel-header> |     </mat-expansion-panel-header> | ||||||
|     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCourseNumber($event)" [formControl]="chipCourse"> |     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCourseNumber($event)" [formControl]="formChipCourse"> | ||||||
|       @for (course of courseNumbers | async; track $index) { |       @for (course of courseNumbers; track $index) { | ||||||
|         <mat-chip-option [value]="course" color="accent"> |         <mat-chip-option [value]="course" color="accent"> | ||||||
|           {{ course }} |           {{ course }} | ||||||
|         </mat-chip-option> |         </mat-chip-option> | ||||||
|       } @empty { |       } @empty { | ||||||
|         <app-loading-indicator [loading]="groupsLoaded !== null" |         <app-loading-indicator [loading]="groupsLoaded !== null" | ||||||
|                                (retryFunction)="groupsLoadRetry.emit(this.facultyId!)"/> |                                (retryFunction)="loadCourseGroup()"/> | ||||||
|       } |       } | ||||||
|     </mat-chip-listbox> |     </mat-chip-listbox> | ||||||
|   </mat-expansion-panel> |   </mat-expansion-panel> | ||||||
| @@ -40,14 +41,14 @@ | |||||||
|         Группа |         Группа | ||||||
|       </mat-panel-title> |       </mat-panel-title> | ||||||
|     </mat-expansion-panel-header> |     </mat-expansion-panel-header> | ||||||
|     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseGroup($event)" [formControl]="chipGroup"> |     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseGroup($event)" [formControl]="formChipGroup"> | ||||||
|       @for (group of filteredGroups | async; track $index) { |       @for (group of filteredGroups; track $index) { | ||||||
|         <mat-chip-option [value]="group.id" color="accent"> |         <mat-chip-option [value]="group.id" color="accent"> | ||||||
|           {{ group.name }} |           {{ group.name }} | ||||||
|         </mat-chip-option> |         </mat-chip-option> | ||||||
|       } @empty { |       } @empty { | ||||||
|         <app-loading-indicator [loading]="groupsLoaded !== null" |         <app-loading-indicator [loading]="groupsLoaded !== null" | ||||||
|                                (retryFunction)="groupsLoadRetry.emit(this.facultyId!)"/> |                                (retryFunction)="loadCourseGroup()"/> | ||||||
|       } |       } | ||||||
|     </mat-chip-listbox> |     </mat-chip-listbox> | ||||||
|   </mat-expansion-panel> |   </mat-expansion-panel> | ||||||
|   | |||||||
| @@ -1,12 +1,13 @@ | |||||||
| import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; | import {Component, EventEmitter, Output, ViewChild} from '@angular/core'; | ||||||
| import {MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion"; | import {MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion"; | ||||||
| import {MatChipListboxChange, MatChipsModule} from '@angular/material/chips'; | import {MatChipListboxChange, MatChipsModule} from '@angular/material/chips'; | ||||||
| import {FormControl, ReactiveFormsModule} from "@angular/forms"; | import {FormControl, FormsModule, ReactiveFormsModule} from "@angular/forms"; | ||||||
| import {AsyncPipe} from "@angular/common"; | import {catchError} from "rxjs"; | ||||||
| import {map, Observable, of} from "rxjs"; |  | ||||||
| import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; | import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; | ||||||
| import {GroupResponse} from "@api/v1/groupResponse"; | import {GroupResponse} from "@api/v1/groupResponse"; | ||||||
| import {FacultyResponse} from "@api/v1/facultyResponse"; | import {FacultyResponse} from "@api/v1/facultyResponse"; | ||||||
|  | import {FacultyService} from "@api/v1/faculty.service"; | ||||||
|  | import {GroupService} from "@api/v1/group.service"; | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-group', |   selector: 'app-group', | ||||||
| @@ -16,49 +17,98 @@ import {FacultyResponse} from "@api/v1/facultyResponse"; | |||||||
|     MatChipsModule, |     MatChipsModule, | ||||||
|     ReactiveFormsModule, |     ReactiveFormsModule, | ||||||
|     LoadingIndicatorComponent, |     LoadingIndicatorComponent, | ||||||
|     AsyncPipe |     FormsModule | ||||||
|   ], |   ], | ||||||
|   templateUrl: './group.component.html', |   templateUrl: './group.component.html', | ||||||
|   styleUrl: './group.component.css' |   styleUrl: './group.component.css', | ||||||
|  |   providers: [FacultyService, GroupService] | ||||||
| }) | }) | ||||||
|  |  | ||||||
| export class GroupComponent { | export class GroupComponent { | ||||||
|   protected facultyId: number | null = null; |   protected facultyId: number | null = null; | ||||||
|   protected courseNumber: number | null = null; |   protected courseNumber: number | null = null; | ||||||
|  |  | ||||||
|   protected filteredGroups: Observable<GroupResponse[]> = of([]); |   protected filteredGroups: GroupResponse[] = []; | ||||||
|   protected courseNumbers: Observable<number[]> = of([]); |   protected courseNumbers: number[] = []; | ||||||
|   protected groups: Observable<GroupResponse[]> = of([]); |   private groups: GroupResponse[] = []; | ||||||
|  |  | ||||||
|   protected chipCourse: FormControl = new FormControl(); |   protected formChipCourse: FormControl = new FormControl(); | ||||||
|   protected chipGroup: FormControl = new FormControl(); |   protected formChipGroup: FormControl = new FormControl(); | ||||||
|  |  | ||||||
|  |   protected faculties: FacultyResponse[] = []; | ||||||
|  |  | ||||||
|   @ViewChild('courseNumberPanel') courseNumberPanel!: MatExpansionPanel; |   @ViewChild('courseNumberPanel') courseNumberPanel!: MatExpansionPanel; | ||||||
|   @ViewChild('groupPanel') groupPanel!: MatExpansionPanel; |   @ViewChild('groupPanel') groupPanel!: MatExpansionPanel; | ||||||
|  |  | ||||||
|   @Input() faculties: Observable<FacultyResponse[]> = of([]); |   protected facultiesLoaded: boolean | null = false; | ||||||
|   @Input() facultiesLoaded: boolean | null = false; |   protected groupsLoaded: boolean | null = false; | ||||||
|   @Output() facultiesLoadRetry: EventEmitter<void> = new EventEmitter<void>(); |  | ||||||
|   @Input() groupsLoaded: boolean | null = false; |  | ||||||
|   @Output() groupsLoadRetry: EventEmitter<number> = new EventEmitter<number>(); |  | ||||||
|  |  | ||||||
|   @Input() set setGroups(data: Observable<GroupResponse[]>) { |   @Output() eventResult = new EventEmitter<number>(); | ||||||
|     this.groups = data; |  | ||||||
|     this.courseNumbers = this.groups.pipe( |   constructor(private facultyApi: FacultyService, private groupApi: GroupService) { | ||||||
|       map(data => data.map(g => g.courseNumber)), |     this.loadFaculties(); | ||||||
|       map(courseNumbersArray => courseNumbersArray.filter((value, index, self) => self.indexOf(value) === index)), |  | ||||||
|       map(uniqueCourseNumbers => uniqueCourseNumbers.sort((a, b) => a - b)) |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Output() groupSelected = new EventEmitter<number>(); |   protected loadFaculties() { | ||||||
|   @Output() facultySelected = new EventEmitter<number>(); |     this.facultiesLoaded = false; | ||||||
|  |     this.facultyApi.getFaculties() | ||||||
|  |       .pipe(catchError(error => { | ||||||
|  |         this.facultiesLoaded = null; | ||||||
|  |         throw error; | ||||||
|  |       })) | ||||||
|  |       .subscribe(data => { | ||||||
|  |         this.faculties = data; | ||||||
|  |         this.facultiesLoaded = true; | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private filteringCourseNumber() { | ||||||
|  |     this.courseNumbers = Array.from( | ||||||
|  |       new Set( | ||||||
|  |         this.groups | ||||||
|  |           .filter(x => x.facultyId === this.facultyId) | ||||||
|  |           .map(x => x.courseNumber) | ||||||
|  |       ) | ||||||
|  |     ).sort((a, b) => a - b); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private filteringGroup() { | ||||||
|  |     this.filteredGroups = this.groups.filter(x => x.facultyId === this.facultyId && x.courseNumber === this.courseNumber); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected loadCourseGroup() { | ||||||
|  |     if (this.groups.length === 0) { | ||||||
|  |       this.groupsLoaded = false; | ||||||
|  |  | ||||||
|  |       this.groupApi.getGroups().pipe( | ||||||
|  |         catchError(error => { | ||||||
|  |           this.groupsLoaded = null; | ||||||
|  |           throw error; | ||||||
|  |         }) | ||||||
|  |       ).subscribe(data => { | ||||||
|  |         this.groups = data; | ||||||
|  |         if (this.courseNumber === null) | ||||||
|  |           this.filteringCourseNumber(); | ||||||
|  |         else | ||||||
|  |           this.filteringGroup(); | ||||||
|  |  | ||||||
|  |         this.groupsLoaded = true; | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this.courseNumber === null) | ||||||
|  |       this.filteringCourseNumber(); | ||||||
|  |     else | ||||||
|  |       this.filteringGroup(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   protected chooseFaculty(event: MatChipListboxChange) { |   protected chooseFaculty(event: MatChipListboxChange) { | ||||||
|     this.courseNumber = null; |     this.courseNumber = null; | ||||||
|     this.groups = of([]); |     this.groups = []; | ||||||
|     this.chipGroup.reset(); |     this.formChipGroup.reset(); | ||||||
|     this.chipCourse.reset(); |     this.formChipCourse.reset(); | ||||||
|  |  | ||||||
|     if (event.value === undefined || event.value === null) { |     if (event.value === undefined || event.value === null) { | ||||||
|       this.facultyId = null; |       this.facultyId = null; | ||||||
| @@ -67,12 +117,12 @@ export class GroupComponent { | |||||||
|     this.facultyId = event.value; |     this.facultyId = event.value; | ||||||
|     this.courseNumberPanel.open(); |     this.courseNumberPanel.open(); | ||||||
|  |  | ||||||
|     this.facultySelected.emit(this.facultyId!); |     this.loadCourseGroup(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected chooseCourseNumber(event: MatChipListboxChange) { |   protected chooseCourseNumber(event: MatChipListboxChange) { | ||||||
|     this.filteredGroups = of([]); |     this.filteredGroups = []; | ||||||
|     this.chipGroup.reset(); |     this.formChipGroup.reset(); | ||||||
|  |  | ||||||
|     if (event.value === undefined || event.value === null) { |     if (event.value === undefined || event.value === null) { | ||||||
|       this.courseNumber = null; |       this.courseNumber = null; | ||||||
| @@ -81,8 +131,7 @@ export class GroupComponent { | |||||||
|  |  | ||||||
|     this.courseNumber = event.value; |     this.courseNumber = event.value; | ||||||
|     this.groupPanel.open(); |     this.groupPanel.open(); | ||||||
|     this.groups.subscribe(data => |     this.loadCourseGroup(); | ||||||
|       this.filteredGroups = of(data.filter(g => g.courseNumber === this.courseNumber))); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected chooseGroup(event: MatChipListboxChange) { |   protected chooseGroup(event: MatChipListboxChange) { | ||||||
| @@ -90,6 +139,6 @@ export class GroupComponent { | |||||||
|       return; |       return; | ||||||
|  |  | ||||||
|     this.groupPanel.close(); |     this.groupPanel.close(); | ||||||
|     this.groupSelected.emit(event.value); |     this.eventResult.emit(event.value); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,12 +6,12 @@ | |||||||
|       </mat-panel-title> |       </mat-panel-title> | ||||||
|     </mat-expansion-panel-header> |     </mat-expansion-panel-header> | ||||||
|     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCampus($event)"> |     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCampus($event)"> | ||||||
|       @for (campus of campuses | async; track $index) { |       @for (campus of campuses; track $index) { | ||||||
|         <mat-chip-option [value]="campus.id" color="accent"> |         <mat-chip-option [value]="campus.id" color="accent"> | ||||||
|           {{ campus.codeName }} |           {{ campus.codeName }} | ||||||
|         </mat-chip-option> |         </mat-chip-option> | ||||||
|       } @empty { |       } @empty { | ||||||
|         <app-loading-indicator [loading]="campusesLoaded !== null" (retryFunction)="campusesLoadRetry.emit()"/> |         <app-loading-indicator [loading]="campusesLoaded !== null" (retryFunction)="loadCampuses()"/> | ||||||
|       } |       } | ||||||
|     </mat-chip-listbox> |     </mat-chip-listbox> | ||||||
|   </mat-expansion-panel> |   </mat-expansion-panel> | ||||||
| @@ -23,12 +23,12 @@ | |||||||
|       </mat-panel-title> |       </mat-panel-title> | ||||||
|     </mat-expansion-panel-header> |     </mat-expansion-panel-header> | ||||||
|     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseLectureHall($event)" [formControl]="chipLecture"> |     <mat-chip-listbox hideSingleSelectionIndicator (change)="chooseLectureHall($event)" [formControl]="chipLecture"> | ||||||
|       @for (lectureHall of lectureHalls | async; track $index) { |       @for (lectureHall of lectureHallsFiltered; track $index) { | ||||||
|         <mat-chip-option [value]="lectureHall.id" color="accent"> |         <mat-chip-option [value]="lectureHall.id" color="accent"> | ||||||
|           {{ lectureHall.name }} |           {{ lectureHall.name }} | ||||||
|         </mat-chip-option> |         </mat-chip-option> | ||||||
|       } @empty { |       } @empty { | ||||||
|         <app-loading-indicator [loading]="lectureHallsLoaded !== null" (retryFunction)="lectureHallsLoadRetry.emit()"/> |         <app-loading-indicator [loading]="lectureHallsLoaded !== null" (retryFunction)="loadLectureHalls()"/> | ||||||
|       } |       } | ||||||
|     </mat-chip-listbox> |     </mat-chip-listbox> | ||||||
|   </mat-expansion-panel> |   </mat-expansion-panel> | ||||||
|   | |||||||
| @@ -2,11 +2,13 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; | |||||||
| import {AsyncPipe} from "@angular/common"; | import {AsyncPipe} from "@angular/common"; | ||||||
| import {MatAccordion, MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion"; | import {MatAccordion, MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion"; | ||||||
| import {MatChipListboxChange, MatChipsModule} from "@angular/material/chips"; | import {MatChipListboxChange, MatChipsModule} from "@angular/material/chips"; | ||||||
| import {Observable, of} from "rxjs"; | import {catchError, Observable, of} from "rxjs"; | ||||||
| import {FormControl, ReactiveFormsModule} from "@angular/forms"; | import {FormControl, ReactiveFormsModule} from "@angular/forms"; | ||||||
| import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; | import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; | ||||||
| import {CampusBasicInfoResponse} from "@api/v1/campusBasicInfoResponse"; | import {CampusBasicInfoResponse} from "@api/v1/campusBasicInfoResponse"; | ||||||
| import {LectureHallResponse} from "@api/v1/lectureHallResponse"; | import {LectureHallResponse} from "@api/v1/lectureHallResponse"; | ||||||
|  | import {CampusService} from "@api/v1/campus.service"; | ||||||
|  | import {LectureHallService} from "@api/v1/lectureHall.service"; | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-lecture-hall', |   selector: 'app-lecture-hall', | ||||||
| @@ -20,7 +22,8 @@ import {LectureHallResponse} from "@api/v1/lectureHallResponse"; | |||||||
|     LoadingIndicatorComponent |     LoadingIndicatorComponent | ||||||
|   ], |   ], | ||||||
|   templateUrl: './lecture-hall.component.html', |   templateUrl: './lecture-hall.component.html', | ||||||
|   styleUrl: './lecture-hall.component.css' |   styleUrl: './lecture-hall.component.css', | ||||||
|  |   providers: [CampusService, LectureHallService] | ||||||
| }) | }) | ||||||
|  |  | ||||||
| export class LectureHallComponent { | export class LectureHallComponent { | ||||||
| @@ -29,29 +32,66 @@ export class LectureHallComponent { | |||||||
|  |  | ||||||
|   @ViewChild('lecturePanel') lecturePanel!: MatExpansionPanel; |   @ViewChild('lecturePanel') lecturePanel!: MatExpansionPanel; | ||||||
|  |  | ||||||
|   @Input() campuses: Observable<CampusBasicInfoResponse[]> = of([]); |   protected campuses: CampusBasicInfoResponse[] = []; | ||||||
|   @Input() campusesLoaded: boolean | null = false; |   protected campusesLoaded: boolean | null = false; | ||||||
|   @Output() campusesLoadRetry: EventEmitter<void> = new EventEmitter<void>(); |  | ||||||
|   @Input() lectureHalls: Observable<LectureHallResponse[]> = of([]); |  | ||||||
|   @Input() lectureHallsLoaded: boolean | null = false; |  | ||||||
|   @Output() lectureHallsLoadRetry: EventEmitter<number> = new EventEmitter<number>(); |  | ||||||
|  |  | ||||||
|   @Output() campusSelected = new EventEmitter<number>(); |   private lectureHalls: LectureHallResponse[] = []; | ||||||
|   @Output() lectureHallSelected = new EventEmitter<number>(); |   protected lectureHallsFiltered: LectureHallResponse[] = []; | ||||||
|  |   protected lectureHallsLoaded: boolean | null = false; | ||||||
|  |  | ||||||
|  |   @Output() eventResult = new EventEmitter<number>(); | ||||||
|  |  | ||||||
|  |   constructor(private campusApi: CampusService, private lectureHallApi: LectureHallService) { | ||||||
|  |     this.loadCampuses(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected loadCampuses() { | ||||||
|  |     this.campusesLoaded = false; | ||||||
|  |     this.campusApi.getCampus() | ||||||
|  |       .pipe(catchError(error => { | ||||||
|  |         this.campusesLoaded = null; | ||||||
|  |         throw error; | ||||||
|  |       })) | ||||||
|  |       .subscribe(data => { | ||||||
|  |         this.campuses = data; | ||||||
|  |         this.campusesLoaded = true; | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private filteringLectureHalls() { | ||||||
|  |     this.lectureHallsFiltered = this.lectureHalls.filter(x => x.campusId === this.campusId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   protected chooseCampus(event: MatChipListboxChange) { |   protected chooseCampus(event: MatChipListboxChange) { | ||||||
|     this.chipLecture.reset(); |     this.chipLecture.reset(); | ||||||
|  |  | ||||||
|     if (event.value === undefined || event.value === null) { |     if (event.value === undefined || event.value === null) { | ||||||
|       this.campusId = null; |       this.campusId = null; | ||||||
|       this.lectureHalls = of([]); |       this.lectureHalls = []; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     this.campusId = event.value; |     this.campusId = event.value; | ||||||
|     this.lecturePanel.open(); |     this.lecturePanel.open(); | ||||||
|  |  | ||||||
|     this.campusSelected.emit(this.campusId!); |     if (this.lectureHalls.length === 0) | ||||||
|  |       this.loadLectureHalls(); | ||||||
|  |     else | ||||||
|  |       this.filteringLectureHalls(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected loadLectureHalls() { | ||||||
|  |     this.lectureHallsLoaded = false; | ||||||
|  |     this.lectureHallApi.getLectureHalls() | ||||||
|  |       .pipe(catchError(error => { | ||||||
|  |         this.lectureHallsLoaded = null; | ||||||
|  |         throw error; | ||||||
|  |       })) | ||||||
|  |       .subscribe(data => { | ||||||
|  |         this.lectureHalls = data; | ||||||
|  |         this.filteringLectureHalls(); | ||||||
|  |         this.lectureHallsLoaded = true; | ||||||
|  |       }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected chooseLectureHall(event: MatChipListboxChange) { |   protected chooseLectureHall(event: MatChipListboxChange) { | ||||||
| @@ -59,6 +99,6 @@ export class LectureHallComponent { | |||||||
|       return; |       return; | ||||||
|  |  | ||||||
|     this.lecturePanel.close(); |     this.lecturePanel.close(); | ||||||
|     this.lectureHallSelected.emit(event.value); |     this.eventResult.emit(event.value); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <div class="search-content"> | <div class="search-content"> | ||||||
|   @if (professors.length === 0) { |   @if (professors.length === 0) { | ||||||
|     <app-loading-indicator [loading]="professorsLoaded !== null" (retryFunction)="professorsLoadRetry.emit()"/> |     <app-loading-indicator [loading]="professorsLoaded !== null" (retryFunction)="loadProfessors()"/> | ||||||
|   } @else { |   } @else { | ||||||
|     <mat-form-field color="accent" style="width: 100%;"> |     <mat-form-field color="accent" style="width: 100%;"> | ||||||
|       <input type="text" placeholder="Поиск..." matInput [formControl]="professorControl" [matAutocomplete]="auto"> |       <input type="text" placeholder="Поиск..." matInput [formControl]="professorControl" [matAutocomplete]="auto"> | ||||||
|   | |||||||
| @@ -3,9 +3,10 @@ import {MatFormField, MatInput} from "@angular/material/input"; | |||||||
| import {FormControl, ReactiveFormsModule} from "@angular/forms"; | import {FormControl, ReactiveFormsModule} from "@angular/forms"; | ||||||
| import {MatAutocompleteModule, MatAutocompleteSelectedEvent} from "@angular/material/autocomplete"; | import {MatAutocompleteModule, MatAutocompleteSelectedEvent} from "@angular/material/autocomplete"; | ||||||
| import {AsyncPipe} from "@angular/common"; | import {AsyncPipe} from "@angular/common"; | ||||||
| import {map, Observable, startWith} from "rxjs"; | import {catchError, map, Observable, startWith} from "rxjs"; | ||||||
| import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; | import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; | ||||||
| import {ProfessorResponse} from "@api/v1/professorResponse"; | import {ProfessorResponse} from "@api/v1/professorResponse"; | ||||||
|  | import {ProfessorService} from "@api/v1/professor.service"; | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-professor', |   selector: 'app-professor', | ||||||
| @@ -19,17 +20,37 @@ import {ProfessorResponse} from "@api/v1/professorResponse"; | |||||||
|     LoadingIndicatorComponent |     LoadingIndicatorComponent | ||||||
|   ], |   ], | ||||||
|   templateUrl: './professor.component.html', |   templateUrl: './professor.component.html', | ||||||
|   styleUrl: './professor.component.css' |   styleUrl: './professor.component.css', | ||||||
|  |   providers: [ProfessorService] | ||||||
| }) | }) | ||||||
| export class ProfessorComponent implements OnInit { | export class ProfessorComponent implements OnInit { | ||||||
|   protected professorControl = new FormControl(); |   protected professorControl = new FormControl(); | ||||||
|   protected filteredProfessors!: Observable<ProfessorResponse[]>; |   protected filteredProfessors!: Observable<ProfessorResponse[]>; | ||||||
|  |  | ||||||
|   @Input() professors: ProfessorResponse[] = []; |   protected professors: ProfessorResponse[] = []; | ||||||
|   @Output() professorSelected = new EventEmitter<number>(); |   protected professorsLoaded: boolean | null = false; | ||||||
|  |  | ||||||
|   @Input() professorsLoaded: boolean | null = false; |   @Output() eventResult = new EventEmitter<number>(); | ||||||
|   @Output() professorsLoadRetry: EventEmitter<void> = new EventEmitter<void>(); |  | ||||||
|  |   constructor(private api: ProfessorService) { | ||||||
|  |     this.loadProfessors(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected loadProfessors() { | ||||||
|  |     if (this.professors.length === 0) { | ||||||
|  |       this.professorsLoaded = false; | ||||||
|  |  | ||||||
|  |       this.api.getProfessors() | ||||||
|  |         .pipe(catchError(error => { | ||||||
|  |           this.professorsLoaded = null; | ||||||
|  |           throw error; | ||||||
|  |         })) | ||||||
|  |         .subscribe(data => { | ||||||
|  |           this.professors = data; | ||||||
|  |           this.professorsLoaded = true; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   ngOnInit(): void { |   ngOnInit(): void { | ||||||
|     this.filteredProfessors = this.professorControl.valueChanges.pipe( |     this.filteredProfessors = this.professorControl.valueChanges.pipe( | ||||||
| @@ -53,7 +74,7 @@ export class ProfessorComponent implements OnInit { | |||||||
|     const selectedOption = this.professors.find(teacher => teacher.id === event.option.value); |     const selectedOption = this.professors.find(teacher => teacher.id === event.option.value); | ||||||
|     if (selectedOption) { |     if (selectedOption) { | ||||||
|       this.professorControl.setValue(selectedOption.name); |       this.professorControl.setValue(selectedOption.name); | ||||||
|       this.professorSelected.emit(selectedOption.id); |       this.eventResult.emit(selectedOption.id); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,24 +2,17 @@ | |||||||
|                (selectedTabChange)="chooseTabs($event)"> |                (selectedTabChange)="chooseTabs($event)"> | ||||||
|   <mat-tab label="Группа"> |   <mat-tab label="Группа"> | ||||||
|     <div> |     <div> | ||||||
|       <app-group (groupSelected)="groupSelected.emit($event)" (facultySelected)="groupLoad($event)" |       <app-group (eventResult)="groupSelected($event)"/> | ||||||
|                                [setGroups]="groups" [faculties]="faculties" [facultiesLoaded]="facultiesLoaded" |  | ||||||
|                                [groupsLoaded]="groupLoaded" (groupsLoadRetry)="groupLoad($event)" |  | ||||||
|                                (facultiesLoadRetry)="facultyLoad()"/> |  | ||||||
|     </div> |     </div> | ||||||
|   </mat-tab> |   </mat-tab> | ||||||
|   <mat-tab label="Преподаватель"> |   <mat-tab label="Преподаватель"> | ||||||
|     <div> |     <div> | ||||||
|       <app-professor (professorSelected)="professorSelected.emit($event)" [professors]="professorsData" [professorsLoaded]="professorsLoaded" (professorsLoadRetry)="professorsLoad()"/> |       <app-professor (eventResult)="professorSelected($event)"/> | ||||||
|     </div> |     </div> | ||||||
|   </mat-tab> |   </mat-tab> | ||||||
|   <mat-tab label="Кабинет"> |   <mat-tab label="Кабинет"> | ||||||
|     <div> |     <div> | ||||||
|       <app-lecture-hall (lectureHallSelected)="lectureHallSelected.emit($event)" [campuses]="campuses" |       <app-lecture-hall (eventResult)="lectureHallSelected($event)"/> | ||||||
|                                       (campusSelected)="lectureHallLoad($event)" [lectureHalls]="lectureHalls" |  | ||||||
|                                       [campusesLoaded]="campusesLoaded" [lectureHallsLoaded]="lectureHallsLoaded" |  | ||||||
|                                       (campusesLoadRetry)="campusLoad()" |  | ||||||
|                                       (lectureHallsLoadRetry)="lectureHallLoad($event)"/> |  | ||||||
|     </div> |     </div> | ||||||
|   </mat-tab> |   </mat-tab> | ||||||
|   <mat-tab label="Другое"> |   <mat-tab label="Другое"> | ||||||
|   | |||||||
| @@ -1,38 +1,31 @@ | |||||||
| import {Component, EventEmitter, Output, ViewChild} from '@angular/core'; | import {Component, EventEmitter, Output} from '@angular/core'; | ||||||
| import {HttpClientModule} from "@angular/common/http"; |  | ||||||
| import {OtherComponent} from "@component/schedule/tabs/other/other.component"; | import {OtherComponent} from "@component/schedule/tabs/other/other.component"; | ||||||
| import {MatTab, MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs"; | import {MatTab, MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs"; | ||||||
| import {catchError, map, Observable, of, switchMap, tap} from "rxjs"; | import {map, Observable} from "rxjs"; | ||||||
| import {ReactiveFormsModule} from "@angular/forms"; | import {ReactiveFormsModule} from "@angular/forms"; | ||||||
| import {AsyncPipe, NgIf} from "@angular/common"; |  | ||||||
| import {MatButton} from "@angular/material/button"; | import {MatButton} from "@angular/material/button"; | ||||||
| import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component"; | import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component"; | ||||||
| import {ProfessorResponse} from "@api/v1/professorResponse"; |  | ||||||
| import {FacultyResponse} from "@api/v1/facultyResponse"; |  | ||||||
| import {GroupResponse} from "@api/v1/groupResponse"; |  | ||||||
| import {CampusBasicInfoResponse} from "@api/v1/campusBasicInfoResponse"; |  | ||||||
| import {LectureHallResponse} from "@api/v1/lectureHallResponse"; |  | ||||||
| import {DisciplineService} from "@api/v1/discipline.service"; |  | ||||||
| import {GroupComponent} from "@component/schedule/tabs/group/group.component"; | import {GroupComponent} from "@component/schedule/tabs/group/group.component"; | ||||||
| import {ProfessorComponent} from "@component/schedule/tabs/professor/professor.component"; | import {ProfessorComponent} from "@component/schedule/tabs/professor/professor.component"; | ||||||
| import {LectureHallComponent} from "@component/schedule/tabs/lecture-hall/lecture-hall.component"; | import {LectureHallComponent} from "@component/schedule/tabs/lecture-hall/lecture-hall.component"; | ||||||
| import {FacultyService} from "@api/v1/faculty.service"; | import {ScheduleService} from "@api/v1/schedule.service"; | ||||||
| import {GroupService} from "@api/v1/group.service"; | import {ScheduleResponse} from "@api/v1/scheduleResponse"; | ||||||
| import {ProfessorService} from "@api/v1/professor.service"; |  | ||||||
| import {CampusService} from "@api/v1/campus.service"; | export enum TabsSelect { | ||||||
| import {LectureHallService} from "@api/v1/lectureHall.service"; |   Group, | ||||||
|  |   Professor, | ||||||
|  |   LectureHall, | ||||||
|  |   Other | ||||||
|  | } | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-tabs', |   selector: 'app-tabs', | ||||||
|   standalone: true, |   standalone: true, | ||||||
|   imports: [ |   imports: [ | ||||||
|     HttpClientModule, |  | ||||||
|     OtherComponent, |     OtherComponent, | ||||||
|     MatTabGroup, |     MatTabGroup, | ||||||
|     MatTab, |     MatTab, | ||||||
|     ReactiveFormsModule, |     ReactiveFormsModule, | ||||||
|     AsyncPipe, |  | ||||||
|     NgIf, |  | ||||||
|     MatButton, |     MatButton, | ||||||
|     DataSpinnerComponent, |     DataSpinnerComponent, | ||||||
|     GroupComponent, |     GroupComponent, | ||||||
| @@ -41,171 +34,122 @@ import {LectureHallService} from "@api/v1/lectureHall.service"; | |||||||
|   ], |   ], | ||||||
|   templateUrl: './tabs.component.html', |   templateUrl: './tabs.component.html', | ||||||
|   styleUrl: './tabs.component.css', |   styleUrl: './tabs.component.css', | ||||||
|   providers: [FacultyService, GroupService, ProfessorService, CampusService, LectureHallService, DisciplineService ] |   providers: [ScheduleService] | ||||||
| }) | }) | ||||||
|  |  | ||||||
| export class TabsComponent { | export class TabsComponent { | ||||||
|   protected professorsData: ProfessorResponse[] = []; |   @Output() eventResult = new EventEmitter<[TabsSelect, number, Observable<ScheduleResponse[]>]>(); | ||||||
|  |  | ||||||
|   protected faculties: Observable<FacultyResponse[]> = of([]); |   constructor(private scheduleApi: ScheduleService) { | ||||||
|   protected groups: Observable<GroupResponse[]> = of([]); |   } | ||||||
|   private groupsData: Observable<GroupResponse[]> = of([]); |  | ||||||
|  |  | ||||||
|   protected campuses: Observable<CampusBasicInfoResponse[]> = of([]); |   protected campuses: Observable<CampusBasicInfoResponse[]> = of([]); | ||||||
|   protected lectureHalls: Observable<LectureHallResponse[]> = of([]); |   protected lectureHalls: Observable<LectureHallResponse[]> = of([]); | ||||||
|   private lectureHallsData: Observable<LectureHallResponse[]> = of([]); |   private lectureHallsData: Observable<LectureHallResponse[]> = of([]); | ||||||
|  |   protected groupSelected(id: number) { | ||||||
|  |     this.eventResult.emit( | ||||||
|  |       [ | ||||||
|  |         TabsSelect.Group, | ||||||
|  |         id, | ||||||
|  |         this.scheduleApi.getByGroup(id) | ||||||
|  |           .pipe( | ||||||
|  |             map(g => | ||||||
|  |               g.map(data => | ||||||
|  |                 ({ | ||||||
|  |                   dayOfWeek: data.dayOfWeek, | ||||||
|  |                   pairNumber: data.pairNumber, | ||||||
|  |                   isEven: data.isEven, | ||||||
|  |                   discipline: data.discipline, | ||||||
|  |                   disciplineId: data.disciplineId, | ||||||
|  |                   isExcludedWeeks: data.isExcludedWeeks, | ||||||
|  |                   weeks: data.weeks, | ||||||
|  |                   typeOfOccupations: data.typeOfOccupations, | ||||||
|  |                   group: data.group, | ||||||
|  |                   groupId: data.groupId, | ||||||
|  |                   lectureHalls: data.lectureHalls, | ||||||
|  |                   lectureHallsId: data.lectureHallsId, | ||||||
|  |                   professors: data.professors, | ||||||
|  |                   professorsId: data.professorsId, | ||||||
|  |                   campus: data.campus, | ||||||
|  |                   campusId: data.campusId, | ||||||
|  |                   linkToMeet: data.linkToMeet | ||||||
|  |                 })) | ||||||
|  |             ) | ||||||
|  |           ) | ||||||
|  |       ] | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // States |   protected professorSelected(id: number) { | ||||||
|   protected facultiesLoaded: boolean | null = false; |     this.eventResult.emit( | ||||||
|   protected groupLoaded: boolean | null = false; |       [ | ||||||
|   protected campusesLoaded: boolean | null = false; |         TabsSelect.Professor, | ||||||
|   protected lectureHallsLoaded: boolean | null = false; |         id, | ||||||
|   protected disciplinesLoaded: boolean | null = false; |         this.scheduleApi.getByProfessor(id) | ||||||
|   protected professorsLoaded: boolean | null = false; |           .pipe( | ||||||
|  |             map(p => | ||||||
|  |               p.map(data => | ||||||
|  |                 ({ | ||||||
|  |                   dayOfWeek: data.dayOfWeek, | ||||||
|  |                   pairNumber: data.pairNumber, | ||||||
|  |                   isEven: data.isEven, | ||||||
|  |                   discipline: data.discipline, | ||||||
|  |                   disciplineId: data.disciplineId, | ||||||
|  |                   isExcludedWeeks: data.isExcludedWeeks, | ||||||
|  |                   weeks: data.weeks, | ||||||
|  |                   typeOfOccupations: data.typeOfOccupations, | ||||||
|  |                   group: data.group, | ||||||
|  |                   groupId: data.groupId, | ||||||
|  |                   lectureHalls: data.lectureHalls, | ||||||
|  |                   lectureHallsId: data.lectureHallsId, | ||||||
|  |                   professors: data.professors, | ||||||
|  |                   professorsId: data.professorsId, | ||||||
|  |                   campus: data.campus, | ||||||
|  |                   campusId: data.campusId, | ||||||
|  |                   linkToMeet: data.linkToMeet | ||||||
|  |                 })) | ||||||
|  |             ) | ||||||
|  |           ) | ||||||
|  |       ] | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @Output() groupSelected: EventEmitter<number> = new EventEmitter<number>(); |   protected lectureHallSelected(id: number) { | ||||||
|   @Output() lectureHallSelected: EventEmitter<number> = new EventEmitter<number>(); |     this.eventResult.emit( | ||||||
|   @Output() professorSelected: EventEmitter<number> = new EventEmitter<number>(); |       [ | ||||||
|  |         TabsSelect.LectureHall, | ||||||
|   constructor( |         id, | ||||||
|     private facultyApi: FacultyService, |         this.scheduleApi.getByLectureHall(id) | ||||||
|     private groupApi: GroupService, |           .pipe( | ||||||
|     private professorApi: ProfessorService, |             map(lh => | ||||||
|     private campusApi: CampusService, |               lh.map(data => | ||||||
|     private lectureHallApi: LectureHallService, |                 ({ | ||||||
|     private disciplineApi: DisciplineService) { |                   dayOfWeek: data.dayOfWeek, | ||||||
|     this.facultyLoad().then(); |                   pairNumber: data.pairNumber, | ||||||
|  |                   isEven: data.isEven, | ||||||
|  |                   discipline: data.discipline, | ||||||
|  |                   disciplineId: data.disciplineId, | ||||||
|  |                   isExcludedWeeks: data.isExcludedWeeks, | ||||||
|  |                   weeks: data.weeks, | ||||||
|  |                   typeOfOccupations: data.typeOfOccupations, | ||||||
|  |                   group: data.group, | ||||||
|  |                   groupId: data.groupId, | ||||||
|  |                   lectureHalls: data.lectureHalls, | ||||||
|  |                   lectureHallsId: data.lectureHallsId, | ||||||
|  |                   professors: data.professors, | ||||||
|  |                   professorsId: data.professorsId, | ||||||
|  |                   campus: data.campus, | ||||||
|  |                   campusId: data.campusId, | ||||||
|  |                   linkToMeet: data.linkToMeet | ||||||
|  |                 })) | ||||||
|  |             ) | ||||||
|  |           ) | ||||||
|  |       ] | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected async chooseTabs(event: MatTabChangeEvent) { |   protected async chooseTabs(event: MatTabChangeEvent) { | ||||||
|     switch (event.index) { |     switch (event.index) { | ||||||
|       case 0: |  | ||||||
|         await this.facultyLoad(); |  | ||||||
|         break; |  | ||||||
|       case 1: |  | ||||||
|         this.professorsLoad(); |  | ||||||
|         break; |  | ||||||
|       case 2: |  | ||||||
|         await this.campusLoad(); |  | ||||||
|         break; |  | ||||||
|       case 3: |  | ||||||
|         await this.extensionLoad(); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   protected async facultyLoad() { |  | ||||||
|     if (this.facultiesLoaded === null) this.facultiesLoaded = false; |  | ||||||
|     if (this.facultiesLoaded) return; |  | ||||||
|  |  | ||||||
|     this.faculties = this.facultyApi.getFaculties().pipe( |  | ||||||
|       tap(() => { |  | ||||||
|         this.facultiesLoaded = true; |  | ||||||
|       }), |  | ||||||
|       catchError((error) => { |  | ||||||
|         this.facultiesLoaded = null; |  | ||||||
|         throw error; |  | ||||||
|       }) |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   protected groupLoad(id: number) { |  | ||||||
|     if (this.groupLoaded === null) this.groupLoaded = false; |  | ||||||
|  |  | ||||||
|     if (this.groupLoaded) |  | ||||||
|       this.groups = this.groupsData.pipe(map(data => data.filter(x => x.facultyId === id))); |  | ||||||
|     else |  | ||||||
|       this.groups = this.groupApi.getByFaculty(id).pipe( |  | ||||||
|         tap(() => { |  | ||||||
|           this.groupLoaded = false; |  | ||||||
|         }), |  | ||||||
|         catchError((error) => { |  | ||||||
|           this.groupLoaded = null; |  | ||||||
|           throw error; |  | ||||||
|         }) |  | ||||||
|       ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   protected professorsLoad() { |  | ||||||
|     if (this.professorsLoaded === null) this.professorsLoaded = false; |  | ||||||
|  |  | ||||||
|     if (this.professorsLoaded) return; |  | ||||||
|  |  | ||||||
|     this.professorApi.getProfessors().pipe( |  | ||||||
|       catchError((error) => { |  | ||||||
|         this.professorsLoaded = null; |  | ||||||
|         throw error; |  | ||||||
|       }) |  | ||||||
|     ).subscribe(data => { |  | ||||||
|       this.professorsData = data; |  | ||||||
|       this.professorEx.Data = data.map(x => |  | ||||||
|         ({ |  | ||||||
|           id: x.id, |  | ||||||
|           name: x.altName ? x.altName : x.name, |  | ||||||
|           selected: false |  | ||||||
|         })); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   protected async campusLoad() { |  | ||||||
|     if (this.campusesLoaded === null) this.campusesLoaded = false; |  | ||||||
|  |  | ||||||
|     if (this.campusesLoaded) return; |  | ||||||
|  |  | ||||||
|     this.campuses = this.campusApi.getCampus().pipe( |  | ||||||
|       tap(() => { |  | ||||||
|         this.campusesLoaded = true; |  | ||||||
|       }), |  | ||||||
|       catchError((error) => { |  | ||||||
|         this.campusesLoaded = null; |  | ||||||
|         throw error; |  | ||||||
|       }) |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   protected lectureHallLoad(id: number) { |  | ||||||
|     if (this.lectureHallsLoaded === null) this.lectureHallsLoaded = false; |  | ||||||
|  |  | ||||||
|     if (this.lectureHallsLoaded) |  | ||||||
|       this.lectureHalls = this.lectureHallsData.pipe(map(data => data.filter(x => x.campusId === id))); |  | ||||||
|     else |  | ||||||
|       this.lectureHalls = this.lectureHallApi.getByCampus(id).pipe( |  | ||||||
|         tap(() => { |  | ||||||
|           this.lectureHallsLoaded = false; |  | ||||||
|         }), |  | ||||||
|         catchError((error) => { |  | ||||||
|           this.lectureHallsLoaded = null; |  | ||||||
|           throw error; |  | ||||||
|         }) |  | ||||||
|       ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   protected async loadLectureHalls() { |  | ||||||
|     if (!this.campusesLoaded) |  | ||||||
|       await this.campusLoad(); |  | ||||||
|  |  | ||||||
|     if (!this.lectureHallsLoaded) { |  | ||||||
|       this.lectureHallsData = this.lectureHallApi.getLectureHalls(); |  | ||||||
|       this.lectureHallsData.pipe( |  | ||||||
|         switchMap(lectureHalls => this.campuses.pipe( |  | ||||||
|           map(campuses => { |  | ||||||
|             return lectureHalls.map(x => { |  | ||||||
|               const campus = campuses.find(c => c.id === x.campusId); |  | ||||||
|               const codeName = campus ? campus.codeName : ''; |  | ||||||
|               return { |  | ||||||
|                 id: x.id, |  | ||||||
|                 name: `${x.name} (${codeName})`, |  | ||||||
|                 selected: false |  | ||||||
|               }; |  | ||||||
|             }); |  | ||||||
|           }) |  | ||||||
|         )), |  | ||||||
|       ).subscribe(data => { |  | ||||||
|         this.lectureHallEx.Data = data; |  | ||||||
|         this.lectureHallsLoaded = true; |  | ||||||
|         this.campusesLoaded = true; |  | ||||||
|       }); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user