frontend: improve leave redirect URL handling

This commit is contained in:
juancarmore 2025-09-11 21:37:34 +02:00
parent 52974b2883
commit f02fcb96a9
6 changed files with 65 additions and 34 deletions

View File

@ -1,7 +1,13 @@
import { inject } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivateFn } from '@angular/router';
import { ErrorReason } from '@lib/models';
import { NavigationService, ParticipantService, RoomService, SessionStorageService } from '@lib/services';
import {
AppDataService,
NavigationService,
ParticipantService,
RoomService,
SessionStorageService
} from '@lib/services';
import { WebComponentProperty } from '@lib/typings/ce/webcomponent/properties.model';
export const extractRoomQueryParamsGuard: CanActivateFn = (route: ActivatedRouteSnapshot) => {
@ -66,14 +72,28 @@ const extractParams = ({ params, queryParams }: ActivatedRouteSnapshot) => ({
/**
* Handles the leave redirect URL logic with automatic referrer detection
*/
const handleLeaveRedirectUrl = (leaveRedirectUrl: string) => {
const handleLeaveRedirectUrl = (leaveRedirectUrl: string | undefined) => {
const navigationService = inject(NavigationService);
const appDataService = inject(AppDataService);
const isEmbeddedMode = appDataService.isEmbeddedMode();
// Explicit valid URL provided - use as is
if (leaveRedirectUrl && isValidUrl(leaveRedirectUrl)) {
// If explicitly provided, use it
navigationService.setLeaveRedirectUrl(leaveRedirectUrl);
} else {
// Check if user came from another domain and auto-configure redirect
return;
}
// Absolute path provided in embedded mode - construct full URL
if (isEmbeddedMode && leaveRedirectUrl?.startsWith('/')) {
// If in embedded mode and a absolute path is provided, construct full URL based on parent origin
const parentUrl = document.referrer;
const parentOrigin = new URL(parentUrl).origin;
navigationService.setLeaveRedirectUrl(parentOrigin + leaveRedirectUrl);
return;
}
// Auto-detect from referrer (only if no explicit URL provided and not embedded)
if (!leaveRedirectUrl && !isEmbeddedMode) {
const autoRedirectUrl = getAutoRedirectUrl();
if (autoRedirectUrl) {
navigationService.setLeaveRedirectUrl(autoRedirectUrl);
@ -110,8 +130,6 @@ const getAutoRedirectUrl = (): string | null => {
};
const isValidUrl = (url: string) => {
if (!url) return false;
try {
new URL(url);
return true;

View File

@ -134,7 +134,7 @@ export class ErrorComponent implements OnInit {
const redirectTo = this.navService.getLeaveRedirectURL();
if (redirectTo) {
// Navigate to the specified redirect URL
await this.navService.redirectTo(redirectTo);
await this.navService.redirectToLeaveUrl();
return;
}

View File

@ -119,7 +119,7 @@ export class EndMeetingComponent implements OnInit {
const redirectTo = this.navService.getLeaveRedirectURL();
if (redirectTo) {
// Navigate to the specified redirect URL
await this.navService.redirectTo(redirectTo);
await this.navService.redirectToLeaveUrl();
return;
}

View File

@ -248,7 +248,7 @@ export class MeetingComponent implements OnInit {
const redirectTo = this.navigationService.getLeaveRedirectURL();
if (redirectTo) {
// Navigate to the specified redirect URL
await this.navigationService.redirectTo(redirectTo);
await this.navigationService.redirectToLeaveUrl();
return;
}

View File

@ -1,4 +1,3 @@
import { Location } from '@angular/common';
import { Injectable } from '@angular/core';
import { Params, Router, UrlTree } from '@angular/router';
import { ErrorReason } from '@lib/models';
@ -12,7 +11,6 @@ export class NavigationService {
constructor(
private router: Router,
private location: Location,
private sessionStorageService: SessionStorageService,
private appDataService: AppDataService
) {}
@ -31,6 +29,31 @@ export class NavigationService {
return this.leaveRedirectUrl;
}
/**
* Redirects the user to the leave redirect URL if set and valid.
*/
async redirectToLeaveUrl() {
const url = this.getLeaveRedirectURL();
if (!url) {
console.warn('No leave redirect URL set');
return;
}
const isExternalURL = /^https?:\/\//.test(url);
if (!isExternalURL) {
console.error('Leave redirect URL is not a valid external URL:', url);
return;
}
const isEmbeddedMode = this.appDataService.isEmbeddedMode();
if (isEmbeddedMode) {
// Change the top window location if in embedded mode
window.top!.location.href = url;
} else {
window.location.href = url;
}
}
/**
* Navigates to a specific route
*
@ -50,30 +73,16 @@ export class NavigationService {
}
/**
* Redirects to internal or external URLs
* Redirects to internal URL
*
* @param url - The URL to redirect to
*/
async redirectTo(url: string): Promise<void> {
const isExternalURL = /^https?:\/\//.test(url);
if (isExternalURL) {
console.log('Redirecting to external URL:', url);
if (this.appDataService.isEmbeddedMode()) {
// Change the top window location if in embedded mode
window.top!.location.href = url;
} else {
window.location.href = url;
}
} else {
console.log('Redirecting to internal route:', url);
try {
let urlTree = this.router.parseUrl(url);
await this.router.navigateByUrl(urlTree, { replaceUrl: true });
} catch (error) {
console.error('Error navigating to internal route:', error);
}
try {
let urlTree = this.router.parseUrl(url);
await this.router.navigateByUrl(urlTree, { replaceUrl: true });
} catch (error) {
console.error('Error navigating to internal route:', error);
}
}

View File

@ -16,7 +16,10 @@ export class ThemeService {
public readonly isDark = computed(() => this._currentTheme() === 'dark');
public readonly isLight = computed(() => this._currentTheme() === 'light');
constructor(@Inject(DOCUMENT) private document: Document, protected ovComponentsThemeService: OpenViduThemeService) {}
constructor(
@Inject(DOCUMENT) private document: Document,
protected ovComponentsThemeService: OpenViduThemeService
) {}
/**
* Initializes the theme based on:
@ -39,7 +42,8 @@ export class ThemeService {
*/
public toggleTheme(): void {
const newTheme: Theme = this._currentTheme() === 'light' ? 'dark' : 'light';
this.setTheme(newTheme); }
this.setTheme(newTheme);
}
/**
* Changes the current theme