From 79393a39c3b174a2bab2738d796dfa1c878184ff Mon Sep 17 00:00:00 2001 From: Polianin Nikita Date: Wed, 28 Aug 2024 03:52:47 +0300 Subject: [PATCH] feat: add parameters as navigation Now there is automatic navigation on the inserted url and on localStorage --- .../schedule/tabs/group/group.component.ts | 47 ++++++------ src/components/schedule/tabs/ischedule-tab.ts | 2 + .../lecture-hall/lecture-hall.component.ts | 37 +++++----- .../tabs/professor/professor.component.ts | 25 ++++--- .../schedule/tabs/tabs.component.ts | 14 +++- src/pages/schedule/schedule.component.ts | 15 +++- src/services/tab-storage.service.ts | 71 +++++++++++++------ 7 files changed, 131 insertions(+), 80 deletions(-) diff --git a/src/components/schedule/tabs/group/group.component.ts b/src/components/schedule/tabs/group/group.component.ts index 901a8bf..d75a02f 100644 --- a/src/components/schedule/tabs/group/group.component.ts +++ b/src/components/schedule/tabs/group/group.component.ts @@ -9,7 +9,7 @@ import {FacultyResponse} from "@api/v1/facultyResponse"; import {FacultyService} from "@api/v1/faculty.service"; import {GroupService} from "@api/v1/group.service"; import {IScheduleTab} from "@component/schedule/tabs/ischedule-tab"; -import {TabSelect, TabSelectType, TabStorageService} from "@service/tab-storage.service"; +import {TabSelect, TabSelectData, TabSelectType, TabStorageService} from "@service/tab-storage.service"; @Component({ selector: 'app-group', @@ -45,20 +45,17 @@ export class GroupComponent implements IScheduleTab { @ViewChild('courseChip') courseChip!: MatChipListbox; @ViewChild('groupChip') groupChip!: MatChipListbox; - private readonly selected: TabSelect[] | null = null; - @ViewChild('facultyIndicator') facultyIndicator!: LoadingIndicatorComponent; @ViewChild('courseIndicator') courseIndicator!: LoadingIndicatorComponent; @ViewChild('groupIndicator') groupIndicator!: LoadingIndicatorComponent; @Output() eventResult = new EventEmitter(); - constructor(private facultyApi: FacultyService, private groupApi: GroupService) { - let selectedData = TabStorageService.selected; - if (selectedData !== null && selectedData.selected !== null) { - if (selectedData.type === TabSelectType.group) - this.selected = selectedData.selected; - } + constructor(private facultyApi: FacultyService, private groupApi: GroupService, private tabStorage: TabStorageService) { + } + + existParams(data: TabSelectData): boolean { + return data.selected['group'] !== undefined || data.selected['course'] !== undefined || data.selected['faculty'] !== undefined; } protected loadFaculties() { @@ -70,11 +67,12 @@ export class GroupComponent implements IScheduleTab { .subscribe(data => { this.faculties = data; - if (this.selected !== null && this.selected.length >= 1) { - let selectedFaculty = data.find(x => x.id === this.selected![0].index); + let selected = TabStorageService.selected?.selected['faculty']; + if (selected) { + let selectedFaculty = data.find(x => x.id === selected.index); - if (selectedFaculty === undefined || selectedFaculty.name !== this.selected[0].name) - selectedFaculty = data.find(x => x.name === this.selected![0].name); + if (selectedFaculty === undefined || selectedFaculty.name !== selected.name) + selectedFaculty = data.find(x => x.name === selected.name); if (selectedFaculty !== undefined) { TabStorageService.trySelectChip(selectedFaculty.id, this.facultyChip); @@ -104,8 +102,12 @@ export class GroupComponent implements IScheduleTab { .sort((a, b) => a - b)) ); - if (this.selected !== null && this.selected.length >= 2) { - let selectedCourse = this.courseNumbers.find(x => x === this.selected![1].index); + let selected = TabStorageService.selected?.selected['course']; + if (selected) { + let selectedCourse = this.courseNumbers.find(x => x === selected.index); + + if (selectedCourse === undefined) + selectedCourse = this.courseNumbers.find(x => x.toString() === selected.name); if (selectedCourse !== undefined) { TabStorageService.trySelectChip(selectedCourse, this.courseChip); @@ -113,11 +115,12 @@ export class GroupComponent implements IScheduleTab { } } - if (this.selected !== null && this.selected.length >= 3) { - let selectedGroup = data.find(x => x.id === this.selected![2].index); + let selectedGroupStorage = TabStorageService.selected?.selected['group']; + if (selectedGroupStorage) { + let selectedGroup = data.find(x => x.id === selectedGroupStorage.index); - if (selectedGroup === undefined || selectedGroup.name !== this.selected[2].name) - selectedGroup = data.find(x => x.name === this.selected![2].name); + if (selectedGroup === undefined || selectedGroup.name !== selectedGroupStorage.name) + selectedGroup = data.find(x => x.name === selectedGroupStorage.name); if (selectedGroup !== undefined) { TabStorageService.trySelectChip(selectedGroup.id, this.groupChip); @@ -144,7 +147,7 @@ export class GroupComponent implements IScheduleTab { return; } - TabStorageService.select(new TabSelect(index, this.faculties!.find(x => x.id === index)?.name ?? ''), TabSelectType.group, 0); + this.tabStorage.select(new TabSelect(index, this.faculties!.find(x => x.id === index)?.name ?? ''), TabSelectType.group, 'faculty'); this.facultyId = index; this.courseNumberPanel.open(); @@ -161,7 +164,7 @@ export class GroupComponent implements IScheduleTab { return; } - TabStorageService.select(new TabSelect(course, course.toString()), TabSelectType.group, 1); + this.tabStorage.select(new TabSelect(course, course.toString()), TabSelectType.group, 'course'); this.courseNumber = course; this.groupPanel.open(); @@ -172,7 +175,7 @@ export class GroupComponent implements IScheduleTab { if (index === undefined) return; - TabStorageService.select(new TabSelect(index, this.groups!.find(x => x.id == index)?.name ?? ''), TabSelectType.group, 2); + this.tabStorage.select(new TabSelect(index, this.groups!.find(x => x.id == index)?.name ?? ''), TabSelectType.group, 'group'); this.groupPanel.close(); this.eventResult.emit(index); diff --git a/src/components/schedule/tabs/ischedule-tab.ts b/src/components/schedule/tabs/ischedule-tab.ts index 987aa92..7265cf6 100644 --- a/src/components/schedule/tabs/ischedule-tab.ts +++ b/src/components/schedule/tabs/ischedule-tab.ts @@ -1,6 +1,8 @@ import {EventEmitter} from "@angular/core"; +import {TabSelectData} from "@service/tab-storage.service"; export interface IScheduleTab { load(): void; eventResult: EventEmitter; + existParams(data: TabSelectData): boolean; } 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 29d94dc..a0faf3c 100644 --- a/src/components/schedule/tabs/lecture-hall/lecture-hall.component.ts +++ b/src/components/schedule/tabs/lecture-hall/lecture-hall.component.ts @@ -10,7 +10,7 @@ import {LectureHallResponse} from "@api/v1/lectureHallResponse"; import {CampusService} from "@api/v1/campus.service"; import {LectureHallService} from "@api/v1/lectureHall.service"; import {IScheduleTab} from "@component/schedule/tabs/ischedule-tab"; -import {TabSelect, TabSelectType, TabStorageService} from "@service/tab-storage.service"; +import {TabSelect, TabSelectData, TabSelectType, TabStorageService} from "@service/tab-storage.service"; @Component({ selector: 'app-lecture-hall', @@ -45,14 +45,12 @@ export class LectureHallComponent implements IScheduleTab { @ViewChild('lectureChip') lectureChip!: MatChipListbox; private lectureHalls: LectureHallResponse[] | null = null; - private readonly selected: TabSelect[] | null = null; - constructor(private campusApi: CampusService, private lectureHallApi: LectureHallService) { - let selectedData = TabStorageService.selected; - if (selectedData !== null && selectedData.selected !== null) { - if (selectedData.type === TabSelectType.lecture) - this.selected = selectedData.selected; - } + constructor(private campusApi: CampusService, private lectureHallApi: LectureHallService, private tabStorage: TabStorageService) { + } + + existParams(data: TabSelectData): boolean { + return data.selected['campus'] !== undefined || data.selected['lecture'] !== undefined; } protected loadCampuses() { @@ -64,11 +62,12 @@ export class LectureHallComponent implements IScheduleTab { .subscribe(data => { this.campuses = data; - if (this.selected !== null && this.selected.length >= 1) { - let selectedCampus = data.find(x => x.id === this.selected![0].index); + let selected = TabStorageService.selected?.selected['campus']; + if (selected) { + let selectedCampus = data.find(x => x.id === selected.index); - if (selectedCampus === undefined || selectedCampus.codeName !== this.selected![0].name) - selectedCampus = data.find(x => x.codeName === this.selected![0].name); + if (selectedCampus === undefined || selectedCampus.codeName !== selected.name) + selectedCampus = data.find(x => x.codeName === selected.name); if (selectedCampus !== undefined) { TabStorageService.trySelectChip(selectedCampus.id, this.campusChip); @@ -85,7 +84,7 @@ export class LectureHallComponent implements IScheduleTab { protected onCampusSelected(index: number) { this.formLectureHalls.reset(); - TabStorageService.select(new TabSelect(index, this.campuses!.find(x => x.id === index)?.codeName ?? ''), TabSelectType.lecture, 0); + this.tabStorage.select(new TabSelect(index, this.campuses!.find(x => x.id === index)?.codeName ?? ''), TabSelectType.lecture, 'campus'); if (index === undefined) { this.campusId = null; @@ -111,11 +110,13 @@ export class LectureHallComponent implements IScheduleTab { .subscribe(data => { this.lectureHalls = data; this.filteringLectureHalls(); - if (this.selected !== null && this.selected.length >= 2) { - let selectedLecture = data.find(x => x.id === this.selected![1].index); - if (selectedLecture === undefined || selectedLecture.name !== this.selected![1].name) - selectedLecture = data.find(x => x.name === this.selected![1].name); + let selected = TabStorageService.selected?.selected['lecture']; + if (selected) { + let selectedLecture = data.find(x => x.id === selected.index); + + if (selectedLecture === undefined || selectedLecture.name !== selected.name) + selectedLecture = data.find(x => x.name === selected.name); if (selectedLecture !== undefined) { TabStorageService.trySelectChip(selectedLecture.id, this.lectureChip); @@ -129,7 +130,7 @@ export class LectureHallComponent implements IScheduleTab { if (index === undefined) return; - TabStorageService.select(new TabSelect(index, this.lectureHallsFiltered!.find(x => x.id === index)?.name ?? ''), TabSelectType.lecture, 1); + this.tabStorage.select(new TabSelect(index, this.lectureHallsFiltered!.find(x => x.id === index)?.name ?? ''), TabSelectType.lecture, 'lecture'); this.lecturePanel.close(); this.eventResult.emit(index); diff --git a/src/components/schedule/tabs/professor/professor.component.ts b/src/components/schedule/tabs/professor/professor.component.ts index d5a7961..5b8c5b3 100644 --- a/src/components/schedule/tabs/professor/professor.component.ts +++ b/src/components/schedule/tabs/professor/professor.component.ts @@ -8,7 +8,7 @@ import {LoadingIndicatorComponent} from "@component/common/loading-indicator/loa import {ProfessorResponse} from "@api/v1/professorResponse"; import {ProfessorService} from "@api/v1/professor.service"; import {IScheduleTab} from "@component/schedule/tabs/ischedule-tab"; -import {TabSelect, TabSelectType, TabStorageService} from "@service/tab-storage.service"; +import {TabSelect, TabSelectData, TabSelectType, TabStorageService} from "@service/tab-storage.service"; @Component({ selector: 'app-professor', @@ -30,18 +30,16 @@ export class ProfessorComponent implements OnInit, IScheduleTab { protected filteredProfessors!: Observable; protected professors: ProfessorResponse[] | null = null; - private readonly selected: TabSelect[] | null = null; @ViewChild('professorIndicator') professorIndicator!: LoadingIndicatorComponent; @Output() eventResult = new EventEmitter(); - constructor(private api: ProfessorService) { - let selectedData = TabStorageService.selected; - if (selectedData !== null && selectedData.selected !== null) { - if (selectedData.type === TabSelectType.professor) - this.selected = selectedData.selected; - } + constructor(private api: ProfessorService, private tabStorage: TabStorageService) { + } + + existParams(data: TabSelectData): boolean { + return data.selected['professor'] !== undefined; } protected loadProfessors() { @@ -54,11 +52,12 @@ export class ProfessorComponent implements OnInit, IScheduleTab { .subscribe(data => { this.professors = data; - if (this.selected !== null && this.selected.length >= 1) { - let selectedProfessor = data.find(x => x.id === this.selected![0].index); + let selected = TabStorageService.selected?.selected['professor']; + if (selected) { + let selectedProfessor = data.find(x => x.id === selected.index); - if (selectedProfessor === undefined || selectedProfessor.name !== this.selected[0].name) - selectedProfessor = data.find(x => x.name === this.selected![0].name); + if (selectedProfessor === undefined || selectedProfessor.name !== selected.name) + selectedProfessor = data.find(x => x.name === selected.name); if (selectedProfessor !== undefined) this.onOptionSelected(selectedProfessor.id); @@ -96,7 +95,7 @@ export class ProfessorComponent implements OnInit, IScheduleTab { this.professorControl.setValue(selectedOption.name); this.eventResult.emit(selectedOption.id); - TabStorageService.select(new TabSelect(selectedOption.id, selectedOption.name), TabSelectType.professor, 0); + this.tabStorage.select(new TabSelect(selectedOption.id, selectedOption.name), TabSelectType.professor, 'professor'); } } diff --git a/src/components/schedule/tabs/tabs.component.ts b/src/components/schedule/tabs/tabs.component.ts index 39a32c8..0ba069a 100644 --- a/src/components/schedule/tabs/tabs.component.ts +++ b/src/components/schedule/tabs/tabs.component.ts @@ -61,8 +61,18 @@ export class TabsComponent implements AfterViewInit { let selected = TabStorageService.selected; let index = 0; - if (selected !== null) - index = selected.type; + + if (selected !== null) { + if (selected.type === null) { + if (this.groupTab.existParams(selected)) + index = 0; + else if (this.professorTab.existParams(selected)) + index = 1; + else if (this.lectureHallTab.existParams(selected)) + index = 2; + } else + index = selected.type; + } if (index === null || index === 0) this.chooseTabs(0).then(); diff --git a/src/pages/schedule/schedule.component.ts b/src/pages/schedule/schedule.component.ts index 64125c1..57c74e3 100644 --- a/src/pages/schedule/schedule.component.ts +++ b/src/pages/schedule/schedule.component.ts @@ -1,4 +1,4 @@ -import {Component, LOCALE_ID, ViewChild} from '@angular/core'; +import {Component, LOCALE_ID, OnInit, ViewChild} from '@angular/core'; import {TableComponent} from "@component/schedule/table/table.component"; import {MatFormField, MatInput} from "@angular/material/input"; import {MatButton} from "@angular/material/button"; @@ -13,6 +13,8 @@ import {ScheduleService} from "@api/v1/schedule.service"; import {ScheduleResponse} from "@api/v1/scheduleResponse"; import {PeriodTimes} from "@model/pairPeriodTime"; import {MatCheckbox} from "@angular/material/checkbox"; +import {ActivatedRoute} from "@angular/router"; +import {TabStorageService} from "@service/tab-storage.service"; @Component({ selector: 'app-schedule', @@ -37,7 +39,7 @@ import {MatCheckbox} from "@angular/material/checkbox"; ] }) -export class ScheduleComponent { +export class ScheduleComponent implements OnInit { protected startWeek: Date; protected data: ScheduleResponse[] = []; protected startTerm: Date; @@ -47,7 +49,11 @@ export class ScheduleComponent { @ViewChild('tableHeader') childComponent!: TableHeaderComponent; - constructor(api: ScheduleService) { + constructor(api: ScheduleService, route: ActivatedRoute) { + route.queryParams.subscribe(params => { + TabStorageService.selectDataFromQuery(params); + }); + this.startTerm = new Date(1, 1, 1); this.startWeek = new Date(1, 1, 1); @@ -65,6 +71,9 @@ export class ScheduleComponent { }); } + ngOnInit(): void { + } + protected result(data: [TabsSelect, number, Observable]) { this.isLoadTable = true; data[2] diff --git a/src/services/tab-storage.service.ts b/src/services/tab-storage.service.ts index a590294..db6fd1c 100644 --- a/src/services/tab-storage.service.ts +++ b/src/services/tab-storage.service.ts @@ -1,5 +1,7 @@ import {MatChipListbox} from "@angular/material/chips"; import {Injectable} from "@angular/core"; +import {Params, Router} from "@angular/router"; +import {Location} from '@angular/common'; export class TabSelect { public index: number; @@ -19,8 +21,8 @@ export enum TabSelectType { } export interface TabSelectData { - selected: TabSelect[] | null; - type: TabSelectType; + selected: { [key: string]: TabSelect }; + type: TabSelectType | null; } @Injectable({ @@ -29,6 +31,9 @@ export interface TabSelectData { export class TabStorageService { private static dataName = 'tabSelectedData'; + constructor(private router: Router, private location: Location) { + } + public static trySelectChip(index: number, chip: MatChipListbox, tryCount: number = 0) { setTimeout(() => { if (chip?._chips !== undefined && chip._chips.length !== 0) { @@ -47,32 +52,54 @@ export class TabStorageService { }, 100); } - public static select(selected: TabSelect, type: TabSelectType, index: number) { - let selectedData = this.selected; + private resetIfNeed(type: TabSelectType) { + let selectedData = TabStorageService.selected; - if (selectedData === null) - selectedData = {} as TabSelectData; + if (selectedData === null || selectedData?.type === null) + return; - if (selectedData.type !== type || selectedData.selected === null || selectedData.selected.length === 0) { - if (index !== 0) - return; - else - selectedData.selected = [selected]; - } else { - if (selectedData.selected.length < index) - return; - - if (selectedData.selected.length - 1 === index) - selectedData.selected[index] = selected; - else if (selectedData.selected.length > index + 1) - selectedData.selected = selectedData.selected.slice(0, index + 1); - else - selectedData.selected.push(selected); + if (selectedData.type !== type) { + localStorage.removeItem(TabStorageService.dataName); + const currentUrl = this.router.url.split('?')[0]; + this.location.replaceState(currentUrl); } + } + public select(selected: TabSelect, type: TabSelectType, navigateName: string) { + this.resetIfNeed(type); + let selectedData = TabStorageService.selected; + + if (selectedData === null || !selectedData.selected) + selectedData = {selected: {}} as TabSelectData; + + selectedData.selected[navigateName] = selected; selectedData.type = type; - localStorage.setItem(this.dataName, JSON.stringify(selectedData)); + localStorage.setItem(TabStorageService.dataName, JSON.stringify(selectedData)); + + const currentUrl = this.router.url.split('?')[0]; + + const queryParam = new URLSearchParams(); + for (let select in selectedData.selected) + queryParam.set(select, selectedData.selected[select].name); + + this.location.replaceState(currentUrl, queryParam.toString()); + } + + public static selectDataFromQuery(query: Params) { + if (Object.keys(query).length === 0) + return; + + let selectedData = {selected: {}} as TabSelectData; + selectedData.type = null; + + for (let select in query) { + selectedData.selected[select] = {} as TabSelect; + selectedData.selected[select].name = query[select]; + selectedData.selected[select].index = -1; + } + + localStorage.setItem(TabStorageService.dataName, JSON.stringify(selectedData)); } public static get selected(): TabSelectData | null {