refactor: folders and components

This commit is contained in:
2024-05-21 02:34:23 +03:00
parent 77845d3a99
commit afc01c1409
32 changed files with 608 additions and 22 deletions

View File

@ -0,0 +1,54 @@
<mat-accordion>
<mat-expansion-panel expanded>
<mat-expansion-panel-header>
<mat-panel-title>
Факультет
</mat-panel-title>
</mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseFaculty($event)">
@for (faculty of faculties | async; track $index) {
<mat-chip-option [value]="faculty.id" color="accent">
{{ faculty.name }}
</mat-chip-option>
} @empty {
<app-loading-indicator [loading]="facultiesLoaded !== null" (retryFunction)="facultiesLoadRetry.emit()"/>
}
</mat-chip-listbox>
</mat-expansion-panel>
<mat-expansion-panel [disabled]="facultyId === null" #courseNumberPanel>
<mat-expansion-panel-header>
<mat-panel-title>
Курс
</mat-panel-title>
</mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCourseNumber($event)" [formControl]="chipCourse">
@for (course of courseNumbers | async; track $index) {
<mat-chip-option [value]="course" color="accent">
{{ course }}
</mat-chip-option>
} @empty {
<app-loading-indicator [loading]="groupsLoaded !== null"
(retryFunction)="groupsLoadRetry.emit(this.facultyId!)"/>
}
</mat-chip-listbox>
</mat-expansion-panel>
<mat-expansion-panel [disabled]="courseNumber === null" #groupPanel>
<mat-expansion-panel-header>
<mat-panel-title>
Группа
</mat-panel-title>
</mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseGroup($event)" [formControl]="chipGroup">
@for (group of filteredGroups | async; track $index) {
<mat-chip-option [value]="group.id" color="accent">
{{ group.name }}
</mat-chip-option>
} @empty {
<app-loading-indicator [loading]="groupsLoaded !== null"
(retryFunction)="groupsLoadRetry.emit(this.facultyId!)"/>
}
</mat-chip-listbox>
</mat-expansion-panel>
</mat-accordion>

View File

