frontend: refactored video-room component and renamed by meeting component
- Implemented EndMeetingComponent to handle user disconnection scenarios. - Created SCSS styles for the EndMeetingComponent to enhance UI/UX. - Updated MeetingComponent to manage participant interactions and room functionalities. - Added HTML structure for meeting access and participant form. - Integrated routing to replace DisconnectedComponent with EndMeetingComponent. - Added unit tests for MeetingComponent to ensure functionality.
This commit is contained in:
parent
91c9690953
commit
1617e2b9d6
@ -1,22 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DisconnectedComponent } from './disconnected.component';
|
||||
|
||||
describe('ParticipantDisconnectedComponent', () => {
|
||||
let component: DisconnectedComponent;
|
||||
let fixture: ComponentFixture<DisconnectedComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [DisconnectedComponent]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DisconnectedComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -6,9 +6,9 @@ export * from './console/recordings/recordings.component';
|
||||
export * from './console/rooms/rooms.component';
|
||||
export * from './console/rooms/room-wizard/room-wizard.component';
|
||||
export * from './console/users-permissions/users-permissions.component';
|
||||
export * from './disconnected/disconnected.component';
|
||||
export * from './meeting/end-meeting/end-meeting.component';
|
||||
export * from './error/error.component';
|
||||
export * from './login/login.component';
|
||||
export * from './room-recordings/room-recordings.component';
|
||||
export * from './video-room/video-room.component';
|
||||
export * from './meeting/meeting.component';
|
||||
export * from './view-recording/view-recording.component';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../../src/assets/styles/design-tokens';
|
||||
@import '../../../../../../../src/assets/styles/design-tokens';
|
||||
|
||||
.disconnected-container {
|
||||
@include ov-theme-transition;
|
||||
@ -8,13 +8,13 @@ import { AppDataService, AuthService, NavigationService, WebComponentManagerServ
|
||||
import { LeftEventReason } from '@lib/typings/ce';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-disconnected',
|
||||
selector: 'ov-end-meeting',
|
||||
standalone: true,
|
||||
imports: [CommonModule, MatCardModule, MatButtonModule, MatIconModule],
|
||||
templateUrl: './disconnected.component.html',
|
||||
styleUrl: './disconnected.component.scss'
|
||||
templateUrl: './end-meeting.component.html',
|
||||
styleUrl: './end-meeting.component.scss'
|
||||
})
|
||||
export class DisconnectedComponent implements OnInit {
|
||||
export class EndMeetingComponent implements OnInit {
|
||||
disconnectedTitle = 'You Left the Meeting';
|
||||
disconnectReason = 'You have successfully left the meeting';
|
||||
|
||||
@ -1,111 +1,4 @@
|
||||
@if (!showRoom) {
|
||||
<div class="ov-page-container">
|
||||
<div class="room-access-container fade-in">
|
||||
<!-- Header Section -->
|
||||
<div class="room-header">
|
||||
<mat-icon class="ov-room-icon room-icon">video_chat</mat-icon>
|
||||
<div class="room-info">
|
||||
<h1 class="room-title">{{ roomId }}</h1>
|
||||
<p class="room-subtitle">Choose how you want to proceed</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Cards Grid -->
|
||||
<div class="action-cards-grid">
|
||||
<!-- Join Room Card -->
|
||||
<mat-card class="action-card primary-card fade-in">
|
||||
<mat-card-header class="card-header">
|
||||
<mat-icon class="ov-room-icon card-icon">meeting_room</mat-icon>
|
||||
<div class="card-title-group">
|
||||
<mat-card-title>Join Meeting</mat-card-title>
|
||||
<mat-card-subtitle>Enter the room and start connecting</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content class="card-content">
|
||||
<form [formGroup]="participantForm" (ngSubmit)="submitAccessRoom()" class="join-form">
|
||||
<mat-form-field appearance="outline" class="name-field">
|
||||
<mat-label>Your display name</mat-label>
|
||||
<input
|
||||
id="participant-name-input"
|
||||
matInput
|
||||
placeholder="Enter your name"
|
||||
formControlName="name"
|
||||
required
|
||||
/>
|
||||
<mat-icon matSuffix class="ov-action-icon">person</mat-icon>
|
||||
@if (participantForm.get('name')?.hasError('minlength')) {
|
||||
<mat-error> The name must be at least <strong>4 characters</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('required')) {
|
||||
<mat-error> The name is <strong>required</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('participantExists')) {
|
||||
<mat-error>
|
||||
The name is already taken. <strong> Please choose another name </strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
id="participant-name-submit"
|
||||
type="submit"
|
||||
class="join-button"
|
||||
[disabled]="participantForm.invalid"
|
||||
>
|
||||
<span>Join Meeting</span>
|
||||
</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<!-- View Recordings Card -->
|
||||
@if (showRecordingCard) {
|
||||
<mat-card class="action-card secondary-card fade-in-delayed">
|
||||
<mat-card-header class="card-header">
|
||||
<mat-icon class="ov-recording-icon card-icon">video_library</mat-icon>
|
||||
<div class="card-title-group">
|
||||
<mat-card-title>View Recordings</mat-card-title>
|
||||
<mat-card-subtitle>Browse and manage past recordings</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content class="card-content">
|
||||
<div class="recordings-info">
|
||||
<p class="recordings-description">
|
||||
Access previously recorded meetings from this room. You can watch, download, or
|
||||
manage existing recordings.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
id="view-recordings-btn"
|
||||
mat-stroked-button
|
||||
color="accent"
|
||||
(click)="goToRecordings()"
|
||||
class="recordings-button"
|
||||
>
|
||||
<span>Browse Recordings</span>
|
||||
</button>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
@if (showBackButton) {
|
||||
<div class="quick-actions fade-in-delayed-more">
|
||||
<button mat-button class="quick-action-button" (click)="goBack()">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
<span>{{ backButtonText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
@if (showMeeting) {
|
||||
<ov-videoconference
|
||||
[token]="participantToken"
|
||||
[participantName]="participantName"
|
||||
@ -208,4 +101,112 @@
|
||||
</div>
|
||||
}
|
||||
</ov-videoconference>
|
||||
} @else {
|
||||
<!-- Move this logic to prejoin meeting page -->
|
||||
<div class="ov-page-container">
|
||||
<div class="room-access-container fade-in">
|
||||
<!-- Header Section -->
|
||||
<div class="room-header">
|
||||
<mat-icon class="ov-room-icon room-icon">video_chat</mat-icon>
|
||||
<div class="room-info">
|
||||
<h1 class="room-title">{{ roomId }}</h1>
|
||||
<p class="room-subtitle">Choose how you want to proceed</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Cards Grid -->
|
||||
<div class="action-cards-grid">
|
||||
<!-- Join Room Card -->
|
||||
<mat-card class="action-card primary-card fade-in">
|
||||
<mat-card-header class="card-header">
|
||||
<mat-icon class="ov-room-icon card-icon">meeting_room</mat-icon>
|
||||
<div class="card-title-group">
|
||||
<mat-card-title>Join Meeting</mat-card-title>
|
||||
<mat-card-subtitle>Enter the room and start connecting</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content class="card-content">
|
||||
<form [formGroup]="participantForm" (ngSubmit)="submitAccessMeeting()" class="join-form">
|
||||
<mat-form-field appearance="outline" class="name-field">
|
||||
<mat-label>Your display name</mat-label>
|
||||
<input
|
||||
id="participant-name-input"
|
||||
matInput
|
||||
placeholder="Enter your name"
|
||||
formControlName="name"
|
||||
required
|
||||
/>
|
||||
<mat-icon matSuffix class="ov-action-icon">person</mat-icon>
|
||||
@if (participantForm.get('name')?.hasError('minlength')) {
|
||||
<mat-error> The name must be at least <strong>4 characters</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('required')) {
|
||||
<mat-error> The name is <strong>required</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('participantExists')) {
|
||||
<mat-error>
|
||||
The name is already taken. <strong> Please choose another name </strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
id="participant-name-submit"
|
||||
type="submit"
|
||||
class="join-button"
|
||||
[disabled]="participantForm.invalid"
|
||||
>
|
||||
<span>Join Meeting</span>
|
||||
</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<!-- View Recordings Card -->
|
||||
@if (showRecordingCard) {
|
||||
<mat-card class="action-card secondary-card fade-in-delayed">
|
||||
<mat-card-header class="card-header">
|
||||
<mat-icon class="ov-recording-icon card-icon">video_library</mat-icon>
|
||||
<div class="card-title-group">
|
||||
<mat-card-title>View Recordings</mat-card-title>
|
||||
<mat-card-subtitle>Browse and manage past recordings</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content class="card-content">
|
||||
<div class="recordings-info">
|
||||
<p class="recordings-description">
|
||||
Access previously recorded meetings from this room. You can watch, download, or
|
||||
manage existing recordings.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
id="view-recordings-btn"
|
||||
mat-stroked-button
|
||||
color="accent"
|
||||
(click)="goToRecordings()"
|
||||
class="recordings-button"
|
||||
>
|
||||
<span>Browse Recordings</span>
|
||||
</button>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
@if (showBackButton) {
|
||||
<div class="quick-actions fade-in-delayed-more">
|
||||
<button mat-button class="quick-action-button" (click)="goBack()">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
<span>{{ backButtonText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@ -1,18 +1,18 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { VideoRoomComponent } from './video-room.component';
|
||||
import { MeetingComponent } from './meeting.component';
|
||||
|
||||
describe('CallComponent', () => {
|
||||
let component: VideoRoomComponent;
|
||||
let fixture: ComponentFixture<VideoRoomComponent>;
|
||||
let component: MeetingComponent;
|
||||
let fixture: ComponentFixture<MeetingComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [VideoRoomComponent]
|
||||
imports: [MeetingComponent]
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(VideoRoomComponent);
|
||||
fixture = TestBed.createComponent(MeetingComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@ -51,9 +51,9 @@ import {
|
||||
} from 'openvidu-components-angular';
|
||||
|
||||
@Component({
|
||||
selector: 'app-video-room',
|
||||
templateUrl: './video-room.component.html',
|
||||
styleUrls: ['./video-room.component.scss'],
|
||||
selector: 'app-meeting',
|
||||
templateUrl: './meeting.component.html',
|
||||
styleUrls: ['./meeting.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
OpenViduComponentsUiModule,
|
||||
@ -72,7 +72,7 @@ import {
|
||||
MatRippleModule
|
||||
]
|
||||
})
|
||||
export class VideoRoomComponent implements OnInit {
|
||||
export class MeetingComponent implements OnInit {
|
||||
participantForm = new FormGroup({
|
||||
name: new FormControl('', [Validators.required, Validators.minLength(4)])
|
||||
});
|
||||
@ -88,7 +88,7 @@ export class VideoRoomComponent implements OnInit {
|
||||
participantToken = '';
|
||||
participantRole: ParticipantRole = ParticipantRole.PUBLISHER;
|
||||
|
||||
showRoom = false;
|
||||
showMeeting = false;
|
||||
features: Signal<ApplicationFeatures>;
|
||||
meetingEndedByMe = false;
|
||||
|
||||
@ -216,11 +216,11 @@ export class VideoRoomComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
async submitAccessRoom() {
|
||||
async submitAccessMeeting() {
|
||||
const { valid, value } = this.participantForm;
|
||||
if (!valid || !value.name?.trim()) {
|
||||
// If the form is invalid, do not proceed
|
||||
console.warn('Participant form is invalid. Cannot access room.');
|
||||
console.warn('Participant form is invalid. Cannot access meeting.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -231,14 +231,14 @@ export class VideoRoomComponent implements OnInit {
|
||||
await this.generateParticipantToken();
|
||||
await this.addParticipantNameToUrl();
|
||||
await this.roomService.loadPreferences(this.roomId);
|
||||
this.showRoom = true;
|
||||
this.showMeeting = true;
|
||||
} catch (error) {
|
||||
console.error('Error accessing room:', error);
|
||||
console.error('Error accessing meeting:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a participant token for joining a video room.
|
||||
* Generates a participant token for joining a meeting.
|
||||
*
|
||||
* @throws When participant already exists in the room (status 409)
|
||||
* @returns Promise that resolves when token is generated
|
||||
@ -13,7 +13,7 @@ import {
|
||||
import {
|
||||
ConsoleComponent,
|
||||
DevelopersSettingsComponent,
|
||||
DisconnectedComponent,
|
||||
EndMeetingComponent,
|
||||
ErrorComponent,
|
||||
LoginComponent,
|
||||
OverviewComponent,
|
||||
@ -22,7 +22,7 @@ import {
|
||||
RoomsComponent,
|
||||
RoomWizardComponent,
|
||||
UsersPermissionsComponent,
|
||||
VideoRoomComponent,
|
||||
MeetingComponent,
|
||||
ViewRecordingComponent
|
||||
} from '@lib/pages';
|
||||
|
||||
@ -34,7 +34,7 @@ export const baseRoutes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'room/:room-id',
|
||||
component: VideoRoomComponent,
|
||||
component: MeetingComponent,
|
||||
canActivate: [
|
||||
runGuardsSerially(extractRoomQueryParamsGuard, checkParticipantRoleAndAuthGuard, removeRoomSecretGuard)
|
||||
]
|
||||
@ -56,7 +56,7 @@ export const baseRoutes: Routes = [
|
||||
component: ViewRecordingComponent,
|
||||
canActivate: [checkRecordingAuthGuard]
|
||||
},
|
||||
{ path: 'disconnected', component: DisconnectedComponent },
|
||||
{ path: 'disconnected', component: EndMeetingComponent },
|
||||
{ path: 'error', component: ErrorComponent },
|
||||
{
|
||||
path: '',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user