From 137f8770c85b1637046690c3539b30b46a9e5c6b Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Wed, 1 Jul 2026 11:53:53 +0300 Subject: [PATCH 01/13] Add create form for room --- uniplanWeb/public/i18n/bg.json | 5 +- uniplanWeb/public/i18n/en.json | 5 +- .../room/room-add-form/room-add-form.html | 19 +++++ .../room/room-add-form/room-add-form.scss | 15 ++++ .../room/room-add-form/room-add-form.spec.ts | 23 ++++++ .../room/room-add-form/room-add-form.ts | 82 +++++++++++++++++++ .../room/room-options/room-options.html | 1 + .../room/room-options/room-options.scss | 0 .../room/room-options/room-options.spec.ts | 23 ++++++ .../room/room-options/room-options.ts | 28 +++++++ .../features/room/room-panel/room-panel.html | 3 +- .../features/room/room-panel/room-panel.ts | 3 +- .../src/app/features/room/room-service.ts | 18 +++- .../features/room/room-table/room-table.html | 2 +- .../features/room/room-table/room-table.ts | 23 ++++-- 15 files changed, 235 insertions(+), 15 deletions(-) create mode 100644 uniplanWeb/src/app/features/room/room-add-form/room-add-form.html create mode 100644 uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss create mode 100644 uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts create mode 100644 uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts create mode 100644 uniplanWeb/src/app/features/room/room-options/room-options.html create mode 100644 uniplanWeb/src/app/features/room/room-options/room-options.scss create mode 100644 uniplanWeb/src/app/features/room/room-options/room-options.spec.ts create mode 100644 uniplanWeb/src/app/features/room/room-options/room-options.ts diff --git a/uniplanWeb/public/i18n/bg.json b/uniplanWeb/public/i18n/bg.json index 5d3fe91..fc90a42 100644 --- a/uniplanWeb/public/i18n/bg.json +++ b/uniplanWeb/public/i18n/bg.json @@ -13,7 +13,10 @@ }, "room": { "room-number": "Номер на стая", - "no-rooms": "Няма записани стаи" + "no-rooms": "Няма записани стаи", + "add": { + "title": "Добави стая" + } }, "faculty": { "delete-button": "Изтрий", diff --git a/uniplanWeb/public/i18n/en.json b/uniplanWeb/public/i18n/en.json index bd15631..c008b79 100644 --- a/uniplanWeb/public/i18n/en.json +++ b/uniplanWeb/public/i18n/en.json @@ -13,7 +13,10 @@ }, "room": { "room-number": "Room number", - "no-rooms": "No rooms" + "no-rooms": "No rooms", + "add": { + "title": "Add room" + } }, "faculty": { "delete-button": "Delete", diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.html b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.html new file mode 100644 index 0000000..c5247a9 --- /dev/null +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.html @@ -0,0 +1,19 @@ + +
+ + {{ 'room.room-number' | translate }} + + + + + {{ 'features.faculty-label' | translate }} + + @for (faculty of faculties; track faculty.id) { + + {{ faculty.facultyName }} + + } + + +
+
\ No newline at end of file diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss new file mode 100644 index 0000000..6f4bf98 --- /dev/null +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss @@ -0,0 +1,15 @@ +mat-form-field { + width: 100%; +} + +mat-dialog-title { + font-size: 20px; + font-weight: bold; + color: #3f51b5; +} + +input { + border-radius: 10px; + width: 100%; +} + diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts new file mode 100644 index 0000000..eebb8bf --- /dev/null +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RoomAddForm } from './room-add-form'; + +describe('RoomAddForm', () => { + let component: RoomAddForm; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RoomAddForm] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RoomAddForm); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts new file mode 100644 index 0000000..fab081f --- /dev/null +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -0,0 +1,82 @@ + +import { Component, OnInit, ChangeDetectionStrategy, inject, DestroyRef } from '@angular/core'; +import { FormsModule, Validators } from '@angular/forms'; +import { 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 { AddForm } from '../../../core/shared/add-form/add-form'; +import { TranslatePipe } from '@ngx-translate/core'; +import { FacultyService } from '../../faculty/faculty-service'; +import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FacultyElm } from '../../../core/interfaces/faculty-elm'; +import { RoomService } from '../room-service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; + +@Component({ + selector: 'app-room-add-form', + templateUrl: './room-add-form.html', + styleUrl: './room-add-form.scss', + changeDetection: ChangeDetectionStrategy.Eager, + imports: [ + MatDialogModule, + MatFormField, + MatLabel, + FormsModule, + MatInputModule, + MatSelectModule, + MatOptionModule, + AddForm, + TranslatePipe, + ReactiveFormsModule + ], +}) + +export class RoomAddForm implements OnInit { + private dialogRef = inject(MatDialogRef); + private facultyService = inject(FacultyService); + private roomService = inject(RoomService) + faculties: FacultyElm[] = []; + private destroyRef = inject(DestroyRef); + + addForm = new FormGroup({ + roomNumber: new FormControl('', Validators.required), + facultyId: new FormControl('', Validators.required), + }); + + ngOnInit(): void { + this.facultyService.getFaculties() + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe({ + next: (data) => { + this.faculties = data; + }, + error: (err) => { + console.error('Failed to load faculties', err); + }, + }); + } + + save() { + if (this.addForm.invalid) { + return; + } + + const newRoom = { + roomNumber: this.addForm.value.roomNumber ?? '', + facultyId: this.addForm.value.facultyId ?? '', + }; + + this.roomService.createRoom(newRoom).subscribe({ + next: (response) => { + console.log('Room created:', response); + this.dialogRef.close(response); + }, + error: (err) => { + console.error('Failed to add room', err); + alert('Failed to add room.'); + }, + }); + } +} diff --git a/uniplanWeb/src/app/features/room/room-options/room-options.html b/uniplanWeb/src/app/features/room/room-options/room-options.html new file mode 100644 index 0000000..7425749 --- /dev/null +++ b/uniplanWeb/src/app/features/room/room-options/room-options.html @@ -0,0 +1 @@ + diff --git a/uniplanWeb/src/app/features/room/room-options/room-options.scss b/uniplanWeb/src/app/features/room/room-options/room-options.scss new file mode 100644 index 0000000..e69de29 diff --git a/uniplanWeb/src/app/features/room/room-options/room-options.spec.ts b/uniplanWeb/src/app/features/room/room-options/room-options.spec.ts new file mode 100644 index 0000000..0d5fbc2 --- /dev/null +++ b/uniplanWeb/src/app/features/room/room-options/room-options.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RoomOptions } from './room-options'; + +describe('RoomOptions', () => { + let component: RoomOptions; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RoomOptions] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RoomOptions); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/uniplanWeb/src/app/features/room/room-options/room-options.ts b/uniplanWeb/src/app/features/room/room-options/room-options.ts new file mode 100644 index 0000000..5fed7f2 --- /dev/null +++ b/uniplanWeb/src/app/features/room/room-options/room-options.ts @@ -0,0 +1,28 @@ +import { Component, ChangeDetectionStrategy, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTableModule } from '@angular/material/table'; +import { MatDialog } from '@angular/material/dialog'; +import { AddButton } from '../../../core/shared/add-button/add-button'; +import { RoomAddForm } from '../room-add-form/room-add-form'; + +@Component({ + selector: 'app-room-options', + templateUrl: './room-options.html', + styleUrl: './room-options.scss', + changeDetection: ChangeDetectionStrategy.Eager, + imports: [ + MatTableModule, + MatIconModule, + MatButtonModule, + AddButton + ], +}) +export class RoomOptions { + private dialog = inject(MatDialog) + openAddForm() { + this.dialog.open(RoomAddForm, { + width: '400px', + }); + } +} diff --git a/uniplanWeb/src/app/features/room/room-panel/room-panel.html b/uniplanWeb/src/app/features/room/room-panel/room-panel.html index 5e00afd..da0f289 100644 --- a/uniplanWeb/src/app/features/room/room-panel/room-panel.html +++ b/uniplanWeb/src/app/features/room/room-panel/room-panel.html @@ -1,3 +1,4 @@
- + +
\ No newline at end of file diff --git a/uniplanWeb/src/app/features/room/room-panel/room-panel.ts b/uniplanWeb/src/app/features/room/room-panel/room-panel.ts index 8b82bb7..d9cb97c 100644 --- a/uniplanWeb/src/app/features/room/room-panel/room-panel.ts +++ b/uniplanWeb/src/app/features/room/room-panel/room-panel.ts @@ -1,11 +1,12 @@ import { Component } from '@angular/core'; import { RoomTable } from '../room-table/room-table'; +import { RoomOptions } from '../room-options/room-options'; @Component({ selector: 'app-room-panel', templateUrl: './room-panel.html', styleUrl: './room-panel.scss', - imports: [RoomTable], + imports: [RoomTable, RoomOptions], }) export class RoomPanel { diff --git a/uniplanWeb/src/app/features/room/room-service.ts b/uniplanWeb/src/app/features/room/room-service.ts index d9c07c5..eea6c27 100644 --- a/uniplanWeb/src/app/features/room/room-service.ts +++ b/uniplanWeb/src/app/features/room/room-service.ts @@ -3,7 +3,7 @@ import { HttpClient } from '@angular/common/http'; import { map, Observable, shareReplay } from 'rxjs'; import { RoomViewModel } from '../../core/interfaces/room-view-model'; import { RoomElm } from '../../core/interfaces/room-elm'; - +import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -11,8 +11,10 @@ import { RoomElm } from '../../core/interfaces/room-elm'; export class RoomService { private apiUrl = 'http://localhost:8080/api/rooms'; + + refreshNeeded = new Subject(); - http = inject(HttpClient); + private http = inject(HttpClient); getRooms(): Observable { return this.http.get(this.apiUrl).pipe( @@ -28,4 +30,16 @@ export class RoomService { shareReplay(1) ); } + + createRoom(room: { + roomNumber: string; + facultyId: string; + }): Observable { + return this.http.post(`${this.apiUrl}`, room).pipe( + map((res) => { + this.refreshNeeded.next(); + return res; + }) + ); + } } \ No newline at end of file diff --git a/uniplanWeb/src/app/features/room/room-table/room-table.html b/uniplanWeb/src/app/features/room/room-table/room-table.html index 0c9c4df..3747b80 100644 --- a/uniplanWeb/src/app/features/room/room-table/room-table.html +++ b/uniplanWeb/src/app/features/room/room-table/room-table.html @@ -35,7 +35,7 @@ - {{ element.facultyId | facultyNamePipe: facultyMap }} + {{ element.facultyId | facultyNamePipe: facultyMap() }} diff --git a/uniplanWeb/src/app/features/room/room-table/room-table.ts b/uniplanWeb/src/app/features/room/room-table/room-table.ts index e186334..874c1eb 100644 --- a/uniplanWeb/src/app/features/room/room-table/room-table.ts +++ b/uniplanWeb/src/app/features/room/room-table/room-table.ts @@ -1,4 +1,4 @@ -import { Component, inject, ChangeDetectionStrategy, DestroyRef } from '@angular/core'; +import { Component, inject, ChangeDetectionStrategy, DestroyRef, signal, OnInit } from '@angular/core'; import { RoomService } from '../room-service'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; @@ -9,6 +9,7 @@ import { CommonModule } from '@angular/common'; import { FacultyService } from '../../faculty/faculty-service'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FacultyNamePipe } from '../../../core/shared/pipes/faculty-name-pipe'; +import { startWith, switchMap } from 'rxjs'; @Component({ selector: 'app-room-table', @@ -26,12 +27,15 @@ import { FacultyNamePipe } from '../../../core/shared/pipes/faculty-name-pipe'; ], }) -export class RoomTable { - roomService = inject(RoomService); - facultyService = inject(FacultyService); - facultyMap = new Map(); +export class RoomTable implements OnInit { + private roomService = inject(RoomService); + + private facultyService = inject(FacultyService); + private destroyRef = inject(DestroyRef); + facultyMap = signal>(new Map()); + displayedColumns: string[] = [ 'position', 'facultyId', @@ -39,17 +43,20 @@ export class RoomTable { 'actions', ]; - data$ = this.roomService.getRooms(); - ngOnInit() { this.loadFaculties(); } + data$ = this.roomService.refreshNeeded.pipe( + startWith(void 0), + switchMap(() => this.roomService.getRooms()) + ); + loadFaculties(): void { this.facultyService.getFaculties() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((faculties) => { - this.facultyMap = new Map(faculties.map((f) => [f.id, f.facultyName])); + this.facultyMap.set(new Map(faculties.map((f) => [f.id, f.facultyName]))); }); } } From 0ff2c228180236000270496ff9d9e50ed586a7a2 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Wed, 1 Jul 2026 13:23:44 +0300 Subject: [PATCH 02/13] Use extracted api url for service --- uniplanWeb/src/app/config/endpoints.ts | 1 + uniplanWeb/src/app/features/room/room-service.ts | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/uniplanWeb/src/app/config/endpoints.ts b/uniplanWeb/src/app/config/endpoints.ts index 53a9589..0d9f0d0 100644 --- a/uniplanWeb/src/app/config/endpoints.ts +++ b/uniplanWeb/src/app/config/endpoints.ts @@ -5,4 +5,5 @@ export const API_ENDPOINTS = { courses: `${environment.baseUrl}/courses`, faculties: `${environment.baseUrl}/faculties`, majors: `${environment.baseUrl}/majors`, + rooms: `${environment.baseUrl}/rooms`, }; diff --git a/uniplanWeb/src/app/features/room/room-service.ts b/uniplanWeb/src/app/features/room/room-service.ts index eea6c27..217367e 100644 --- a/uniplanWeb/src/app/features/room/room-service.ts +++ b/uniplanWeb/src/app/features/room/room-service.ts @@ -4,20 +4,19 @@ import { map, Observable, shareReplay } from 'rxjs'; import { RoomViewModel } from '../../core/interfaces/room-view-model'; import { RoomElm } from '../../core/interfaces/room-elm'; import { Subject } from 'rxjs'; +import { API_ENDPOINTS } from '../../config/endpoints'; @Injectable({ providedIn: 'root' }) export class RoomService { - private apiUrl = 'http://localhost:8080/api/rooms'; - refreshNeeded = new Subject(); private http = inject(HttpClient); getRooms(): Observable { - return this.http.get(this.apiUrl).pipe( + return this.http.get(API_ENDPOINTS.rooms).pipe( map(rooms => rooms ?? []), map(rooms => rooms.map((room, index) => ({ @@ -35,7 +34,7 @@ export class RoomService { roomNumber: string; facultyId: string; }): Observable { - return this.http.post(`${this.apiUrl}`, room).pipe( + return this.http.post(`${(API_ENDPOINTS.rooms)}`, room).pipe( map((res) => { this.refreshNeeded.next(); return res; From 2966cfd94df128ceb21de8d104c3adb253e6cf43 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Wed, 1 Jul 2026 13:37:08 +0300 Subject: [PATCH 03/13] Add takeUntilDestroyed to subscriptions --- .../room/room-add-form/room-add-form.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index fab081f..50dcaa9 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -68,15 +68,17 @@ export class RoomAddForm implements OnInit { facultyId: this.addForm.value.facultyId ?? '', }; - this.roomService.createRoom(newRoom).subscribe({ - next: (response) => { - console.log('Room created:', response); - this.dialogRef.close(response); - }, - error: (err) => { - console.error('Failed to add room', err); - alert('Failed to add room.'); - }, - }); + this.roomService.createRoom(newRoom) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe({ + next: (response) => { + console.log('Room created:', response); + this.dialogRef.close(response); + }, + error: (err) => { + console.error('Failed to add room', err); + alert('Failed to add room.'); + }, + }); } } From 24741f1d651f2d6be7e3f46d98b1252b19b31e6d Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Thu, 2 Jul 2026 10:34:31 +0300 Subject: [PATCH 04/13] Add i18n to alert --- uniplanWeb/public/i18n/bg.json | 3 ++- uniplanWeb/public/i18n/en.json | 3 ++- .../src/app/features/room/room-add-form/room-add-form.ts | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/uniplanWeb/public/i18n/bg.json b/uniplanWeb/public/i18n/bg.json index fc90a42..352855c 100644 --- a/uniplanWeb/public/i18n/bg.json +++ b/uniplanWeb/public/i18n/bg.json @@ -15,7 +15,8 @@ "room-number": "Номер на стая", "no-rooms": "Няма записани стаи", "add": { - "title": "Добави стая" + "title": "Добави стая", + "failed": "Неуспешно добавяне на стаята." } }, "faculty": { diff --git a/uniplanWeb/public/i18n/en.json b/uniplanWeb/public/i18n/en.json index c008b79..ebc553d 100644 --- a/uniplanWeb/public/i18n/en.json +++ b/uniplanWeb/public/i18n/en.json @@ -15,7 +15,8 @@ "room-number": "Room number", "no-rooms": "No rooms", "add": { - "title": "Add room" + "title": "Add room", + "failed": "Failed to add room." } }, "faculty": { diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index 50dcaa9..62ac8d9 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -13,6 +13,7 @@ import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms'; import { FacultyElm } from '../../../core/interfaces/faculty-elm'; import { RoomService } from '../room-service'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-room-add-form', @@ -39,6 +40,7 @@ export class RoomAddForm implements OnInit { private roomService = inject(RoomService) faculties: FacultyElm[] = []; private destroyRef = inject(DestroyRef); + private translate = inject(TranslateService); addForm = new FormGroup({ roomNumber: new FormControl('', Validators.required), @@ -77,7 +79,7 @@ export class RoomAddForm implements OnInit { }, error: (err) => { console.error('Failed to add room', err); - alert('Failed to add room.'); + alert(this.translate.instant('room.add.failed')); }, }); } From c696e70f5078bcc0b703a91572cd4c7280b094a1 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Tue, 7 Jul 2026 12:58:39 +0300 Subject: [PATCH 05/13] Fix tests for room component --- .../features/room/room-add-form/room-add-form.spec.ts | 11 ++++++++--- .../features/room/room-options/room-options.spec.ts | 7 +++++-- .../app/features/room/room-panel/room-panel.spec.ts | 7 +++++-- .../app/features/room/room-table/room-table.spec.ts | 9 ++++++--- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts index eebb8bf..c121f51 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.spec.ts @@ -1,6 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - import { RoomAddForm } from './room-add-form'; +import { translateTestingProviders } from '@testing/translate-testing'; +import { MatDialogRef } from '@angular/material/dialog'; describe('RoomAddForm', () => { let component: RoomAddForm; @@ -8,9 +9,13 @@ describe('RoomAddForm', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [RoomAddForm] + imports: [RoomAddForm], + providers: [ + ...translateTestingProviders, + { provide: MatDialogRef, useValue: {} }, + ] }) - .compileComponents(); + .compileComponents(); fixture = TestBed.createComponent(RoomAddForm); component = fixture.componentInstance; diff --git a/uniplanWeb/src/app/features/room/room-options/room-options.spec.ts b/uniplanWeb/src/app/features/room/room-options/room-options.spec.ts index 0d5fbc2..0ac38d0 100644 --- a/uniplanWeb/src/app/features/room/room-options/room-options.spec.ts +++ b/uniplanWeb/src/app/features/room/room-options/room-options.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - import { RoomOptions } from './room-options'; +import { translateTestingProviders } from '@testing/translate-testing'; describe('RoomOptions', () => { let component: RoomOptions; @@ -8,7 +8,10 @@ describe('RoomOptions', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [RoomOptions] + imports: [RoomOptions], + providers: [ + ...translateTestingProviders + ] }) .compileComponents(); diff --git a/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts b/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts index 5dcff7f..2c0e32a 100644 --- a/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts +++ b/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - import { RoomPanel } from './room-panel'; +import { translateTestingProviders } from '@testing/translate-testing'; describe('RoomPanel', () => { let component: RoomPanel; @@ -8,7 +8,10 @@ describe('RoomPanel', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [RoomPanel] + imports: [RoomPanel], + providers: [ + ...translateTestingProviders, + ] }) .compileComponents(); diff --git a/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts b/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts index 5730503..06144f2 100644 --- a/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts +++ b/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - import { RoomTable } from './room-table'; +import { translateTestingProviders } from '@testing/translate-testing'; describe('RoomTable', () => { let component: RoomTable; @@ -8,9 +8,12 @@ describe('RoomTable', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [RoomTable] + imports: [RoomTable], + providers: [ + ...translateTestingProviders + ] }) - .compileComponents(); + .compileComponents(); fixture = TestBed.createComponent(RoomTable); component = fixture.componentInstance; From b08129ecb320e69341064d8c9606de2b6b5ac20e Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Tue, 7 Jul 2026 13:07:52 +0300 Subject: [PATCH 06/13] Resolve double submit issue --- .../features/room/room-add-form/room-add-form.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index 62ac8d9..3cb2520 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -14,6 +14,7 @@ import { FacultyElm } from '../../../core/interfaces/faculty-elm'; import { RoomService } from '../room-service'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { TranslateService } from '@ngx-translate/core'; +import { finalize } from 'rxjs'; @Component({ selector: 'app-room-add-form', @@ -41,6 +42,7 @@ export class RoomAddForm implements OnInit { faculties: FacultyElm[] = []; private destroyRef = inject(DestroyRef); private translate = inject(TranslateService); + private isSubmitting = false; addForm = new FormGroup({ roomNumber: new FormControl('', Validators.required), @@ -61,20 +63,26 @@ export class RoomAddForm implements OnInit { } save() { - if (this.addForm.invalid) { + if (this.addForm.invalid || this.isSubmitting) { return; } + this.isSubmitting = true; + this.addForm.disable(); + const newRoom = { roomNumber: this.addForm.value.roomNumber ?? '', facultyId: this.addForm.value.facultyId ?? '', }; this.roomService.createRoom(newRoom) - .pipe(takeUntilDestroyed(this.destroyRef)) + .pipe(takeUntilDestroyed(this.destroyRef), + finalize(() => { + this.isSubmitting = false; + this.addForm.enable(); + })) .subscribe({ next: (response) => { - console.log('Room created:', response); this.dialogRef.close(response); }, error: (err) => { From c2ddf083bba18f48d1e03484b7d84d718c9387da Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Tue, 7 Jul 2026 13:19:20 +0300 Subject: [PATCH 07/13] Replace alert with snack bar --- uniplanWeb/public/i18n/bg.json | 3 ++- uniplanWeb/public/i18n/en.json | 3 ++- .../app/features/room/room-add-form/room-add-form.ts | 11 ++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/uniplanWeb/public/i18n/bg.json b/uniplanWeb/public/i18n/bg.json index 352855c..4c84a8a 100644 --- a/uniplanWeb/public/i18n/bg.json +++ b/uniplanWeb/public/i18n/bg.json @@ -64,7 +64,8 @@ "save-button": "Запази", "delete-button": "Изтрий", "option-all": "Всички", - "confirm-delete": "Потвърдете изтриването" + "confirm-delete": "Потвърдете изтриването", + "close-btn": "Затвори" }, "home": { "title": "Начало!" diff --git a/uniplanWeb/public/i18n/en.json b/uniplanWeb/public/i18n/en.json index ebc553d..993ce63 100644 --- a/uniplanWeb/public/i18n/en.json +++ b/uniplanWeb/public/i18n/en.json @@ -64,7 +64,8 @@ "save-button": "Save", "delete-button": "Delete", "option-all": "All", - "confirm-delete": "Confirm deletion" + "confirm-delete": "Confirm deletion", + "close-btn": "Close" }, "home": { "title": "Main!" diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index 3cb2520..a289287 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -15,6 +15,7 @@ import { RoomService } from '../room-service'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { TranslateService } from '@ngx-translate/core'; import { finalize } from 'rxjs'; +import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ selector: 'app-room-add-form', @@ -43,6 +44,7 @@ export class RoomAddForm implements OnInit { private destroyRef = inject(DestroyRef); private translate = inject(TranslateService); private isSubmitting = false; + private _snackBar = inject(MatSnackBar); addForm = new FormGroup({ roomNumber: new FormControl('', Validators.required), @@ -62,6 +64,10 @@ export class RoomAddForm implements OnInit { }); } + openSnackBar(message: string, action: string) { + this._snackBar.open(message, action); + } + save() { if (this.addForm.invalid || this.isSubmitting) { return; @@ -87,7 +93,10 @@ export class RoomAddForm implements OnInit { }, error: (err) => { console.error('Failed to add room', err); - alert(this.translate.instant('room.add.failed')); + this.openSnackBar( + this.translate.instant('room.add.failed'), + this.translate.instant('shared.close-btn') + ); }, }); } From fa1374d7bd6862b44506fbbbec5a06bbfa400084 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Wed, 15 Jul 2026 13:02:43 +0300 Subject: [PATCH 08/13] Fix button position --- .../src/app/features/room/room-add-form/room-add-form.scss | 1 - .../src/app/features/room/room-options/room-options.scss | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss index 6f4bf98..9b05a56 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.scss @@ -12,4 +12,3 @@ input { border-radius: 10px; width: 100%; } - diff --git a/uniplanWeb/src/app/features/room/room-options/room-options.scss b/uniplanWeb/src/app/features/room/room-options/room-options.scss index e69de29..0c696e5 100644 --- a/uniplanWeb/src/app/features/room/room-options/room-options.scss +++ b/uniplanWeb/src/app/features/room/room-options/room-options.scss @@ -0,0 +1,5 @@ +.add-button { + display: block; + margin-top: 3.3%; + margin-bottom: 1.5%; +} \ No newline at end of file From 22921897615e2f5a3fa3c51978f05094aa094a86 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Wed, 15 Jul 2026 13:08:57 +0300 Subject: [PATCH 09/13] Optimized imports --- .../features/room/room-add-form/room-add-form.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index a289287..947c970 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -1,21 +1,18 @@ - import { Component, OnInit, ChangeDetectionStrategy, inject, DestroyRef } from '@angular/core'; -import { FormsModule, Validators } from '@angular/forms'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { Validators, FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms'; import { 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 { MatSnackBar } from '@angular/material/snack-bar'; +import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { finalize } from 'rxjs'; import { AddForm } from '../../../core/shared/add-form/add-form'; -import { TranslatePipe } from '@ngx-translate/core'; import { FacultyService } from '../../faculty/faculty-service'; -import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms'; import { FacultyElm } from '../../../core/interfaces/faculty-elm'; import { RoomService } from '../room-service'; -import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { TranslateService } from '@ngx-translate/core'; -import { finalize } from 'rxjs'; -import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ selector: 'app-room-add-form', @@ -26,7 +23,6 @@ import { MatSnackBar } from '@angular/material/snack-bar'; MatDialogModule, MatFormField, MatLabel, - FormsModule, MatInputModule, MatSelectModule, MatOptionModule, From 57b253db54f403f542fcebeab7c3046a3c78d896 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Wed, 15 Jul 2026 13:25:45 +0300 Subject: [PATCH 10/13] Add typed formGroup definitions --- .../src/app/features/room/room-add-form/room-add-form.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index 947c970..bb382b2 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -43,8 +43,8 @@ export class RoomAddForm implements OnInit { private _snackBar = inject(MatSnackBar); addForm = new FormGroup({ - roomNumber: new FormControl('', Validators.required), - facultyId: new FormControl('', Validators.required), + roomNumber: new FormControl('', Validators.required), + facultyId: new FormControl('', Validators.required), }); ngOnInit(): void { From bb93a150a29d0c3aab568df7dc2e527a10c5b763 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Wed, 15 Jul 2026 13:34:25 +0300 Subject: [PATCH 11/13] Add snackbar displaying error message --- uniplanWeb/public/i18n/bg.json | 3 +++ uniplanWeb/public/i18n/en.json | 3 +++ .../src/app/features/room/room-add-form/room-add-form.ts | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/uniplanWeb/public/i18n/bg.json b/uniplanWeb/public/i18n/bg.json index 4c84a8a..7ac66ea 100644 --- a/uniplanWeb/public/i18n/bg.json +++ b/uniplanWeb/public/i18n/bg.json @@ -29,6 +29,9 @@ }, "edit": { "title": "Редактирай факултет" + }, + "load":{ + "failed":"Неуспешно зареждане на факултети" } }, "major": { diff --git a/uniplanWeb/public/i18n/en.json b/uniplanWeb/public/i18n/en.json index 993ce63..c44c379 100644 --- a/uniplanWeb/public/i18n/en.json +++ b/uniplanWeb/public/i18n/en.json @@ -29,6 +29,9 @@ }, "edit": { "title": "Edit faculty" + }, + "load":{ + "failed":"Failed to load faculties" } }, "major": { diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index bb382b2..48b67bf 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -48,6 +48,10 @@ export class RoomAddForm implements OnInit { }); ngOnInit(): void { + this.openSnackBar( + this.translate.instant('faculty.load.failed'), + this.translate.instant('shared.close-btn') + ); this.facultyService.getFaculties() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ @@ -56,6 +60,10 @@ export class RoomAddForm implements OnInit { }, error: (err) => { console.error('Failed to load faculties', err); + this.openSnackBar( + this.translate.instant('faculty.load.failed'), + this.translate.instant('shared.close-btn') + ); }, }); } From 0b1b3a8e51dbd1d33543b8cf84d2dcb7d4c262e8 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Mon, 20 Jul 2026 11:06:58 +0300 Subject: [PATCH 12/13] Add return types to functions --- .../src/app/core/interfaces/course-elm.ts | 7 ++++ .../app/features/faculty/faculty-service.ts | 24 ++++++------ .../src/app/features/major/major-service.ts | 39 ++++++++++--------- .../room/room-add-form/room-add-form.ts | 8 +--- .../room/room-options/room-options.ts | 2 +- 5 files changed, 42 insertions(+), 38 deletions(-) create mode 100644 uniplanWeb/src/app/core/interfaces/course-elm.ts diff --git a/uniplanWeb/src/app/core/interfaces/course-elm.ts b/uniplanWeb/src/app/core/interfaces/course-elm.ts new file mode 100644 index 0000000..f63c510 --- /dev/null +++ b/uniplanWeb/src/app/core/interfaces/course-elm.ts @@ -0,0 +1,7 @@ +export interface CourseElm { + id: string; + majorId: string; + courseYear: number; + locaticourseTypeon: string; + courseSubtype: string; +} \ No newline at end of file diff --git a/uniplanWeb/src/app/features/faculty/faculty-service.ts b/uniplanWeb/src/app/features/faculty/faculty-service.ts index 1c423f0..bb4faa1 100644 --- a/uniplanWeb/src/app/features/faculty/faculty-service.ts +++ b/uniplanWeb/src/app/features/faculty/faculty-service.ts @@ -1,8 +1,8 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { map, Observable, Subject } from 'rxjs'; +import { map, Observable, Subject, tap } from 'rxjs'; import { FacultyElm } from '../../core/interfaces/faculty-elm'; -import {API_ENDPOINTS} from '../../config/endpoints'; +import { API_ENDPOINTS } from '../../config/endpoints'; @Injectable({ providedIn: 'root', @@ -10,7 +10,7 @@ import {API_ENDPOINTS} from '../../config/endpoints'; export class FacultyService { refreshNeeded = new Subject(); - constructor(private http: HttpClient) {} + constructor(private http: HttpClient) { } getFaculties(): Observable { return this.http.get(API_ENDPOINTS.faculties).pipe( @@ -30,9 +30,9 @@ export class FacultyService { universityId: string; facultyName: string; location: string; - }): Observable { - return this.http.post(`${API_ENDPOINTS.faculties}`, faculty).pipe( - map((res) => { + }): Observable { + return this.http.post(`${API_ENDPOINTS.faculties}`, faculty).pipe( + tap((res) => { this.refreshNeeded.next(); return res; }) @@ -46,18 +46,18 @@ export class FacultyService { facultyName: string; location: string; } - ): Observable { - return this.http.put(`${API_ENDPOINTS.faculties}/${id}`, updatedFaculty).pipe( - map((res) => { + ): Observable { + return this.http.put(`${API_ENDPOINTS.faculties}/${id}`, updatedFaculty).pipe( + tap((res) => { this.refreshNeeded.next(); return res; }) ); } - deleteFaculty(id: string): Observable { - return this.http.delete(`${API_ENDPOINTS.faculties}/${id}`).pipe( - map((res) => { + deleteFaculty(id: string): Observable { + return this.http.delete(`${API_ENDPOINTS.faculties}/${id}`).pipe( + tap((res) => { this.refreshNeeded.next(); return res; }) diff --git a/uniplanWeb/src/app/features/major/major-service.ts b/uniplanWeb/src/app/features/major/major-service.ts index c7a4626..97ee402 100644 --- a/uniplanWeb/src/app/features/major/major-service.ts +++ b/uniplanWeb/src/app/features/major/major-service.ts @@ -1,9 +1,9 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { map, Observable, Subject, switchMap } from 'rxjs'; +import { map, Observable, Subject, switchMap, tap } from 'rxjs'; import { MajorElm } from '../../core/interfaces/major-elm'; -import {environment} from '../../../environments/environment'; -import {API_ENDPOINTS} from '../../config/endpoints'; +import { API_ENDPOINTS } from '../../config/endpoints'; +import { CourseElm } from '../../core/interfaces/course-elm'; @Injectable({ providedIn: 'root', @@ -11,7 +11,7 @@ import {API_ENDPOINTS} from '../../config/endpoints'; export class MajorService { refreshNeeded = new Subject(); - constructor(private http: HttpClient) {} + constructor(private http: HttpClient) { } getMajors(): Observable { return this.http.get(API_ENDPOINTS.majors).pipe( @@ -32,8 +32,8 @@ export class MajorService { createMajor(createMajor: { facultyId: string; majorName: string; - }): Observable { - return this.http.post(`${API_ENDPOINTS.majors}`, createMajor).pipe( + }): Observable { + return this.http.post(`${API_ENDPOINTS.majors}`, createMajor).pipe( map((res) => { this.refreshNeeded.next(); return res; @@ -46,25 +46,26 @@ export class MajorService { courseYear: number; courseType: string; courseSubtype: string; - }): Observable { - return this.http.post(`${API_ENDPOINTS.courses}`, course).pipe( + }): Observable { + return this.http.post(`${API_ENDPOINTS.courses}`, course).pipe( map((res) => { this.refreshNeeded.next(); return res; }) ); } + createMajorWithCourse(majorData: { facultyId: string; majorName: string; type: string; subtype: string; - }): Observable { + }): Observable { return this.createMajor({ facultyId: majorData.facultyId, majorName: majorData.majorName, }).pipe( - switchMap((createdMajor: any) => { + switchMap((createdMajor) => { return this.createCourse({ majorId: createdMajor.id, courseType: majorData.type, @@ -75,20 +76,20 @@ export class MajorService { ); } - deleteMajor(id: string): Observable { - return this.http.delete(`${API_ENDPOINTS.majors}/${id}`).pipe( - map((res) => { + deleteMajor(id: string): Observable { + return this.http.delete(`${API_ENDPOINTS.majors}/${id}`).pipe( + tap((res) => { this.refreshNeeded.next(); return res; }) ); } - deleteCourse(courseId: string): Observable { - return this.http.delete(`${API_ENDPOINTS.courses}/${courseId}`); + deleteCourse(courseId: string): Observable { + return this.http.delete(`${API_ENDPOINTS.courses}/${courseId}`); } - deleteMajorWithCourse(major: MajorElm): Observable { + deleteMajorWithCourse(major: MajorElm): Observable { return this.deleteCourse(major.courseId).pipe( switchMap(() => this.deleteMajor(major.id)) ); @@ -97,9 +98,9 @@ export class MajorService { editMajor( id: string, updateMajor: { facultyId: string; majorName: string } - ): Observable { - return this.http.put(`${API_ENDPOINTS.majors}/${id}`, updateMajor).pipe( - map((res) => { + ): Observable { + return this.http.put(`${API_ENDPOINTS.majors}/${id}`, updateMajor).pipe( + tap((res) => { this.refreshNeeded.next(); return res; }) diff --git a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts index 48b67bf..0a4e4b9 100644 --- a/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts +++ b/uniplanWeb/src/app/features/room/room-add-form/room-add-form.ts @@ -48,10 +48,6 @@ export class RoomAddForm implements OnInit { }); ngOnInit(): void { - this.openSnackBar( - this.translate.instant('faculty.load.failed'), - this.translate.instant('shared.close-btn') - ); this.facultyService.getFaculties() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ @@ -68,11 +64,11 @@ export class RoomAddForm implements OnInit { }); } - openSnackBar(message: string, action: string) { + openSnackBar(message: string, action: string): void { this._snackBar.open(message, action); } - save() { + save(): void { if (this.addForm.invalid || this.isSubmitting) { return; } diff --git a/uniplanWeb/src/app/features/room/room-options/room-options.ts b/uniplanWeb/src/app/features/room/room-options/room-options.ts index 5fed7f2..b0340c1 100644 --- a/uniplanWeb/src/app/features/room/room-options/room-options.ts +++ b/uniplanWeb/src/app/features/room/room-options/room-options.ts @@ -20,7 +20,7 @@ import { RoomAddForm } from '../room-add-form/room-add-form'; }) export class RoomOptions { private dialog = inject(MatDialog) - openAddForm() { + openAddForm() : void { this.dialog.open(RoomAddForm, { width: '400px', }); From c1dc63f02ea2c58401da2e27e5d393cf0a82f7d4 Mon Sep 17 00:00:00 2001 From: PIPetkova19 Date: Mon, 20 Jul 2026 11:15:05 +0300 Subject: [PATCH 13/13] Remove unused imports from tests --- uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts | 1 - uniplanWeb/src/app/features/room/room-table/room-table.spec.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts b/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts index fd747b7..a20ed64 100644 --- a/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts +++ b/uniplanWeb/src/app/features/room/room-panel/room-panel.spec.ts @@ -1,7 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { translateTestingProviders } from '@testing/translate-testing'; import { RoomPanel } from './room-panel'; -import { translateTestingProviders } from '@testing/translate-testing'; describe('RoomPanel', () => { let component: RoomPanel; diff --git a/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts b/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts index 2fa8590..d8029a5 100644 --- a/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts +++ b/uniplanWeb/src/app/features/room/room-table/room-table.spec.ts @@ -1,7 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { translateTestingProviders } from '@testing/translate-testing'; import { RoomTable } from './room-table'; -import { translateTestingProviders } from '@testing/translate-testing'; describe('RoomTable', () => { let component: RoomTable;