@ -0,0 +1,95 @@
import {Component, EventEmitter, Input, 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 {FacultyResponse} from "@model/facultyResponse";
import {GroupResponse} from "@model/groupResponse";
import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component";
@Component({
selector: 'app-group',
standalone: true,
imports: [
MatExpansionModule,
MatChipsModule,
ReactiveFormsModule,
LoadingIndicatorComponent,
AsyncPipe
],
templateUrl: './group.component.html',
styleUrl: './group.component.css'
})
export class GroupComponent {
protected facultyId: number | null = null;
protected courseNumber: number | null = null;
protected filteredGroups: Observable<GroupResponse[]> = of([]);
protected courseNumbers: Observable<number[]> = of([]);
protected groups: Observable<GroupResponse[]> = of([]);
protected chipCourse: FormControl = new FormControl();
protected chipGroup: FormControl = new FormControl();
@ViewChild('courseNumberPanel') courseNumberPanel!: MatExpansionPanel;
@ViewChild('groupPanel') groupPanel!: MatExpansionPanel;
@Input() faculties: Observable<FacultyResponse[]> = of([]);
@Input() facultiesLoaded: 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[]>) {
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() groupSelected = new EventEmitter<number>();
@Output() facultySelected = new EventEmitter<number>();
protected chooseFaculty(event: MatChipListboxChange) {
this.courseNumber = null;
this.groups = of([]);
this.chipGroup.reset();
this.chipCourse.reset();
if (event.value === undefined || event.value === null) {
this.facultyId = null;
return;
}
this.facultyId = event.value;
this.courseNumberPanel.open();
this.facultySelected.emit(this.facultyId!);
}
protected chooseCourseNumber(event: MatChipListboxChange) {
this.filteredGroups = of([]);
this.chipGroup.reset();
if (event.value === undefined || event.value === null) {
this.courseNumber = null;
return;
}
this.courseNumber = event.value;
this.groupPanel.open();
this.groups.subscribe(data =>
this.filteredGroups = of(data.filter(g => g.courseNumber === this.courseNumber)));
}
protected chooseGroup(event: MatChipListboxChange) {
if (event.value === undefined || event.value === null)
return;
this.groupPanel.close();
this.groupSelected.emit(event.value);
}
}

View File

@ -0,0 +1,35 @@
<mat-accordion>
<mat-expansion-panel expanded>
<mat-expansion-panel-header>
<mat-panel-title>
Кампус
</mat-panel-title>
</mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseCampus($event)">
@for (campus of campuses | async; track $index) {
<mat-chip-option [value]="campus.id" color="accent">
{{ campus.codeName }}
</mat-chip-option>
} @empty {
<app-loading-indicator [loading]="campusesLoaded !== null" (retryFunction)="campusesLoadRetry.emit()"/>
}
</mat-chip-listbox>
</mat-expansion-panel>
<mat-expansion-panel [disabled]="campusId === null" #lecturePanel>
<mat-expansion-panel-header>
<mat-panel-title>
Кабинет
</mat-panel-title>
</mat-expansion-panel-header>
<mat-chip-listbox hideSingleSelectionIndicator (change)="chooseLectureHall($event)" [formControl]="chipLecture">
@for (lectureHall of lectureHalls | async; track $index) {
<mat-chip-option [value]="lectureHall.id" color="accent">
{{ lectureHall.name }}
</mat-chip-option>
} @empty {
<app-loading-indicator [loading]="lectureHallsLoaded !== null" (retryFunction)="lectureHallsLoadRetry.emit()"/>
}
</mat-chip-listbox>
</mat-expansion-panel>
</mat-accordion>

View File

@ -0,0 +1,63 @@
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 {CampusBasicInfoResponse} from "@model/campusBasicInfoResponse";
import {FormControl, ReactiveFormsModule} from "@angular/forms";
import {LectureHallResponse} from "@model/lectureHallResponse";
import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component";
@Component({
selector: 'app-lecture-hall',
standalone: true,
imports: [
MatChipsModule,
MatExpansionModule,
AsyncPipe,
ReactiveFormsModule,
MatAccordion,
LoadingIndicatorComponent
],
templateUrl: './lecture-hall.component.html',
styleUrl: './lecture-hall.component.css'
})
export class LectureHallComponent {
protected campusId: number | null = null;
protected chipLecture: FormControl = new FormControl();
@ViewChild('lecturePanel') lecturePanel!: MatExpansionPanel;
@Input() campuses: Observable<CampusBasicInfoResponse[]> = of([]);
@Input() 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>();
@Output() lectureHallSelected = new EventEmitter<number>();
protected chooseCampus(event: MatChipListboxChange) {
this.chipLecture.reset();
if (event.value === undefined || event.value === null) {
this.campusId = null;
this.lectureHalls = of([]);
return;
}
this.campusId = event.value;
this.lecturePanel.open();
this.campusSelected.emit(this.campusId!);
}
protected chooseLectureHall(event: MatChipListboxChange) {
if (event.value === undefined || event.value === null)
return;
this.lecturePanel.close();
this.lectureHallSelected.emit(event.value);
}
}

View File

@ -0,0 +1,13 @@
.header-menu {
position: sticky;
top: 0;
background-color: var(--mat-menu-container-color);
z-index: 1;
padding-top: 5px;
}
.button-group {
display: flex;
justify-content: space-between;
align-items: center;
}

View File

@ -0,0 +1,45 @@
<!--suppress CssInvalidPropertyValue -->
<button mat-button [matMenuTriggerFor]="menu" #menuTrigger="matMenuTrigger" [id]="idButton">{{ textButton }}</button>
<mat-menu #menu="matMenu" [hasBackdrop]="false" class="menu-options">
<div (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()" style="padding: 0 15px 15px">
<div class="header-menu">
<mat-form-field appearance="outline" color="accent" style="display:flex;">
<input matInput placeholder="Поиск..." [(ngModel)]="searchQuery" [disabled]="data.length === 0">
<button mat-icon-button matSuffix (click)="clearSearchQuery()" [disabled]="data.length === 0">
<mat-icon style="color: var(--mdc-filled-button-label-text-color);">close</mat-icon>
</button>
</mat-form-field>
<div class="button-group">
<mat-checkbox (click)="checkData()" [disabled]="data.length === 0" #chooseCheckbox/>
<button mat-button (click)="clearAll()" [disabled]="data.length === 0">Очистить</button>
</div>
<hr/>
</div>
@if (data.length === 0) {
<app-loading-indicator style="display: flex; justify-content: center;" [loading]="dataLoaded !== null"
(retryFunction)="retryLoadData.emit()"/>
} @else {
<mat-selection-list>
@if (filteredData.value.length !== 0) {
<cdk-virtual-scroll-viewport autosize [minBufferPx]="300" [maxBufferPx]="500"
style="height: 250px; width: 260px; overflow-x: clip;">
<div *cdkVirtualFor="let item of filteredData">
<mat-list-option togglePosition="before" style="height: auto;" [value]="item.id"
[selected]="item.selected"
(click)="checkboxStateChange(item.id)">
<div style="text-wrap: balance;">{{ item.name }}</div>
</mat-list-option>
<mat-divider style="margin: 10px 0;"/>
</div>
</cdk-virtual-scroll-viewport>
} @else {
<div style="color: var(--mdc-text-button-label-text-color);">
Нет подходящих элементов
</div>
}
</mat-selection-list>
}
</div>
</mat-menu>

View File

@ -0,0 +1,141 @@
import {Component, EventEmitter, HostListener, Input, Output, ViewChild} from '@angular/core';
import {MatMenu, MatMenuTrigger} from "@angular/material/menu";
import {MatCheckbox} from "@angular/material/checkbox";
import {BehaviorSubject} from "rxjs";
import {MatButton, MatIconButton} from "@angular/material/button";
import {MatFormField, MatSuffix} from "@angular/material/form-field";
import {MatIcon} from "@angular/material/icon";
import {FormsModule} from "@angular/forms";
import {MatListOption, MatSelectionList} from "@angular/material/list";
import {ScrollingModule} from "@angular/cdk/scrolling";
import {ScrollingModule as ExperimentalScrollingModule} from '@angular/cdk-experimental/scrolling';
import {MatDivider} from "@angular/material/divider";
import {MatInput} from "@angular/material/input";
import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component";
export interface SelectData {
id: number,
name: string,
selected: boolean
}
@Component({
selector: 'app-other',
standalone: true,
imports: [
MatMenuTrigger,
MatButton,
MatMenu,
MatFormField,
MatIcon,
FormsModule,
MatCheckbox,
MatSelectionList,
MatListOption,
MatDivider,
MatIconButton,
MatInput,
MatSuffix,
ScrollingModule,
ExperimentalScrollingModule,
LoadingIndicatorComponent
],
templateUrl: './other.component.html',
styleUrl: './other.component.css'
})
export class OtherComponent {
private _searchQuery: string = '';
protected filteredData: BehaviorSubject<SelectData[]> = new BehaviorSubject<SelectData[]>([]);
protected data: SelectData[] = [];
@Input() idButton!: string;
@Input() textButton!: string;
@ViewChild('menuTrigger') menuTrigger!: MatMenuTrigger;
@ViewChild('chooseCheckbox') chooseCheckbox!: MatCheckbox;
@Input() dataLoaded: boolean | null = false;
@Output() retryLoadData: EventEmitter<void> = new EventEmitter<void>();
get selectedIds(): number[] {
return this.data.filter(x => x.selected).map(x => x.id);
}
set Data(data: SelectData[]) {
this.data = data;
this.data.forEach(x => x.selected = false);
this.filteredData.next(this.data);
}
protected get searchQuery(): string {
return this._searchQuery;
}
private updateCheckBox() {
this.chooseCheckbox.checked = this.data.every(x => x.selected);
this.chooseCheckbox.indeterminate = this.data.some(x => x.selected) && !this.chooseCheckbox.checked;
}
protected set searchQuery(value: string) {
this._searchQuery = value;
this.updateFilteredData();
}
protected updateFilteredData(): void {
this.filteredData.next(this.data.filter(x =>
x.name.toLowerCase().includes(this.searchQuery.toLowerCase())
));
}
protected clearSearchQuery(): void {
this.searchQuery = '';
}
protected clearAll(): void {
this.data.forEach(x => x.selected = false);
if (this.searchQuery !== '') {
const updatedData = this.filteredData.value.map(x => {
return {...x, selected: false};
});
this.filteredData.next(updatedData);
} else
this.updateFilteredData();
this.updateCheckBox();
}
protected checkData() {
const check: boolean = this.filteredData.value.some(x => !x.selected) && !this.filteredData.value.every(x => x.selected);
const updatedData = this.filteredData.value.map(data => {
this.data.find(x => x.id === data.id)!.selected = check;
return {...data, selected: check};
});
this.filteredData.next(updatedData);
this.updateCheckBox();
}
protected checkboxStateChange(item: number) {
const data = this.data.find(x => x.id === item)!;
data.selected = !data.selected;
const updatedData = this.filteredData.value;
updatedData.find(x => x.id === item)!.selected = data.selected;
this.filteredData.next(updatedData);
this.updateCheckBox();
}
@HostListener('document:click', ['$event'])
private onClick(event: MouseEvent): void {
if (this.menuTrigger && this.menuTrigger.menuOpen
&& (event.target as HTMLElement).closest('.mat-menu-content') === null
&& !this.isInsideMenuButton(event.target as HTMLElement, this.idButton)) {
this.menuTrigger.closeMenu();
}
}
private isInsideMenuButton(target: HTMLElement, id: string): boolean {
let parentElement: HTMLElement | null = target.parentElement;
return (parentElement !== null && parentElement.id === id);
}
}

View File

@ -0,0 +1,5 @@
.search-content {
display: flex;
align-items: center;
justify-content: center;
}

View File

@ -0,0 +1,18 @@
<div class="search-content">
@if (professors.length === 0) {
<app-loading-indicator [loading]="professorsLoaded !== null" (retryFunction)="professorsLoadRetry.emit()"/>
} @else {
<mat-form-field color="accent" style="width: 100%;">
<input type="text" placeholder="Поиск..." matInput [formControl]="professorControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="onOptionSelected($event)"
[autoActiveFirstOption]="false" [hideSingleSelectionIndicator]="true">
@for (option of filteredProfessors | async; track option) {
<mat-option [value]="option.id">
{{ option.name }}
</mat-option>
}
</mat-autocomplete>
</mat-form-field>
}
</div>

View File

@ -0,0 +1,59 @@
import {Component, EventEmitter, Input, OnInit, Output} from "@angular/core";
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 {ProfessorResponse} from "@model/professorResponse";
import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loading-indicator.component";
@Component({
selector: 'app-professor',
standalone: true,
imports: [
MatAutocompleteModule,
MatFormField,
AsyncPipe,
ReactiveFormsModule,
MatInput,
LoadingIndicatorComponent
],
templateUrl: './professor.component.html',
styleUrl: './professor.component.css'
})
export class ProfessorComponent implements OnInit {
protected professorControl = new FormControl();
protected filteredProfessors!: Observable<ProfessorResponse[]>;
@Input() professors: ProfessorResponse[] = [];
@Output() professorSelected = new EventEmitter<number>();
@Input() professorsLoaded: boolean | null = false;
@Output() professorsLoadRetry: EventEmitter<void> = new EventEmitter<void>();
ngOnInit(): void {
this.filteredProfessors = this.professorControl.valueChanges.pipe(
startWith(''),
map(value => this._filterProfessors(value))
);
}
private _filterProfessors(value: string | number): ProfessorResponse[] {
if (typeof value === 'string') {
if (value === '') return [];
const filterValue = value.toLowerCase();
return this.professors.filter(teacher => teacher.name.toLowerCase().includes(filterValue));
} else {
const selectedTeacher = this.professors.find(teacher => teacher.id === value);
return selectedTeacher ? [selectedTeacher] : [];
}
}
protected onOptionSelected(event: MatAutocompleteSelectedEvent) {
const selectedOption = this.professors.find(teacher => teacher.id === event.option.value);
if (selectedOption) {
this.professorControl.setValue(selectedOption.name);
this.professorSelected.emit(selectedOption.id);
}
}
}

View File

@ -0,0 +1,14 @@
.padding-content div {
padding: 30px 15px;
}
.margin-other-button {
display: flex;
align-items: stretch;
justify-content: space-around;
flex-wrap: wrap;
}
.margin-other-button app-schedule-tabs-other {
margin-right: 15px;
}

View File

@ -0,0 +1,36 @@
<mat-tab-group dynamicHeight mat-stretch-tabs="false" mat-align-tabs="start" color="accent" class="padding-content"
(selectedTabChange)="chooseTabs($event)">
<mat-tab label="Группа">
<div>
<app-group (groupSelected)="groupSelected.emit($event)" (facultySelected)="groupLoad($event)"
[setGroups]="groups" [faculties]="faculties" [facultiesLoaded]="facultiesLoaded"
[groupsLoaded]="groupLoaded" (groupsLoadRetry)="groupLoad($event)"
(facultiesLoadRetry)="facultyLoad()"/>
</div>
</mat-tab>
<mat-tab label="Преподаватель">
<div>
<app-professor (professorSelected)="professorSelected.emit($event)" [professors]="professorsData" [professorsLoaded]="professorsLoaded" (professorsLoadRetry)="professorsLoad()"/>
</div>
</mat-tab>
<mat-tab label="Кабинет">
<div>
<app-lecture-hall (lectureHallSelected)="lectureHallSelected.emit($event)" [campuses]="campuses"
(campusSelected)="lectureHallLoad($event)" [lectureHalls]="lectureHalls"
[campusesLoaded]="campusesLoaded" [lectureHallsLoaded]="lectureHallsLoaded"
(campusesLoadRetry)="campusLoad()"
(lectureHallsLoadRetry)="lectureHallLoad($event)"/>
</div>
</mat-tab>
<mat-tab label="Другое">
<div class="margin-other-button">
<app-other idButton="disciplines-button" textButton="Дисциплины" #discipline [dataLoaded]="disciplinesLoaded" (retryLoadData)="loadDisciplines()"/>
<app-other idButton="lecture-button" textButton="Кабинеты" #lecture [dataLoaded]="campusesLoaded && lectureHallsLoaded" (retryLoadData)="loadLectureHalls()"/>
<app-other idButton="group-button" textButton="Группы" #group [dataLoaded]="facultiesLoaded && groupLoaded" (retryLoadData)="loadGroups()"/>
<app-other idButton="professor-button" textButton="Профессоры" #professor [dataLoaded]="professorsLoaded" (retryLoadData)="professorsLoad()"/>
<section>
<button mat-flat-button (click)="onClickNagmi()">Отфильтровать</button>
</section>
</div>
</mat-tab>
</mat-tab-group>

View File

@ -0,0 +1,277 @@
import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
import {HttpClientModule} from "@angular/common/http";
import {ApiService} from '@service/api.service';
import {OtherComponent} from "@component/schedule/tabs/other/other.component";
import {MatTab, MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs";
import {
ProfessorComponent
} from "@component/schedule/tabs/professor/professor.component";
import {GroupComponent} from "@component/schedule/tabs/group/group.component";
import {
LectureHallComponent
} from "@component/schedule/tabs/lecture-hall/lecture-hall.component";
import {ProfessorResponse} from "@model/professorResponse";
import {catchError, map, Observable, of, switchMap, tap} from "rxjs";
import {GroupResponse} from "@model/groupResponse";
import {FacultyResponse} from "@model/facultyResponse";
import {CampusBasicInfoResponse} from "@model/campusBasicInfoResponse";
import {LectureHallResponse} from "@model/lectureHallResponse";
import {ReactiveFormsModule} from "@angular/forms";
import {AsyncPipe, NgIf} from "@angular/common";
import {DisciplineResponse} from "@model/disciplineResponse";
import {MatButton} from "@angular/material/button";
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
@Component({
selector: 'app-tabs',
standalone: true,
imports: [
HttpClientModule,
OtherComponent,
MatTabGroup,
MatTab,
ProfessorComponent,
GroupComponent,
LectureHallComponent,
ReactiveFormsModule,
AsyncPipe,
NgIf,
MatButton,
DataSpinnerComponent
],
templateUrl: './tabs.component.html',
styleUrl: './tabs.component.css'
})
export class TabsComponent {
protected professorsData: ProfessorResponse[] = [];
protected faculties: Observable<FacultyResponse[]> = of([]);
protected groups: Observable<GroupResponse[]> = of([]);
private groupsData: Observable<GroupResponse[]> = of([]);
protected campuses: Observable<CampusBasicInfoResponse[]> = of([]);
protected lectureHalls: Observable<LectureHallResponse[]> = of([]);
private lectureHallsData: Observable<LectureHallResponse[]> = of([]);
// 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;
@Output() groupSelected: EventEmitter<number> = new EventEmitter<number>();
@Output() lectureHallSelected: EventEmitter<number> = new EventEmitter<number>();
@Output() professorSelected: EventEmitter<number> = new EventEmitter<number>();
constructor(private api: ApiService) {
this.facultyLoad().then();
}
protected async chooseTabs(event: MatTabChangeEvent) {
console.log(event);
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.api.get<FacultyResponse[]>("Faculty/Get").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.api.get<GroupResponse[]>("Group/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.api.get<ProfessorResponse[]>("Professor/Get").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.api.get<CampusBasicInfoResponse[]>("Campus/Get").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.api.get<LectureHallResponse[]>("LectureHall/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.api.get<LectureHallResponse[]>("LectureHall/Get");
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;
});
}
}
protected async loadDisciplines() {
if (!this.disciplinesLoaded) {
this.api.get<DisciplineResponse[]>("Discipline/Get").pipe(
catchError((error) => {
this.disciplinesLoaded = null;
throw error;
})).subscribe(data => {
this.disciplineEx.Data = data.map(x =>
({
id: x.id,
name: x.name,
selected: false
}));
this.disciplinesLoaded = true;
});
}
}
protected async loadGroups() {
if (!this.facultiesLoaded)
await this.facultyLoad();
if (!this.groupLoaded) {
this.groupsData = this.api.get<GroupResponse[]>("Group/Get");
this.groupsData.pipe(
switchMap(groups => this.faculties.pipe(
map(campuses => {
return groups.map(x => {
const faculties = campuses.find(c => c.id === x.facultyId);
const name = faculties ? faculties.name : '';
return {
id: x.id,
name: `${x.name} (${name})`,
selected: false
};
});
})
))
).subscribe(data => {
this.groupEx.Data = data;
this.groupLoaded = true;
});
}
}
protected async extensionLoad() {
// Lecture Hall
await this.loadLectureHalls();
// Disciplines
await this.loadDisciplines();
// Groups
await this.loadGroups();
// Professors
if (this.professorsData.length === 0)
this.professorsLoad();
}
@ViewChild('discipline') disciplineEx!: OtherComponent;
@ViewChild('lecture') lectureHallEx!: OtherComponent;
@ViewChild('group') groupEx!: OtherComponent;
@ViewChild('professor') professorEx!: OtherComponent;
onClickNagmi() {
console.log('huy = ' + this.disciplineEx.selectedIds);
console.log('huy2 = ' + this.lectureHallEx.selectedIds);
console.log('huy3 = ' + this.groupEx.selectedIds);
console.log('huy3 = ' + this.professorEx.selectedIds);
}
}