diff --git a/src/components/schedule/tabs/group/group.component.html b/src/components/schedule/tabs/group/group.component.html index c2d88b9..566594a 100644 --- a/src/components/schedule/tabs/group/group.component.html +++ b/src/components/schedule/tabs/group/group.component.html @@ -6,12 +6,13 @@ - @for (faculty of faculties | async; track $index) { + @for (faculty of faculties; track $index) { {{ faculty.name }} } @empty { - + } @@ -22,14 +23,14 @@ Курс - - @for (course of courseNumbers | async; track $index) { + + @for (course of courseNumbers; track $index) { {{ course }} } @empty { + (retryFunction)="loadCourseGroup()"/> } @@ -40,14 +41,14 @@ Группа - - @for (group of filteredGroups | async; track $index) { + + @for (group of filteredGroups; track $index) { {{ group.name }} } @empty { + (retryFunction)="loadCourseGroup()"/> } diff --git a/src/components/schedule/tabs/group/group.component.ts b/src/components/schedule/tabs/group/group.component.ts index 1b2c525..465258f 100644 --- a/src/components/schedule/tabs/group/group.component.ts +++ b/src/components/schedule/tabs/group/group.component.ts @@ -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 {MatChipListboxChange, MatChipsModule} from '@angular/material/chips'; -import {FormControl, ReactiveFormsModule} from "@angular/forms"; -import {AsyncPipe} from "@angular/common"; -import {map, Observable, of} from "rxjs"; +import {FormControl, FormsModule, ReactiveFormsModule} from "@angular/forms"; +import {catchError} from "rxjs"; import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; import {GroupResponse} from "@api/v1/groupResponse"; import {FacultyResponse} from "@api/v1/facultyResponse"; +import {FacultyService} from "@api/v1/faculty.service"; +import {GroupService} from "@api/v1/group.service"; @Component({ selector: 'app-group', @@ -16,49 +17,98 @@ import {FacultyResponse} from "@api/v1/facultyResponse"; MatChipsModule, ReactiveFormsModule, LoadingIndicatorComponent, - AsyncPipe + FormsModule ], templateUrl: './group.component.html', - styleUrl: './group.component.css' + styleUrl: './group.component.css', + providers: [FacultyService, GroupService] }) export class GroupComponent { protected facultyId: number | null = null; protected courseNumber: number | null = null; - protected filteredGroups: Observable = of([]); - protected courseNumbers: Observable = of([]); - protected groups: Observable = of([]); + protected filteredGroups: GroupResponse[] = []; + protected courseNumbers: number[] = []; + private groups: GroupResponse[] = []; - protected chipCourse: FormControl = new FormControl(); - protected chipGroup: FormControl = new FormControl(); + protected formChipCourse: FormControl = new FormControl(); + protected formChipGroup: FormControl = new FormControl(); + + protected faculties: FacultyResponse[] = []; @ViewChild('courseNumberPanel') courseNumberPanel!: MatExpansionPanel; @ViewChild('groupPanel') groupPanel!: MatExpansionPanel; - @Input() faculties: Observable = of([]); - @Input() facultiesLoaded: boolean | null = false; - @Output() facultiesLoadRetry: EventEmitter = new EventEmitter(); - @Input() groupsLoaded: boolean | null = false; - @Output() groupsLoadRetry: EventEmitter = new EventEmitter(); + protected facultiesLoaded: boolean | null = false; + protected groupsLoaded: boolean | null = false; - @Input() set setGroups(data: Observable) { - this.groups = data; - this.courseNumbers = this.groups.pipe( - map(data => data.map(g => g.courseNumber)), - map(courseNumbersArray => courseNumbersArray.filter((value, index, self) => self.indexOf(value) === index)), - map(uniqueCourseNumbers => uniqueCourseNumbers.sort((a, b) => a - b)) - ); + @Output() eventResult = new EventEmitter(); + + constructor(private facultyApi: FacultyService, private groupApi: GroupService) { + this.loadFaculties(); } - @Output() groupSelected = new EventEmitter(); - @Output() facultySelected = new EventEmitter(); + protected loadFaculties() { + 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) { this.courseNumber = null; - this.groups = of([]); - this.chipGroup.reset(); - this.chipCourse.reset(); + this.groups = []; + this.formChipGroup.reset(); + this.formChipCourse.reset(); if (event.value === undefined || event.value === null) { this.facultyId = null; @@ -67,12 +117,12 @@ export class GroupComponent { this.facultyId = event.value; this.courseNumberPanel.open(); - this.facultySelected.emit(this.facultyId!); + this.loadCourseGroup(); } protected chooseCourseNumber(event: MatChipListboxChange) { - this.filteredGroups = of([]); - this.chipGroup.reset(); + this.filteredGroups = []; + this.formChipGroup.reset(); if (event.value === undefined || event.value === null) { this.courseNumber = null; @@ -81,8 +131,7 @@ export class GroupComponent { this.courseNumber = event.value; this.groupPanel.open(); - this.groups.subscribe(data => - this.filteredGroups = of(data.filter(g => g.courseNumber === this.courseNumber))); + this.loadCourseGroup(); } protected chooseGroup(event: MatChipListboxChange) { @@ -90,6 +139,6 @@ export class GroupComponent { return; this.groupPanel.close(); - this.groupSelected.emit(event.value); + this.eventResult.emit(event.value); } } diff --git a/src/components/schedule/tabs/lecture-hall/lecture-hall.component.html b/src/components/schedule/tabs/lecture-hall/lecture-hall.component.html index b132e17..faa01b9 100644 --- a/src/components/schedule/tabs/lecture-hall/lecture-hall.component.html +++ b/src/components/schedule/tabs/lecture-hall/lecture-hall.component.html @@ -6,12 +6,12 @@ - @for (campus of campuses | async; track $index) { + @for (campus of campuses; track $index) { {{ campus.codeName }} } @empty { - + } @@ -23,12 +23,12 @@ - @for (lectureHall of lectureHalls | async; track $index) { + @for (lectureHall of lectureHallsFiltered; track $index) { {{ lectureHall.name }} } @empty { - + } diff --git a/src/components/schedule/tabs/lecture-hall/lecture-hall.component.ts b/src/components/schedule/tabs/lecture-hall/lecture-hall.component.ts index df06d01..8e90438 100644 --- a/src/components/schedule/tabs/lecture-hall/lecture-hall.component.ts +++ b/src/components/schedule/tabs/lecture-hall/lecture-hall.component.ts @@ -2,11 +2,13 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; import {AsyncPipe} from "@angular/common"; import {MatAccordion, MatExpansionModule, MatExpansionPanel} from "@angular/material/expansion"; 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 {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component"; import {CampusBasicInfoResponse} from "@api/v1/campusBasicInfoResponse"; import {LectureHallResponse} from "@api/v1/lectureHallResponse"; +import {CampusService} from "@api/v1/campus.service"; +import {LectureHallService} from "@api/v1/lectureHall.service"; @Component({ selector: 'app-lecture-hall', @@ -20,7 +22,8 @@ import {LectureHallResponse} from "@api/v1/lectureHallResponse"; LoadingIndicatorComponent ], templateUrl: './lecture-hall.component.html', - styleUrl: './lecture-hall.component.css' + styleUrl: './lecture-hall.component.css', + providers: [CampusService, LectureHallService] }) export class LectureHallComponent { @@ -29,29 +32,66 @@ export class LectureHallComponent { @ViewChild('lecturePanel') lecturePanel!: MatExpansionPanel; - @Input() campuses: Observable = of([]); - @Input() campusesLoaded: boolean | null = false; - @Output() campusesLoadRetry: EventEmitter = new EventEmitter(); - @Input() lectureHalls: Observable = of([]); - @Input() lectureHallsLoaded: boolean | null = false; - @Output() lectureHallsLoadRetry: EventEmitter = new EventEmitter(); + protected campuses: CampusBasicInfoResponse[] = []; + protected campusesLoaded: boolean | null = false; - @Output() campusSelected = new EventEmitter(); - @Output() lectureHallSelected = new EventEmitter(); + private lectureHalls: LectureHallResponse[] = []; + protected lectureHallsFiltered: LectureHallResponse[] = []; + protected lectureHallsLoaded: boolean | null = false; + + @Output() eventResult = new EventEmitter(); + + 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) { this.chipLecture.reset(); if (event.value === undefined || event.value === null) { this.campusId = null; - this.lectureHalls = of([]); + this.lectureHalls = []; return; } this.campusId = event.value; 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) { @@ -59,6 +99,6 @@ export class LectureHallComponent { return; this.lecturePanel.close(); - this.lectureHallSelected.emit(event.value); + this.eventResult.emit(event.value); } } diff --git a/src/components/schedule/tabs/professor/professor.component.html b/src/components/schedule/tabs/professor/professor.component.html index 3fc2074..4a2ed0a 100644 --- a/src/components/schedule/tabs/professor/professor.component.html +++ b/src/components/schedule/tabs/professor/professor.component.html @@ -1,6 +1,6 @@
@if (professors.length === 0) { - + } @else { diff --git a/src/components/schedule/tabs/professor/professor.component.ts b/src/components/schedule/tabs/professor/professor.component.ts index 8b1e2ab..fffe10c 100644 --- a/src/components/schedule/tabs/professor/professor.component.ts +++ b/src/components/schedule/tabs/professor/professor.component.ts @@ -3,9 +3,10 @@ import {MatFormField, MatInput} from "@angular/material/input"; import {FormControl, ReactiveFormsModule} from "@angular/forms"; import {MatAutocompleteModule, MatAutocompleteSelectedEvent} from "@angular/material/autocomplete"; 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 {ProfessorResponse} from "@api/v1/professorResponse"; +import {ProfessorService} from "@api/v1/professor.service"; @Component({ selector: 'app-professor', @@ -19,17 +20,37 @@ import {ProfessorResponse} from "@api/v1/professorResponse"; LoadingIndicatorComponent ], templateUrl: './professor.component.html', - styleUrl: './professor.component.css' + styleUrl: './professor.component.css', + providers: [ProfessorService] }) export class ProfessorComponent implements OnInit { protected professorControl = new FormControl(); protected filteredProfessors!: Observable; - @Input() professors: ProfessorResponse[] = []; - @Output() professorSelected = new EventEmitter(); + protected professors: ProfessorResponse[] = []; + protected professorsLoaded: boolean | null = false; - @Input() professorsLoaded: boolean | null = false; - @Output() professorsLoadRetry: EventEmitter = new EventEmitter(); + @Output() eventResult = new EventEmitter(); + + 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 { 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); if (selectedOption) { this.professorControl.setValue(selectedOption.name); - this.professorSelected.emit(selectedOption.id); + this.eventResult.emit(selectedOption.id); } } } diff --git a/src/components/schedule/tabs/tabs.component.html b/src/components/schedule/tabs/tabs.component.html index 06ee020..194d111 100644 --- a/src/components/schedule/tabs/tabs.component.html +++ b/src/components/schedule/tabs/tabs.component.html @@ -2,24 +2,17 @@ (selectedTabChange)="chooseTabs($event)">
- +
- +
- +
diff --git a/src/components/schedule/tabs/tabs.component.ts b/src/components/schedule/tabs/tabs.component.ts index 9b200b7..ce3eeba 100644 --- a/src/components/schedule/tabs/tabs.component.ts +++ b/src/components/schedule/tabs/tabs.component.ts @@ -1,38 +1,31 @@ -import {Component, EventEmitter, Output, ViewChild} from '@angular/core'; -import {HttpClientModule} from "@angular/common/http"; +import {Component, EventEmitter, Output} from '@angular/core'; import {OtherComponent} from "@component/schedule/tabs/other/other.component"; 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 {AsyncPipe, NgIf} from "@angular/common"; import {MatButton} from "@angular/material/button"; 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 {ProfessorComponent} from "@component/schedule/tabs/professor/professor.component"; import {LectureHallComponent} from "@component/schedule/tabs/lecture-hall/lecture-hall.component"; -import {FacultyService} from "@api/v1/faculty.service"; -import {GroupService} from "@api/v1/group.service"; -import {ProfessorService} from "@api/v1/professor.service"; -import {CampusService} from "@api/v1/campus.service"; -import {LectureHallService} from "@api/v1/lectureHall.service"; +import {ScheduleService} from "@api/v1/schedule.service"; +import {ScheduleResponse} from "@api/v1/scheduleResponse"; + +export enum TabsSelect { + Group, + Professor, + LectureHall, + Other +} @Component({ selector: 'app-tabs', standalone: true, imports: [ - HttpClientModule, OtherComponent, MatTabGroup, MatTab, ReactiveFormsModule, - AsyncPipe, - NgIf, MatButton, DataSpinnerComponent, GroupComponent, @@ -41,171 +34,122 @@ import {LectureHallService} from "@api/v1/lectureHall.service"; ], templateUrl: './tabs.component.html', styleUrl: './tabs.component.css', - providers: [FacultyService, GroupService, ProfessorService, CampusService, LectureHallService, DisciplineService ] + providers: [ScheduleService] }) export class TabsComponent { - protected professorsData: ProfessorResponse[] = []; + @Output() eventResult = new EventEmitter<[TabsSelect, number, Observable]>(); - protected faculties: Observable = of([]); - protected groups: Observable = of([]); - private groupsData: Observable = of([]); + constructor(private scheduleApi: ScheduleService) { + } protected campuses: Observable = of([]); protected lectureHalls: Observable = of([]); private lectureHallsData: Observable = 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 facultiesLoaded: boolean | null = false; - protected groupLoaded: boolean | null = false; - protected campusesLoaded: boolean | null = false; - protected lectureHallsLoaded: boolean | null = false; - protected disciplinesLoaded: boolean | null = false; - protected professorsLoaded: boolean | null = false; + protected professorSelected(id: number) { + this.eventResult.emit( + [ + TabsSelect.Professor, + id, + this.scheduleApi.getByProfessor(id) + .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 = new EventEmitter(); - @Output() lectureHallSelected: EventEmitter = new EventEmitter(); - @Output() professorSelected: EventEmitter = new EventEmitter(); - - constructor( - private facultyApi: FacultyService, - private groupApi: GroupService, - private professorApi: ProfessorService, - private campusApi: CampusService, - private lectureHallApi: LectureHallService, - private disciplineApi: DisciplineService) { - this.facultyLoad().then(); + protected lectureHallSelected(id: number) { + this.eventResult.emit( + [ + TabsSelect.LectureHall, + id, + this.scheduleApi.getByLectureHall(id) + .pipe( + map(lh => + lh.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 + })) + ) + ) + ] + ); } protected async chooseTabs(event: MatTabChangeEvent) { 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; - }); } }