From fdc93e4f197c8a1afeb28e7f339dc86494811ca7 Mon Sep 17 00:00:00 2001 From: juancarmore Date: Tue, 17 Jun 2025 15:11:49 +0200 Subject: [PATCH] frontend: enhance view recording component with error handling and status messages --- .../room-recordings.component.ts | 4 +- .../view-recording.component.html | 63 ++++++++++++++----- .../view-recording.component.scss | 32 ++++++++++ .../view-recording.component.ts | 41 ++++++++---- 4 files changed, 111 insertions(+), 29 deletions(-) diff --git a/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts index 0295f93..13286f5 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/room-recordings/room-recordings.component.ts @@ -108,7 +108,9 @@ export class RoomRecordingsComponent implements OnInit { openShareDialog(recording: MeetRecordingInfo) { this.dialog.open(ShareRecordingDialogComponent, { width: '400px', - data: { recordingId: recording.recordingId } + data: { + recordingId: recording.recordingId + } }); } diff --git a/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.html b/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.html index 9d6791c..3aedbfc 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.html +++ b/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.html @@ -1,25 +1,58 @@ -@if (recording && recordingUrl) { +@if (recording) { -
- -
+ @if (recordingUrl) { + @if (!videoError) { +
+ +
+ } @else { +
+ error + Error loading video. Please try again later. +
+ } + } @else { + @if (['STARTING', 'ACTIVE', 'ENDING'].includes(recording.status)) { +
+ hourglass_empty + Recording is still in progress... +
+ } @else { +
+ error_outline + Recording has failed +
+ } + }

{{ recording.roomId }}

{{ recording.startDate | date: 'M/d/yy, H:mm' }} -
- - -
+ @if (recordingUrl && !videoError) { +
+ + +
+ }
+} @else { +
+ +
} diff --git a/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.scss index f6d4610..4b8cd22 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.scss +++ b/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.scss @@ -1,3 +1,10 @@ +.loader-container { + display: flex; + justify-content: center; + align-items: center; + height: 60vh; +} + .recording-container { max-width: 900px; margin: 20px auto; @@ -18,6 +25,31 @@ height: 100%; } +.status-message { + display: flex; + align-items: center; + gap: 8px; + color: #555; + font-size: 1.1rem; + padding: 20px; +} + +.status-message.error { + color: #d32f2f; +} + +.video-error { + display: flex; + align-items: center; + gap: 8px; + padding: 16px; + background-color: #fbe9e7; + border: 1px solid #ef9a9a; + color: #c62828; + border-radius: 4px; + margin-bottom: 10px; +} + .title { font-size: 1.8rem; font-weight: 600; diff --git a/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.ts index 35d0cb1..01f0ebd 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/view-recording/view-recording.component.ts @@ -4,25 +4,29 @@ import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatDialog } from '@angular/material/dialog'; import { MatIconModule } from '@angular/material/icon'; -import { ActivatedRoute } from '@angular/router'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { ActivatedRoute, Router } from '@angular/router'; import { ShareRecordingDialogComponent } from '@lib/components'; import { HttpService } from '@lib/services'; -import { ActionService, MeetRecordingInfo } from 'shared-meet-components'; +import { ActionService, MeetRecordingInfo, MeetRecordingStatus } from 'shared-meet-components'; @Component({ selector: 'app-view-recording', templateUrl: './view-recording.component.html', styleUrls: ['./view-recording.component.scss'], standalone: true, - imports: [MatCardModule, MatButtonModule, MatIconModule, DatePipe] + imports: [MatCardModule, MatButtonModule, MatIconModule, DatePipe, MatProgressSpinnerModule] }) export class ViewRecordingComponent implements OnInit { - recording: MeetRecordingInfo | undefined; - recordingUrl: string | undefined; + recording?: MeetRecordingInfo; + recordingUrl?: string; + + videoError = false; constructor( protected httpService: HttpService, protected actionService: ActionService, + protected router: Router, protected route: ActivatedRoute, protected dialog: MatDialog ) {} @@ -31,18 +35,26 @@ export class ViewRecordingComponent implements OnInit { const recordingId = this.route.snapshot.paramMap.get('recording-id'); const secret = this.route.snapshot.queryParams['secret']; - this.recording = await this.httpService.getRecording(recordingId!, secret!); - this.playRecording(); - } + try { + this.recording = await this.httpService.getRecording(recordingId!, secret!); - playRecording() { - this.recordingUrl = this.httpService.getRecordingMediaUrl(this.recording!.recordingId); + if (this.recording.status === MeetRecordingStatus.COMPLETE) { + this.recordingUrl = this.httpService.getRecordingMediaUrl(this.recording!.recordingId); + } + } catch (error) { + console.error('Error fetching recording:', error); + } } downloadRecording() { + if (!this.recording || !this.recordingUrl) { + console.error('Recording is not available for download'); + return; + } + const link = document.createElement('a'); - link.href = this.recordingUrl!; - link.download = this.recording!.filename || 'openvidu-recording.mp4'; + link.href = this.recordingUrl; + link.download = this.recording.filename || 'openvidu-recording.mp4'; link.dispatchEvent( new MouseEvent('click', { bubbles: true, @@ -58,7 +70,10 @@ export class ViewRecordingComponent implements OnInit { openShareDialog() { this.dialog.open(ShareRecordingDialogComponent, { width: '400px', - data: { recordingId: this.recording!.recordingId } + data: { + recordingId: this.recording!.recordingId, + recordingUrl: window.location.href + } }); } }