diff --git a/uniplanWeb/src/app/core/interfaces/major-option-elm.ts b/uniplanWeb/src/app/core/interfaces/major-option-elm.ts new file mode 100644 index 0000000..e8465f9 --- /dev/null +++ b/uniplanWeb/src/app/core/interfaces/major-option-elm.ts @@ -0,0 +1,5 @@ +export interface MajorOptionElm { + id: string; + facultyId: string; + majorName: string; +} diff --git a/uniplanWeb/src/app/core/shared/add-button/add-button.ts b/uniplanWeb/src/app/core/shared/add-button/add-button.ts index 1e299ef..133c6dd 100644 --- a/uniplanWeb/src/app/core/shared/add-button/add-button.ts +++ b/uniplanWeb/src/app/core/shared/add-button/add-button.ts @@ -13,7 +13,7 @@ import { TranslatePipe } from '@ngx-translate/core'; export class AddButton { @Output() addClicked = new EventEmitter(); - onClick(): void { + public onClick(): void { this.addClicked.emit(); } } diff --git a/uniplanWeb/src/app/core/shared/add-form/add-form.ts b/uniplanWeb/src/app/core/shared/add-form/add-form.ts index de8e117..7bf4044 100644 --- a/uniplanWeb/src/app/core/shared/add-form/add-form.ts +++ b/uniplanWeb/src/app/core/shared/add-form/add-form.ts @@ -13,7 +13,7 @@ import { TranslatePipe } from '@ngx-translate/core'; imports: [MatDialogModule, FormsModule, MatInputModule, TranslatePipe], }) export class AddForm { - @Input() title: string = ''; + @Input() public title: string = ''; - @Output() saveClicked = new EventEmitter(); + @Output() public readonly saveClicked :EventEmitter = new EventEmitter(); } diff --git a/uniplanWeb/src/app/core/shared/delete-form/delete-form.ts b/uniplanWeb/src/app/core/shared/delete-form/delete-form.ts index a81695a..7daceaa 100644 --- a/uniplanWeb/src/app/core/shared/delete-form/delete-form.ts +++ b/uniplanWeb/src/app/core/shared/delete-form/delete-form.ts @@ -12,7 +12,7 @@ import { TranslatePipe } from '@ngx-translate/core'; imports: [MatDialogModule, FormsModule, MatInputModule, TranslatePipe], }) export class DeleteForm { - @Input() title: string = ''; + @Input() public title: string = ''; - @Output() deleteClicked = new EventEmitter(); + @Output() public readonly deleteClicked:EventEmitter = new EventEmitter(); } diff --git a/uniplanWeb/src/app/core/shared/edit-form/edit-form.ts b/uniplanWeb/src/app/core/shared/edit-form/edit-form.ts index f560f97..1363b50 100644 --- a/uniplanWeb/src/app/core/shared/edit-form/edit-form.ts +++ b/uniplanWeb/src/app/core/shared/edit-form/edit-form.ts @@ -12,7 +12,7 @@ import { TranslatePipe } from '@ngx-translate/core'; }) export class EditForm { - @Input() title: string = ''; + @Input() public title: string = ''; - @Output() saveClicked = new EventEmitter(); + @Output() public readonly saveClicked:EventEmitter = new EventEmitter(); } diff --git a/uniplanWeb/src/app/core/shared/filters-form/filters-form.ts b/uniplanWeb/src/app/core/shared/filters-form/filters-form.ts index a78b851..2df1ad3 100644 --- a/uniplanWeb/src/app/core/shared/filters-form/filters-form.ts +++ b/uniplanWeb/src/app/core/shared/filters-form/filters-form.ts @@ -14,20 +14,20 @@ import { TranslatePipe } from '@ngx-translate/core'; imports: [MatFormFieldModule, MatSelectModule, MatOptionModule, TranslatePipe], }) export class FiltersForm { - @Input() label = ''; + @Input() public label: string = ''; - @Input() options: string[] = []; + @Input() public options: string[] = []; - @Input() objectOptions: { id: string; name: string }[] = []; + @Input() public objectOptions: { id: string; name: string }[] = []; - @Input() selected = ''; - @Output() selectionChange = new EventEmitter(); + @Input() public selected = ''; + @Output() public readonly selectionChange = new EventEmitter(); - onChange(value: string) { + public onChange(value: string) { this.selectionChange.emit(value); } - isObjectMode(): boolean { + public isObjectMode(): boolean { return this.objectOptions && this.objectOptions.length > 0; } } diff --git a/uniplanWeb/src/app/core/shared/input-filter/input-filter.ts b/uniplanWeb/src/app/core/shared/input-filter/input-filter.ts index 1f70c70..a0a821b 100644 --- a/uniplanWeb/src/app/core/shared/input-filter/input-filter.ts +++ b/uniplanWeb/src/app/core/shared/input-filter/input-filter.ts @@ -12,7 +12,7 @@ import { MatFormField, MatInputModule } from '@angular/material/input'; styleUrl: './input-filter.scss', }) export class InputFilter { - @Input() label: string = ''; - @Input() searchText = ''; - @Output() searchTextChange = new EventEmitter(); + @Input() public label: string = ''; + @Input() public searchText: string = ''; + @Output() public readonly searchTextChange: EventEmitter = new EventEmitter(); } diff --git a/uniplanWeb/src/app/core/shared/main-panel/main-panel.ts b/uniplanWeb/src/app/core/shared/main-panel/main-panel.ts new file mode 100644 index 0000000..a56abaa --- /dev/null +++ b/uniplanWeb/src/app/core/shared/main-panel/main-panel.ts @@ -0,0 +1,106 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +import { FacultyOptions } from '../../../features/faculty/faculty-options/faculty-options'; +import { ViewService } from './view.service'; +import { MajorOptions } from '../../../features/major/major-options/major-options'; +import { FacultyTable } from '../../../features/faculty/faculty-table/faculty-table'; +import { MajorTable } from '../../../features/major/major-table/major-table'; +import { MajorFilters } from '../../../features/major/major-filters/major-filters'; +import { StudentOptions } from '../../../features/student/student-options/student-options'; +import { + StudentTable, + ELEMENT_STUDENT_DATA, +} from '../../../features/student/student-table/student-table'; +import { StudentFilters } from '../../../features/student/student-filters/student-filters'; +import { MajorElm } from '../../interfaces/major-elm'; +import { MajorService } from '../../../features/major/major-service'; +import { FacultyService } from '../../../features/faculty/faculty-service'; +import {StudentElm} from '../../interfaces/student-elm'; +import {FacultyElm} from '../../interfaces/faculty-elm'; + +@Component({ + selector: 'app-main-panel', + imports: [ + FacultyOptions, + MajorOptions, + FacultyTable, + MajorTable, + MajorFilters, + StudentOptions, + StudentTable, + StudentFilters +], + standalone: true, + templateUrl: './main-panel.html', + changeDetection: ChangeDetectionStrategy.Eager, + styleUrl: './main-panel.scss', +}) +export class MainPanel { + protected currentView: string = 'home'; + + protected majors: MajorElm[] = []; + protected students: StudentElm[] = ELEMENT_STUDENT_DATA; + + protected searchText: string = ''; + protected searchFacNum: string = ''; + protected searchMajor: string = ''; + protected selectedStudentSubtype: string = ''; + protected studentSubtypes: string[] = []; + + protected selectedFaculty: string = ''; + protected selectedType: string = ''; + protected selectedSubtype: string = ''; + + protected faculties: { id: string; name: string }[] = []; + protected types: string[] = []; + protected subtypes: string[] = []; + + private facultyMap: Map = new Map(); + + public constructor( + private viewService: ViewService, + private majorService: MajorService, + private facultyService: FacultyService + ) { + this.viewService.currentView$.subscribe((view: string): void => { + this.currentView = view; + }); + } + + public ngOnInit(): void { + this.loadMajorFilters(); + this.loadStudentFilters(); + + this.majorService.refreshNeeded.subscribe((): void => { + this.loadMajorFilters(); + }); + + this.viewService.currentView$.subscribe((view: string): void => { + this.currentView = view; + }); + } + + private loadMajorFilters(): void { + this.facultyService.getFaculties().subscribe((faculties: FacultyElm[]): void => { + this.facultyMap = new Map(faculties.map((f: FacultyElm): [any, any] => [f.id, f.facultyName])); + + this.majorService.getMajors().subscribe((data: MajorElm[]): void => { + this.majors = data; + + const filterOptionsMajor = MajorTable.getFilterOptions( + this.majors, + this.facultyMap + ); + + this.faculties = filterOptionsMajor.faculties; + this.types = filterOptionsMajor.types; + this.subtypes = filterOptionsMajor.subtypes; + }); + }); + } + + private loadStudentFilters(): void { + const filterOptionsStudent = StudentTable.getFilterOptions(this.students); + this.studentSubtypes = filterOptionsStudent.subtypes; + } +} diff --git a/uniplanWeb/src/app/core/shared/main-panel/view.service.ts b/uniplanWeb/src/app/core/shared/main-panel/view.service.ts new file mode 100644 index 0000000..e69de29 diff --git a/uniplanWeb/src/app/core/shared/navmenu-component/navmenu-component.ts b/uniplanWeb/src/app/core/shared/navmenu-component/navmenu-component.ts index 926e096..76e94c3 100644 --- a/uniplanWeb/src/app/core/shared/navmenu-component/navmenu-component.ts +++ b/uniplanWeb/src/app/core/shared/navmenu-component/navmenu-component.ts @@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common'; import { RouterLink, RouterLinkActive } from '@angular/router'; import { TranslatePipe } from '@ngx-translate/core'; +import { ViewService } from '../main-panel/view.service'; import { LoginAuthService } from '../../../services/login-auth-service'; @Component({ @@ -14,22 +15,22 @@ import { LoginAuthService } from '../../../services/login-auth-service'; styleUrls: ['./navmenu-component.scss'], }) export class NavmenuComponent implements OnInit { - isSidebarCollapsed = false; - isMobileView = window.innerWidth <= 768; + protected isSidebarCollapsed: boolean = false; + protected isMobileView: boolean = window.innerWidth <= 768; constructor(public authService: LoginAuthService) {} - ngOnInit(): void { + public ngOnInit(): void { this.checkViewport(); } @HostListener('window:resize', ['$event']) - onResize(event: Event): void { + protected onResize(event: Event): void { this.checkViewport(); } private checkViewport(): void { - const isNowMobile = window.innerWidth <= 768; + const isNowMobile: boolean = window.innerWidth <= 768; if (this.isMobileView !== isNowMobile) { this.isMobileView = isNowMobile; } @@ -38,7 +39,7 @@ export class NavmenuComponent implements OnInit { } } - toggleSidebar(): void { + protected toggleSidebar(): void { this.isSidebarCollapsed = !this.isSidebarCollapsed; } } diff --git a/uniplanWeb/src/app/features/faculty/faculty-add-form/faculty-add-form.ts b/uniplanWeb/src/app/features/faculty/faculty-add-form/faculty-add-form.ts index 8b75138..056dfb9 100644 --- a/uniplanWeb/src/app/features/faculty/faculty-add-form/faculty-add-form.ts +++ b/uniplanWeb/src/app/features/faculty/faculty-add-form/faculty-add-form.ts @@ -32,10 +32,10 @@ import { TranslatePipe } from '@ngx-translate/core'; styleUrl: './faculty-add-form.scss', }) export class FacultyAddForm implements OnInit { - facultyName = ''; - location = ''; - universityId = ''; - universities: UniversityElm[] = []; + protected facultyName: string = ''; + protected location: string = ''; + protected universityId: string = ''; + protected universities: UniversityElm[] = []; constructor( private dialogRef: MatDialogRef, @@ -43,18 +43,18 @@ export class FacultyAddForm implements OnInit { private universityService: UniversityService ) { } - ngOnInit(): void { + public ngOnInit(): void { this.universityService.getAllUniversities().subscribe({ - next: (data) => { + next: (data: UniversityElm[]): void => { this.universities = data; }, - error: (err) => { + error: (err: any): void => { console.error('Failed to load universities', err); }, }); } - save() { + protected save(): void { if (!this.facultyName.trim()) { alert('Please enter faculty name.'); return; @@ -72,11 +72,11 @@ export class FacultyAddForm implements OnInit { }; this.facultyService.createFaculty(newFaculty).subscribe({ - next: (response) => { + next: (response: any): void => { console.log('Faculty created:', response); this.dialogRef.close(response); }, - error: (err) => { + error: (err: any): void => { console.error('Failed to add faculty', err); alert('Failed to add faculty.'); }, diff --git a/uniplanWeb/src/app/features/faculty/faculty-delete-form/faculty-delete-form.ts b/uniplanWeb/src/app/features/faculty/faculty-delete-form/faculty-delete-form.ts index 853c1a5..a1a14f2 100644 --- a/uniplanWeb/src/app/features/faculty/faculty-delete-form/faculty-delete-form.ts +++ b/uniplanWeb/src/app/features/faculty/faculty-delete-form/faculty-delete-form.ts @@ -23,12 +23,12 @@ export class FacultyDeleteForm { public data: { id: string; facultyName: string } ) { } - deleteFaculty(): void { + protected deleteFaculty(): void { this.facultyService.deleteFaculty(this.data.id).subscribe({ - next: () => { + next: (): void => { this.dialogRef.close(true); }, - error: () => { + error: (): void => { alert('Възникна грешка при изтриването на факултета.'); }, }); diff --git a/uniplanWeb/src/app/features/faculty/faculty-edit/faculty-edit.ts b/uniplanWeb/src/app/features/faculty/faculty-edit/faculty-edit.ts index 41636a6..479d832 100644 --- a/uniplanWeb/src/app/features/faculty/faculty-edit/faculty-edit.ts +++ b/uniplanWeb/src/app/features/faculty/faculty-edit/faculty-edit.ts @@ -32,9 +32,9 @@ import { TranslatePipe } from '@ngx-translate/core'; ], }) export class FacultyEdit { - facultyName = ''; - location = ''; - universityId = ''; + protected facultyName: string = ''; + protected location: string = ''; + protected universityId: string = ''; constructor( private dialogRef: MatDialogRef, @@ -51,8 +51,7 @@ export class FacultyEdit { this.location = data.location; this.universityId = data.universityId; } - - save() { + protected save(): void { if (!this.facultyName.trim()) { alert('Please enter faculty name.'); return; @@ -70,10 +69,10 @@ export class FacultyEdit { universityId: this.universityId, }) .subscribe({ - next: () => { + next: (): void => { this.dialogRef.close(true); }, - error: () => { + error: (): void => { alert('Failed to update faculty.'); }, }); diff --git a/uniplanWeb/src/app/features/faculty/faculty-options/faculty-options.ts b/uniplanWeb/src/app/features/faculty/faculty-options/faculty-options.ts index 78bb40f..865fcac 100644 --- a/uniplanWeb/src/app/features/faculty/faculty-options/faculty-options.ts +++ b/uniplanWeb/src/app/features/faculty/faculty-options/faculty-options.ts @@ -22,7 +22,7 @@ import { AddButton } from '../../../core/shared/add-button/add-button'; export class FacultyOptions { constructor(private dialog: MatDialog) { } - openAddForm() { + protected openAddForm(): void { this.dialog.open(FacultyAddForm, { width: '400px', }); diff --git a/uniplanWeb/src/app/features/faculty/faculty-service.ts b/uniplanWeb/src/app/features/faculty/faculty-service.ts index 1c423f0..9111a12 100644 --- a/uniplanWeb/src/app/features/faculty/faculty-service.ts +++ b/uniplanWeb/src/app/features/faculty/faculty-service.ts @@ -26,7 +26,7 @@ export class FacultyService { ); } - createFaculty(faculty: { + public createFaculty(faculty: { universityId: string; facultyName: string; location: string; @@ -39,7 +39,7 @@ export class FacultyService { ); } - editFaculty( + public editFaculty( id: string, updatedFaculty: { universityId: string; diff --git a/uniplanWeb/src/app/features/major/major-add-form/major-add-form.ts b/uniplanWeb/src/app/features/major/major-add-form/major-add-form.ts index 997af68..2b651b1 100644 --- a/uniplanWeb/src/app/features/major/major-add-form/major-add-form.ts +++ b/uniplanWeb/src/app/features/major/major-add-form/major-add-form.ts @@ -13,7 +13,7 @@ import { MajorService } from '../major-service'; import { FacultyElm } from '../../../core/interfaces/faculty-elm'; import { FacultyService } from '../../faculty/faculty-service'; import { TranslatePipe } from '@ngx-translate/core'; - + @Component({ selector: 'app-major-add-form', templateUrl: './major-add-form.html', @@ -38,24 +38,24 @@ export class MajorAddForm implements OnInit { type = ''; subtype = ''; - faculties: FacultyElm[] = []; + protected faculties: FacultyElm[] = []; constructor( private dialogRef: MatDialogRef, private majorService: MajorService, private facultyService: FacultyService - ) { } + ) {} - ngOnInit(): void { + public ngOnInit(): void { this.facultyService.getFaculties().subscribe({ - next: (data) => { + next: (data: FacultyElm[]) => { this.faculties = data; }, - error: (err) => console.error('Failed to load faculties', err), + error: (err: any): void => console.error('Failed to load faculties', err), }); } - save() { + protected save(): void { if ( !this.majorName.trim() || !this.faculty || @@ -74,10 +74,10 @@ export class MajorAddForm implements OnInit { subtype: this.subtype, }) .subscribe({ - next: () => { + next: (): void => { this.dialogRef.close(true); }, - error: () => alert('Failed to create major or course.'), + error: (): void => alert('Failed to create major or course.'), }); } } diff --git a/uniplanWeb/src/app/features/major/major-delete-form/major-delete-form.ts b/uniplanWeb/src/app/features/major/major-delete-form/major-delete-form.ts index 8daf4d0..8a5619c 100644 --- a/uniplanWeb/src/app/features/major/major-delete-form/major-delete-form.ts +++ b/uniplanWeb/src/app/features/major/major-delete-form/major-delete-form.ts @@ -25,11 +25,11 @@ export class MajorDeleteForm { public data: { id: string; name: string } ) {} - deleteMajor(): void { + protected deleteMajor(): void { this.majorService .deleteMajor(this.data.id) .subscribe({ - next: () => { + next: (): void => { this.dialogRef.close(true); }, error: () => { diff --git a/uniplanWeb/src/app/features/major/major-edit-form/major-edit-form.ts b/uniplanWeb/src/app/features/major/major-edit-form/major-edit-form.ts index f3ee936..4e0049a 100644 --- a/uniplanWeb/src/app/features/major/major-edit-form/major-edit-form.ts +++ b/uniplanWeb/src/app/features/major/major-edit-form/major-edit-form.ts @@ -10,6 +10,7 @@ import { MatOptionModule } from '@angular/material/core'; import { MatSelectModule } from '@angular/material/select'; import { MatInputModule } from '@angular/material/input'; import { FormsModule } from '@angular/forms'; + import { MajorService } from '../major-service'; import { FacultyService } from '../../faculty/faculty-service'; import { FacultyElm } from '../../../core/interfaces/faculty-elm'; @@ -32,10 +33,10 @@ import { TranslatePipe } from '@ngx-translate/core'; TranslatePipe], }) export class MajorEditForm implements OnInit { - majorName = ''; - facultyId = ''; + protected majorName: string = ''; + protected facultyId: string = ''; - faculties: FacultyElm[] = []; + protected faculties: FacultyElm[] = []; constructor( private dialogRef: MatDialogRef, @@ -52,14 +53,14 @@ export class MajorEditForm implements OnInit { this.facultyId = data.facultyId || ''; } - ngOnInit(): void { + public ngOnInit(): void { this.facultyService.getFaculties().subscribe({ - next: (data) => (this.faculties = data), - error: (err) => console.error('Failed to load faculties', err), + next: (data: FacultyElm[]): FacultyElm[] => (this.faculties = data), + error: (err: any): void => console.error('Failed to load faculties', err), }); } - save() { + protected save(): void { if (!this.majorName.trim()) { alert('Please enter the major name.'); return; @@ -71,8 +72,8 @@ export class MajorEditForm implements OnInit { majorName: this.majorName, }) .subscribe({ - next: () => this.dialogRef.close(true), - error: () => alert('Failed to update major.'), + next: (): void => this.dialogRef.close(true), + error: (): void => alert('Failed to update major.'), }); } } diff --git a/uniplanWeb/src/app/features/major/major-filters/major-filters.ts b/uniplanWeb/src/app/features/major/major-filters/major-filters.ts index ae46530..b437913 100644 --- a/uniplanWeb/src/app/features/major/major-filters/major-filters.ts +++ b/uniplanWeb/src/app/features/major/major-filters/major-filters.ts @@ -23,19 +23,19 @@ import { TranslatePipe } from '@ngx-translate/core'; ], }) export class MajorFilters { - @Input() internalSearchText = ''; + @Input() public internalSearchText = ''; - @Input() faculties: { id: string; name: string }[] = []; + @Input() public faculties: { id: string; name: string }[] = []; - @Input() types: string[] = []; - @Input() subtypes: string[] = []; + @Input() public types: string[] = []; + @Input() public subtypes: string[] = []; - @Input() selectedFaculty = ''; - @Input() selectedType = ''; - @Input() selectedSubtype = ''; + @Input() public selectedFaculty: string = ''; + @Input() public selectedType: string = ''; + @Input() public selectedSubtype: string = ''; - @Output() facultyChange = new EventEmitter(); - @Output() typeChange = new EventEmitter(); - @Output() subtypeChange = new EventEmitter(); - @Output() searchTextChange = new EventEmitter(); + @Output() public readonly facultyChange: EventEmitter = new EventEmitter(); + @Output() public readonly typeChange: EventEmitter = new EventEmitter(); + @Output() public readonly subtypeChange: EventEmitter = new EventEmitter(); + @Output() public readonly searchTextChange: EventEmitter = new EventEmitter(); } diff --git a/uniplanWeb/src/app/features/major/major-options/major-options.ts b/uniplanWeb/src/app/features/major/major-options/major-options.ts index e5a0660..e55b232 100644 --- a/uniplanWeb/src/app/features/major/major-options/major-options.ts +++ b/uniplanWeb/src/app/features/major/major-options/major-options.ts @@ -22,7 +22,7 @@ import { AddButton } from '../../../core/shared/add-button/add-button'; export class MajorOptions { constructor(private dialog: MatDialog) {} - openAddForm() { + protected openAddForm(): void { this.dialog.open(MajorAddForm, { width: '400px', }); diff --git a/uniplanWeb/src/app/features/major/major-service.ts b/uniplanWeb/src/app/features/major/major-service.ts index c7a4626..32d6348 100644 --- a/uniplanWeb/src/app/features/major/major-service.ts +++ b/uniplanWeb/src/app/features/major/major-service.ts @@ -29,7 +29,7 @@ export class MajorService { ); } - createMajor(createMajor: { + public createMajor(createMajor: { facultyId: string; majorName: string; }): Observable { @@ -41,7 +41,7 @@ export class MajorService { ); } - createCourse(course: { + public createCourse(course: { majorId: string; courseYear: number; courseType: string; @@ -54,7 +54,7 @@ export class MajorService { }) ); } - createMajorWithCourse(majorData: { + public createMajorWithCourse(majorData: { facultyId: string; majorName: string; type: string; @@ -64,7 +64,7 @@ export class MajorService { facultyId: majorData.facultyId, majorName: majorData.majorName, }).pipe( - switchMap((createdMajor: any) => { + switchMap((createdMajor: any): Observable => { return this.createCourse({ majorId: createdMajor.id, courseType: majorData.type, @@ -94,7 +94,7 @@ export class MajorService { ); } - editMajor( + public editMajor( id: string, updateMajor: { facultyId: string; majorName: string } ): Observable { diff --git a/uniplanWeb/src/app/features/student/student-add-form/student-add-form.html b/uniplanWeb/src/app/features/student/student-add-form/student-add-form.html index d9a2c23..b7fde58 100644 --- a/uniplanWeb/src/app/features/student/student-add-form/student-add-form.html +++ b/uniplanWeb/src/app/features/student/student-add-form/student-add-form.html @@ -32,4 +32,4 @@ - \ No newline at end of file + diff --git a/uniplanWeb/src/app/features/student/student-add-form/student-add-form.ts b/uniplanWeb/src/app/features/student/student-add-form/student-add-form.ts index cf22217..d3cffd3 100644 --- a/uniplanWeb/src/app/features/student/student-add-form/student-add-form.ts +++ b/uniplanWeb/src/app/features/student/student-add-form/student-add-form.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { Component, ChangeDetectionStrategy, OnInit, inject} from '@angular/core'; import { AddForm } from '../../../core/shared/add-form/add-form'; import { MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { @@ -8,6 +8,11 @@ import { } from '@angular/material/input'; import { FormsModule } from '@angular/forms'; import { TranslatePipe } from '@ngx-translate/core'; +import { MajorElm } from '../../../core/interfaces/major-elm'; +import { MajorService } from '../../major/major-service'; +import {MatSelectModule} from '@angular/material/select'; +import {MatOptionModule} from '@angular/material/core'; +import { MajorOptionElm } from '../../../core/interfaces/major-option-elm'; @Component({ selector: 'app-student-add-form', @@ -21,26 +26,49 @@ import { TranslatePipe } from '@ngx-translate/core'; FormsModule, MatInputModule, AddForm, + MatSelectModule, + MatOptionModule, TranslatePipe ], }) -export class StudentAddForm { - studentName = ''; - facultyNumber = ''; - faculty = ''; - major = ''; - course = ''; - type = ''; +export class StudentAddForm implements OnInit { + protected studentName: string = ''; + protected facultyNumber: string = ''; + protected faculty: string = ''; + protected major: string = ''; + protected course: string = ''; + protected type: string = ''; - constructor(private dialogRef: MatDialogRef) { } + protected majors: MajorOptionElm[] = []; + protected courses: string[] = ['1', '2', '3', '4']; + protected types: string[] = []; - save() { + private readonly dialogRef: MatDialogRef = + inject(MatDialogRef); + + private readonly majorService: MajorService = inject(MajorService); + + public ngOnInit(): void { + console.log('StudentAddForm opened'); + + this.majorService.getMajorOptions().subscribe({ + next: (majors: MajorOptionElm[]): void => { + console.log('Major dropdown data:', majors); + this.majors = majors; + }, + error: (err: unknown): void => { + console.error('Failed to load major options', err); + }, + }); + } + + protected save(): void { if (!this.studentName.trim()) { alert('Please enter student name.'); return; } if (!this.facultyNumber.trim()) { - alert('Please enter faculty numbe.'); + alert('Please enter faculty number.'); return; } if (!this.faculty.trim()) { @@ -79,4 +107,16 @@ export class StudentAddForm { type: this.type, }); } + + protected onMajorChange(value: string): void { + this.major = value; + } + + protected onCourseChange(value: string): void { + this.course = value; + } + + protected onTypeChange(value: string): void { + this.type = value; + } } diff --git a/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.html b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.html new file mode 100644 index 0000000..844a3cb --- /dev/null +++ b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.html @@ -0,0 +1,44 @@ + + + + Име: + + + + + Факултетен номер: + + + + + Специалност: + + + + + Квалификационна степен: + + бакалавър + магистър + + + + + Курс: + + 1 + 2 + 3 + 4 + + + + + Форма на обучение: + + редовно + задочно + + + + diff --git a/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.scss b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.scss new file mode 100644 index 0000000..4673eee --- /dev/null +++ b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.scss @@ -0,0 +1,7 @@ +:host { + display: block; +} + +mat-form-field { + width: 100%; +} diff --git a/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.spec.ts b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.spec.ts new file mode 100644 index 0000000..fbb7498 --- /dev/null +++ b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StudentEditForm } from './student-edit-form'; + +describe('StudentEditForm', () => { + let component: StudentEditForm; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [StudentEditForm] + }) + .compileComponents(); + + fixture = TestBed.createComponent(StudentEditForm); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.ts b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.ts new file mode 100644 index 0000000..7897325 --- /dev/null +++ b/uniplanWeb/src/app/features/student/student-edit-form/student-edit-form.ts @@ -0,0 +1,86 @@ +import { Component, Inject, ChangeDetectionStrategy } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { + MAT_DIALOG_DATA, + MatDialogModule, + MatDialogRef, +} from '@angular/material/dialog'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; +import { MatOptionModule } from '@angular/material/core'; + +import { EditForm } from '../../../core/shared/edit-form/edit-form'; +import { StudentElm } from '../../../core/interfaces/student-elm'; + +@Component({ + selector: 'app-student-edit-form', + standalone: true, + imports: [ + EditForm, + MatDialogModule, + MatFormField, + MatLabel, + FormsModule, + MatInputModule, + MatSelectModule, + MatOptionModule, + ], + templateUrl: './student-edit-form.html', + changeDetection: ChangeDetectionStrategy.Eager, + styleUrl: './student-edit-form.scss', +}) +export class StudentEditForm { + protected name: string = ''; + protected facultyNumber: string = ''; + protected major: string = ''; + protected majorType: StudentElm['majorType'] = 'бакалавър'; + protected course: string = ''; + protected subtype: StudentElm['subtype'] = 'редовно'; + + public constructor( + private readonly dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) protected readonly data: StudentElm + ) { + this.name = data.name; + this.facultyNumber = data.facultyNumber; + this.major = data.major; + this.majorType = data.majorType; + this.course = data.course; + this.subtype = data.subtype; + } + + protected save(): void { + if (!this.name.trim()) { + alert('Моля въведете име на студента.'); + return; + } + + if (!this.facultyNumber.trim()) { + alert('Моля въведете факултетен номер.'); + return; + } + + if (!this.major.trim()) { + alert('Моля въведете специалност.'); + return; + } + + if (!this.course.trim()) { + alert('Моля въведете курс.'); + return; + } + + const updatedStudent: StudentElm = { + ...this.data, + name: this.name, + facultyNumber: this.facultyNumber, + major: this.major, + majorType: this.majorType, + course: this.course, + subtype: this.subtype, + }; + + this.dialogRef.close(updatedStudent); + } +} diff --git a/uniplanWeb/src/app/features/student/student-filters/student-filters.ts b/uniplanWeb/src/app/features/student/student-filters/student-filters.ts index 66b8b2b..3e90c48 100644 --- a/uniplanWeb/src/app/features/student/student-filters/student-filters.ts +++ b/uniplanWeb/src/app/features/student/student-filters/student-filters.ts @@ -11,16 +11,16 @@ import { TranslatePipe } from '@ngx-translate/core'; imports: [InputFilter, FiltersForm, TranslatePipe], }) export class StudentFilters { - @Input() internalSearchText = ''; - @Output() searchTextChange = new EventEmitter(); + @Input() public internalSearchText: string = ''; + @Output() public readonly searchTextChange: EventEmitter = new EventEmitter(); - @Input() internalSearchFacNum = ''; - @Output() searchFacNumChange = new EventEmitter(); + @Input() public internalSearchFacNum: string = ''; + @Output() public readonly searchFacNumChange: EventEmitter = new EventEmitter(); - @Input() internalSearchMajor = ''; - @Output() searchMajorChange = new EventEmitter(); + @Input() public internalSearchMajor: string = ''; + @Output() public readonly searchMajorChange: EventEmitter = new EventEmitter(); - @Input() subtypes: string[] = []; - @Input() selectedSubtype = ''; - @Output() subtypeChange = new EventEmitter(); + @Input() public subtypes: string[] = []; + @Input() public selectedSubtype: string = ''; + @Output() public readonly subtypeChange: EventEmitter = new EventEmitter(); } diff --git a/uniplanWeb/src/app/features/student/student-options/student-options.ts b/uniplanWeb/src/app/features/student/student-options/student-options.ts index 04b7c24..5a60b48 100644 --- a/uniplanWeb/src/app/features/student/student-options/student-options.ts +++ b/uniplanWeb/src/app/features/student/student-options/student-options.ts @@ -13,7 +13,7 @@ import { StudentAddForm } from '../student-add-form/student-add-form'; export class StudentOptions { constructor(private dialog: MatDialog) {} - openAddForm() { + protected openAddForm(): void { this.dialog.open(StudentAddForm, { width: '400px', }); diff --git a/uniplanWeb/src/app/features/student/student-table/student-table.ts b/uniplanWeb/src/app/features/student/student-table/student-table.ts index 3bc330c..1c7eb7c 100644 --- a/uniplanWeb/src/app/features/student/student-table/student-table.ts +++ b/uniplanWeb/src/app/features/student/student-table/student-table.ts @@ -4,7 +4,8 @@ import { SimpleChanges, OnChanges, OnInit, - ChangeDetectionStrategy + ChangeDetectionStrategy, + inject } from '@angular/core'; import { StudentElm } from '../../../core/interfaces/student-elm'; import { TranslatePipe } from '@ngx-translate/core'; @@ -12,6 +13,8 @@ import { TranslatePipe } from '@ngx-translate/core'; import { MatTableModule } from '@angular/material/table'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; +import {MatDialog, MatDialogModule} from '@angular/material/dialog'; +import {StudentEditForm} from '../student-edit-form/student-edit-form'; export const ELEMENT_STUDENT_DATA: StudentElm[] = [ { @@ -114,14 +117,16 @@ export const ELEMENT_STUDENT_DATA: StudentElm[] = [ imports: [MatTableModule, MatIconModule, MatButtonModule, TranslatePipe], }) export class StudentTable implements OnInit, OnChanges { - @Input() searchText = ''; - @Input() searchFacNum = ''; - @Input() searchMajor = ''; - @Input() subtype = ''; + private readonly dialog: MatDialog = inject(MatDialog); - @Input() subtypes: string[] = []; + @Input() public searchText: string = ''; + @Input() public searchFacNum: string = ''; + @Input() public searchMajor: string = ''; + @Input() public subtype: string = ''; - displayedColumns: string[] = [ + @Input() public subtypes: string[] = []; + + protected displayedColumns: string[] = [ 'position', 'name', 'facultyNumber', @@ -132,44 +137,59 @@ export class StudentTable implements OnInit, OnChanges { 'actions', ]; - originalData: StudentElm[] = ELEMENT_STUDENT_DATA; - dataSourceFilter: StudentElm[] = ELEMENT_STUDENT_DATA; + protected originalData: StudentElm[] = ELEMENT_STUDENT_DATA; + protected dataSourceFilter: StudentElm[] = ELEMENT_STUDENT_DATA; - ngOnInit(): void { + public ngOnInit(): void { this.subtypes = StudentTable.getFilterOptions(this.originalData).subtypes; this.applyFilters(); } - ngOnChanges(changes: SimpleChanges): void { + public ngOnChanges(changes: SimpleChanges): void { this.applyFilters(); } - applyFilters(): void { - const name = this.searchText.toLowerCase(); - const major = this.searchMajor.toLowerCase(); - const facNum = this.searchFacNum; + private applyFilters(): void { + const name: string = this.searchText.toLowerCase(); + const major: string = this.searchMajor.toLowerCase(); + const facNum: string = this.searchFacNum; this.dataSourceFilter = this.originalData.filter((student) => { - const matchName = !name || student.name.toLowerCase().includes(name); - const matchMajor = !major || student.major.toLowerCase().includes(major); - const matchFacNum = !facNum || student.facultyNumber.includes(facNum); - const matchSubtype = !this.subtype || student.subtype === this.subtype; + const matchName: boolean = !name || student.name.toLowerCase().includes(name); + const matchMajor: boolean = !major || student.major.toLowerCase().includes(major); + const matchFacNum: boolean = !facNum || student.facultyNumber.includes(facNum); + const matchSubtype: boolean = !this.subtype || student.subtype === this.subtype; return matchName && matchMajor && matchFacNum && matchSubtype; }); } - static getFilterOptions(data: StudentElm[]) { + public static getFilterOptions(data: StudentElm[]) { return { - subtypes: [...new Set(data.map((e) => e.subtype))], + subtypes: [...new Set(data.map((e: StudentElm) => e.subtype))], }; } - onEdit(element: StudentElm): void { - console.log('Editing:', element); + protected onEdit(element: StudentElm): void { + const dialogRef = this.dialog.open(StudentEditForm, { + width: '500px', + data: { ...element }, + }); + + dialogRef.afterClosed().subscribe((updatedStudent: StudentElm | undefined): void => { + if (!updatedStudent) { + return; + } + + this.originalData = this.originalData.map((student: StudentElm): StudentElm => + student.position === element.position ? updatedStudent : student + ); + + this.applyFilters(); + }); } - onDelete(element: StudentElm): void { + protected onDelete(element: StudentElm): void { console.log('Deleting:', element); } } diff --git a/uniplanWeb/src/app/services/login-auth-service.ts b/uniplanWeb/src/app/services/login-auth-service.ts index 3ec49fe..8d68305 100644 --- a/uniplanWeb/src/app/services/login-auth-service.ts +++ b/uniplanWeb/src/app/services/login-auth-service.ts @@ -4,17 +4,17 @@ import { Injectable } from '@angular/core'; providedIn: 'root' }) export class LoginAuthService { - private loggedIn = false; + private loggedIn: boolean = false; constructor() { this.loggedIn = !!localStorage.getItem('user'); } - isLoggedIn(): boolean { + public isLoggedIn(): boolean { return this.loggedIn; } - logout(): void { + public logout(): void { localStorage.removeItem('user'); this.loggedIn = false; }