From c304c9c7614128cde16029f1c8bb7a06b7768cf1 Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Thu, 17 Jul 2025 16:53:17 +0200 Subject: [PATCH] ov-components: add PreJoin directive to support custom pre-join templates in VideoconferenceComponent --- .../videoconference.component.html | 23 ++- .../videoconference.component.ts | 25 +++ ...idu-components-angular.directive.module.ts | 5 +- .../openvidu-components-angular.directive.ts | 194 ++++++++++++++++++ 4 files changed, 237 insertions(+), 10 deletions(-) diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html index 4c46fb25..4e9c5419 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html @@ -5,15 +5,20 @@
- + + + + + +
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts index 4fd618ee..b1402cfc 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts @@ -10,6 +10,7 @@ import { ParticipantPanelItemDirective, ParticipantPanelItemElementsDirective, ParticipantsPanelDirective, + PreJoinDirective, StreamDirective, ToolbarAdditionalButtonsDirective, ToolbarAdditionalPanelButtonsDirective, @@ -114,6 +115,12 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { */ @ContentChild(StreamDirective) externalStream: StreamDirective; + // *** PreJoin *** + /** + * @internal + */ + @ContentChild(PreJoinDirective) externalPreJoin: PreJoinDirective; + /** * @internal */ @@ -198,6 +205,10 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { * @internal */ openviduAngularStreamTemplate: TemplateRef; + /** + * @internal + */ + openviduAngularPreJoinTemplate: TemplateRef; /** * Provides event notifications that fire when the local participant is ready to join to the room. @@ -435,6 +446,7 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { this.setupToolbarTemplate(); this.setupPanelTemplate(); this.setupLayoutTemplate(); + this.setupPreJoinTemplate(); } /** @@ -576,6 +588,19 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { } } + /** + * @internal + */ + private setupPreJoinTemplate(): void { + if (this.externalPreJoin) { + this.log.d('Setting EXTERNAL PREJOIN'); + this.openviduAngularPreJoinTemplate = this.externalPreJoin.template; + } else { + this.log.d('Setting DEFAULT PREJOIN'); + // Keep the default behavior - no template is set + } + } + /** * @internal */ diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts index 7ba55d15..793f923d 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts @@ -12,7 +12,8 @@ import { ToolbarAdditionalPanelButtonsDirective, AdditionalPanelsDirective, ActivitiesPanelDirective, - BackgroundEffectsPanelDirective + BackgroundEffectsPanelDirective, + PreJoinDirective } from './openvidu-components-angular.directive'; @NgModule({ @@ -29,6 +30,7 @@ import { ToolbarAdditionalPanelButtonsDirective, ParticipantPanelItemElementsDirective, ActivitiesPanelDirective, + PreJoinDirective, // BackgroundEffectsPanelDirective ], exports: [ @@ -44,6 +46,7 @@ import { ToolbarAdditionalPanelButtonsDirective, ParticipantPanelItemElementsDirective, ActivitiesPanelDirective, + PreJoinDirective, // BackgroundEffectsPanelDirective ] }) diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts index 933ec53b..13bef658 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts @@ -1814,3 +1814,197 @@ export class StreamDirective { public container: ViewContainerRef ) {} } + +/** + * The ***ovPreJoin** directive empowers you to substitute the default pre-join component template with a custom one. + * This directive allows you to create a completely custom pre-join experience while maintaining the core functionality. + * + * In the example below, we demonstrate how to replace the pre-join template with a custom one that includes + * device selection and a custom join button. + * + * + * ```typescript + * import { HttpClient } from '@angular/common/http'; + * import { Component } from '@angular/core'; + * import { lastValueFrom } from 'rxjs'; + * import { FormsModule } from '@angular/forms'; + * + * import { + * DeviceService, + * ParticipantService, + * OpenViduComponentsModule, + * } from 'openvidu-components-angular'; + * + * @Component({ + * selector: 'app-root', + * template: ` + * + * + *
+ *

Join Meeting

+ *
+ * + * + *
+ *
+ *
+ * `, + * styles: ` + * .custom-prejoin { + * display: flex; + * flex-direction: column; + * align-items: center; + * justify-content: center; + * height: 100vh; + * background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + * color: white; + * } + * .prejoin-form { + * display: flex; + * flex-direction: column; + * gap: 20px; + * align-items: center; + * } + * .name-input { + * padding: 12px; + * border: none; + * border-radius: 8px; + * font-size: 16px; + * min-width: 250px; + * } + * .join-button { + * padding: 12px 24px; + * background: #4CAF50; + * color: white; + * border: none; + * border-radius: 8px; + * font-size: 16px; + * cursor: pointer; + * transition: background 0.3s; + * } + * .join-button:hover:not(:disabled) { + * background: #45a049; + * } + * .join-button:disabled { + * background: #cccccc; + * cursor: not-allowed; + * } + * `, + * standalone: true, + * imports: [OpenViduComponentsModule, FormsModule], + * }) + * export class AppComponent { + * // For local development, leave these variables empty + * // For production, configure them with correct URLs depending on your deployment + * APPLICATION_SERVER_URL = ''; + * LIVEKIT_URL = ''; + * + * // Define the name of the room and initialize the token variable + * roomName = 'custom-prejoin'; + * token!: string; + * participantName: string = ''; + * + * constructor( + * private httpClient: HttpClient, + * private deviceService: DeviceService, + * private participantService: ParticipantService + * ) { + * this.configureUrls(); + * } + * + * private configureUrls() { + * // If APPLICATION_SERVER_URL is not configured, use default value from local development + * if (!this.APPLICATION_SERVER_URL) { + * if (window.location.hostname === 'localhost') { + * this.APPLICATION_SERVER_URL = 'http://localhost:6080/'; + * } else { + * this.APPLICATION_SERVER_URL = + * 'https://' + window.location.hostname + ':6443/'; + * } + * } + * + * // If LIVEKIT_URL is not configured, use default value from local development + * if (!this.LIVEKIT_URL) { + * if (window.location.hostname === 'localhost') { + * this.LIVEKIT_URL = 'ws://localhost:7880/'; + * } else { + * this.LIVEKIT_URL = 'wss://' + window.location.hostname + ':7443/'; + * } + * } + * } + * + * // Function to request a token when a participant joins the room + * async onTokenRequested(participantName: string) { + * const { token } = await this.getToken(this.roomName, participantName); + * this.token = token; + * } + * + * // Function called when ready to join + * onReadyToJoin() { + * console.log('Ready to join the meeting'); + * } + * + * // Function to join the meeting + * async joinMeeting() { + * if (this.participantName.trim()) { + * // Request token with the participant name + * await this.onTokenRequested(this.participantName); + * } + * } + * + * // Function to get a token from the server + * getToken(roomName: string, participantName: string): Promise { + * try { + * // Send a POST request to the server to obtain a token + * return lastValueFrom( + * this.httpClient.post(this.APPLICATION_SERVER_URL + 'token', { + * roomName, + * participantName, + * }) + * ); + * } catch (error: any) { + * // Handle errors, e.g., if the server is not reachable + * if (error.status === 404) { + * throw { + * status: error.status, + * message: + * 'Cannot connect with the backend. ' + error.url + ' not found', + * }; + * } + * throw error; + * } + * } + * } + * + * ``` + * + * + * For a detailed tutorial on customizing the pre-join component, please visit [this link](https://openvidu.io/latest/docs/tutorials/angular-components/openvidu-custom-prejoin/). + */ + +@Directive({ + selector: '[ovPreJoin]', + standalone: false +}) +export class PreJoinDirective { + constructor( + public template: TemplateRef, + public container: ViewContainerRef + ) {} +}