frontend: add handling for closed room state with appropriate error messaging and UI updates

This commit is contained in:
juancarmore 2025-08-30 13:35:11 +02:00
parent 089877959a
commit 88e7002cab
6 changed files with 41 additions and 5 deletions

View File

@ -32,6 +32,9 @@ export const validateRoomAccessGuard: CanActivateFn = async (
case 404: case 404:
// Room not found // Room not found
return navigationService.redirectToErrorPage(ErrorReason.INVALID_ROOM); return navigationService.redirectToErrorPage(ErrorReason.INVALID_ROOM);
case 409:
// Room is closed
return navigationService.redirectToErrorPage(ErrorReason.CLOSED_ROOM);
default: default:
return navigationService.redirectToErrorPage(ErrorReason.INTERNAL_ERROR); return navigationService.redirectToErrorPage(ErrorReason.INTERNAL_ERROR);
} }

View File

@ -1,4 +1,5 @@
export enum ErrorReason { export enum ErrorReason {
CLOSED_ROOM = 'closed-room',
MISSING_ROOM_SECRET = 'missing-room-secret', MISSING_ROOM_SECRET = 'missing-room-secret',
MISSING_RECORDING_SECRET = 'missing-recording-secret', MISSING_RECORDING_SECRET = 'missing-recording-secret',
INVALID_ROOM_SECRET = 'invalid-room-secret', INVALID_ROOM_SECRET = 'invalid-room-secret',

View File

@ -50,6 +50,10 @@ export class ErrorComponent implements OnInit {
*/ */
private mapReasonToNameAndMessage(reason: string): { title: string; message: string } { private mapReasonToNameAndMessage(reason: string): { title: string; message: string } {
const reasonMap: { [key in ErrorReason]: { title: string; message: string } } = { const reasonMap: { [key in ErrorReason]: { title: string; message: string } } = {
[ErrorReason.CLOSED_ROOM]: {
title: 'Closed room',
message: 'The room you are trying to access is closed'
},
[ErrorReason.MISSING_ROOM_SECRET]: { [ErrorReason.MISSING_ROOM_SECRET]: {
title: 'Missing secret', title: 'Missing secret',
message: 'You need to provide a secret to join the room as a moderator or speaker' message: 'You need to provide a secret to join the room as a moderator or speaker'

View File

@ -215,12 +215,16 @@
<!-- Action Cards Grid --> <!-- Action Cards Grid -->
<div class="action-cards-grid"> <div class="action-cards-grid">
<!-- Join Room Card --> <!-- Join Room Card -->
<mat-card class="action-card primary-card fade-in"> <mat-card class="action-card primary-card fade-in" [ngClass]="{ 'room-closed-card': roomClosed }">
<mat-card-header class="card-header"> <mat-card-header class="card-header">
<mat-icon class="ov-room-icon card-icon">meeting_room</mat-icon> <mat-icon class="ov-room-icon card-icon">{{ roomClosed ? 'lock' : 'meeting_room' }}</mat-icon>
<div class="card-title-group"> <div class="card-title-group">
<mat-card-title>Join Meeting</mat-card-title> <mat-card-title>{{ roomClosed ? 'Room Closed' : 'Join Meeting' }}</mat-card-title>
<mat-card-subtitle>Enter the room and start connecting</mat-card-subtitle> <mat-card-subtitle>{{
roomClosed
? 'This room is currently closed and not accepting new participants'
: 'Enter the room and start connecting'
}}</mat-card-subtitle>
</div> </div>
</mat-card-header> </mat-card-header>
@ -250,7 +254,7 @@
id="participant-name-submit" id="participant-name-submit"
type="submit" type="submit"
class="join-button" class="join-button"
[disabled]="participantForm.invalid" [disabled]="participantForm.invalid || roomClosed"
> >
<span>Join Meeting</span> <span>Join Meeting</span>
</button> </button>

View File

@ -133,6 +133,16 @@
background: linear-gradient(135deg, var(--ov-meet-surface-color) 0%, var(--ov-meet-color-primary-light) 180%); background: linear-gradient(135deg, var(--ov-meet-surface-color) 0%, var(--ov-meet-color-primary-light) 180%);
color: var(--ov-meet-text-on-primary); color: var(--ov-meet-text-on-primary);
} }
&.room-closed-card {
.card-header {
background: linear-gradient(135deg, var(--ov-meet-surface-color) 0%, var(--ov-meet-color-warning) 180%);
.mat-icon {
color: var(--ov-meet-color-warning) !important;
}
}
}
} }
// Secondary Card - Recordings styling // Secondary Card - Recordings styling

View File

@ -1,4 +1,5 @@
import { Clipboard } from '@angular/cdk/clipboard'; import { Clipboard } from '@angular/cdk/clipboard';
import { CommonModule } from '@angular/common';
import { Component, OnInit, Signal } from '@angular/core'; import { Component, OnInit, Signal } from '@angular/core';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatButtonModule, MatIconButton } from '@angular/material/button'; import { MatButtonModule, MatIconButton } from '@angular/material/button';
@ -31,6 +32,7 @@ import {
import { import {
LeftEventReason, LeftEventReason,
MeetRoom, MeetRoom,
MeetRoomStatus,
ParticipantRole, ParticipantRole,
WebComponentEvent, WebComponentEvent,
WebComponentOutboundEventMessage WebComponentOutboundEventMessage
@ -65,6 +67,7 @@ import { Subject, takeUntil } from 'rxjs';
imports: [ imports: [
OpenViduComponentsUiModule, OpenViduComponentsUiModule,
ApiDirectiveModule, ApiDirectiveModule,
CommonModule,
MatFormFieldModule, MatFormFieldModule,
MatInputModule, MatInputModule,
FormsModule, FormsModule,
@ -87,6 +90,7 @@ export class MeetingComponent implements OnInit {
hasRecordings = false; hasRecordings = false;
showRecordingCard = false; showRecordingCard = false;
roomClosed = false;
showBackButton = true; showBackButton = true;
backButtonText = 'Back'; backButtonText = 'Back';
@ -137,6 +141,7 @@ export class MeetingComponent implements OnInit {
this.roomId = this.roomService.getRoomId(); this.roomId = this.roomService.getRoomId();
this.roomSecret = this.roomService.getRoomSecret(); this.roomSecret = this.roomService.getRoomSecret();
this.room = await this.roomService.getRoom(this.roomId); this.room = await this.roomService.getRoom(this.roomId);
this.roomClosed = this.room.status === MeetRoomStatus.CLOSED;
await this.setBackButtonText(); await this.setBackButtonText();
await this.checkForRecordings(); await this.checkForRecordings();
@ -218,6 +223,11 @@ export class MeetingComponent implements OnInit {
if (participantName) { if (participantName) {
this.participantForm.get('name')?.setValue(participantName); this.participantForm.get('name')?.setValue(participantName);
} }
// Disable the form if the room is closed
if (this.roomClosed) {
this.participantForm.disable();
}
} }
async goToRecordings() { async goToRecordings() {
@ -309,6 +319,10 @@ export class MeetingComponent implements OnInit {
// Room not found // Room not found
await this.navigationService.redirectToErrorPage(ErrorReason.INVALID_ROOM, true); await this.navigationService.redirectToErrorPage(ErrorReason.INVALID_ROOM, true);
break; break;
case 409:
// Room is closed
await this.navigationService.redirectToErrorPage(ErrorReason.CLOSED_ROOM, true);
break;
default: default:
await this.navigationService.redirectToErrorPage(ErrorReason.INTERNAL_ERROR, true); await this.navigationService.redirectToErrorPage(ErrorReason.INTERNAL_ERROR, true);
} }