From 91c9690953f95b20dbd5e7f893fe9509d02e7350 Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Mon, 28 Jul 2025 14:59:56 +0200 Subject: [PATCH] frontend: Implement basic room creation component and integrate with room wizard - Added RoomBasicCreationComponent for creating a room with optional name prefix. - Integrated basic creation into RoomWizardComponent, allowing users to switch to advanced mode. - Updated wizard navigation to include 'back' functionality and adjusted visibility of navigation buttons. - Created RoomDetailsComponent for configuring room details, including auto-deletion date and time. - Enhanced styling for new components and ensured responsive design. - Updated wizard state service to manage new steps and handle edit mode appropriately. --- .../wizard-nav/wizard-nav.component.html | 14 ++ .../wizard-nav/wizard-nav.component.scss | 8 +- .../wizard-nav/wizard-nav.component.ts | 16 +- .../src/lib/models/wizard.model.ts | 5 +- .../room-basic-creation.component.html | 53 +++++ .../room-basic-creation.component.scss | 174 ++++++++++++++ .../room-basic-creation.component.ts | 61 +++++ .../room-wizard/room-wizard.component.html | 89 ++++--- .../room-wizard/room-wizard.component.scss | 26 ++- .../room-wizard/room-wizard.component.ts | 38 ++- .../room-details.component.html} | 16 +- .../room-details.component.scss} | 8 +- .../room-details.component.spec.ts} | 10 +- .../room-details.component.ts} | 22 +- .../pages/console/rooms/rooms.component.scss | 219 ------------------ .../src/lib/services/wizard-state.service.ts | 19 +- 16 files changed, 479 insertions(+), 299 deletions(-) create mode 100644 frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.html create mode 100644 frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.scss create mode 100644 frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.ts rename frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/{basic-info/basic-info.component.html => room-details/room-details.component.html} (86%) rename frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/{basic-info/basic-info.component.scss => room-details/room-details.component.scss} (97%) rename frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/{basic-info/basic-info.component.spec.ts => room-details/room-details.component.spec.ts} (54%) rename frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/{basic-info/basic-info.component.ts => room-details/room-details.component.ts} (83%) diff --git a/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.html b/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.html index f85f307..354b257 100644 --- a/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.html +++ b/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.html @@ -14,6 +14,20 @@ } + @if (config.showBack) { + + + } +
diff --git a/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.scss b/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.scss index ca96850..fdbf3a5 100644 --- a/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.scss +++ b/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.scss @@ -15,7 +15,7 @@ flex: 1; } - .cancel-btn { + .cancel-btn, .back-btn { margin-right: auto; } @@ -38,7 +38,7 @@ margin-right: 0; } - &.cancel-btn { + &.cancel-btn, &.back-btn { color: var(--ov-meet-text-secondary); border-color: var(--ov-meet-border-color-strong); @@ -127,7 +127,7 @@ flex-direction: column; gap: var(--ov-meet-spacing-md); - .cancel-btn { + .cancel-btn, .back-btn { margin-right: 0; order: 3; width: 100%; @@ -171,7 +171,7 @@ } &.loading { - button:not(.cancel-btn) { + button:not(.cancel-btn):not(.back-btn) { pointer-events: none; opacity: 0.7; diff --git a/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.ts b/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.ts index 181247c..a3aae66 100644 --- a/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/components/wizard-nav/wizard-nav.component.ts @@ -17,7 +17,8 @@ export class WizardNavComponent { @Input() config: WizardNavigationConfig = { showPrevious: false, showNext: true, - showCancel: true, + showCancel: false, + showBack: true, showFinish: false, showSkipAndFinish: false, disableFinish: false, @@ -27,6 +28,8 @@ export class WizardNavComponent { finishLabel: 'Finish' }; + @Input() backButtonText: string = 'Back'; + /** * Current step identifier for context */ @@ -38,6 +41,7 @@ export class WizardNavComponent { @Output() previous = new EventEmitter(); @Output() next = new EventEmitter(); @Output() cancel = new EventEmitter(); + @Output() back = new EventEmitter(); @Output() finish = new EventEmitter(); /** @@ -78,6 +82,16 @@ export class WizardNavComponent { this.navigate.emit(event); } + onBack() { + if (!this.config.showBack) return; + const event: WizardNavigationEvent = { + action: 'back', + currentStepIndex: this.currentStepId + }; + this.back.emit(event); + this.navigate.emit(event); + } + onFinish() { if (!this.config.showFinish) return; diff --git a/frontend/projects/shared-meet-components/src/lib/models/wizard.model.ts b/frontend/projects/shared-meet-components/src/lib/models/wizard.model.ts index ef83d36..b256cc5 100644 --- a/frontend/projects/shared-meet-components/src/lib/models/wizard.model.ts +++ b/frontend/projects/shared-meet-components/src/lib/models/wizard.model.ts @@ -19,7 +19,10 @@ export interface WizardNavigationConfig { // Button visibility flags showPrevious: boolean; showNext: boolean; + // Cancel button visibility showCancel: boolean; + // Used for going back to the previous page + showBack: boolean; showFinish: boolean; showSkipAndFinish: boolean; // Used for quick create actions disableFinish?: boolean; @@ -36,6 +39,6 @@ export interface WizardNavigationConfig { * Event interface for wizard navigation actions */ export interface WizardNavigationEvent { - action: 'next' | 'previous' | 'cancel' | 'finish'; + action: 'next' | 'previous' | 'cancel' | 'finish' | 'back'; currentStepIndex?: number; } diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.html b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.html new file mode 100644 index 0000000..56a0744 --- /dev/null +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.html @@ -0,0 +1,53 @@ +
+ + + + +
+
+ + + Room Name Prefix + + label + Optional prefix for room names. Leave empty for default naming. + @if (roomCreationForm.get('roomIdPrefix')?.hasError('maxlength')) { + Room name prefix cannot exceed 50 characters + } + + + +
+ + + +
+
+
+
\ No newline at end of file diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.scss new file mode 100644 index 0000000..4d8ba35 --- /dev/null +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.scss @@ -0,0 +1,174 @@ +@import '../../../../../../../../src/assets/styles/design-tokens'; + +.room-basic-creation-page { + @include ov-page-content; + @include ov-container; + + padding: var(--ov-meet-spacing-xl); + max-width: 600px; + margin: 0 auto; + + .page-header { + display: flex; + align-items: flex-start; + gap: var(--ov-meet-spacing-md); + margin-bottom: var(--ov-meet-spacing-xl); + + .page-icon { + @include ov-icon(xxl); + color: var(--ov-meet-icon-rooms); + margin-top: var(--ov-meet-spacing-xs); + } + + .page-title-group { + flex: 1; + + .page-title { + margin: 0 0 var(--ov-meet-spacing-sm) 0; + font-size: var(--ov-meet-font-size-xxl); + font-weight: var(--ov-meet-font-weight-medium); + color: var(--ov-meet-text-primary); + line-height: var(--ov-meet-line-height-tight); + } + + .page-description { + margin: 0; + font-size: var(--ov-meet-font-size-lg); + color: var(--ov-meet-text-secondary); + line-height: var(--ov-meet-line-height-normal); + } + } + } + + .page-content { + .room-basic-creation-form { + display: flex; + flex-direction: column; + gap: var(--ov-meet-spacing-xl); + + .form-field { + width: 100%; + + // Material form field customization using existing system + ::ng-deep { + .mat-mdc-form-field-outline { + border-radius: var(--ov-meet-radius-sm); + } + + .mat-mdc-form-field-label { + color: var(--ov-meet-text-secondary); + } + + .mat-mdc-form-field-hint { + color: var(--ov-meet-text-hint); + font-size: var(--ov-meet-font-size-xs); + } + + // Icon styling in form fields + .mat-mdc-form-field-icon-suffix { + mat-icon { + @include ov-icon(sm); + } + } + } + } + + .action-buttons { + display: flex; + gap: var(--ov-meet-spacing-md); + justify-content: center; + align-items: center; + margin-top: var(--ov-meet-spacing-lg); + + .create-button { + @include ov-button-base; + flex: 1; + max-width: 200px; + background-color: var(--ov-meet-color-success); + color: var(--ov-meet-text-on-primary); + box-shadow: var(--ov-meet-shadow-sm); + + mat-icon { + @include ov-icon(sm); + margin-right: var(--ov-meet-spacing-xs); + } + + span { + font-size: var(--ov-meet-font-size-md); + font-weight: var(--ov-meet-font-weight-medium); + } + } + + .advanced-button { + @include ov-button-base; + flex: 1; + max-width: 200px; + + mat-icon { + @include ov-icon(sm); + margin-right: var(--ov-meet-spacing-xs); + } + + span { + font-size: var(--ov-meet-font-size-md); + font-weight: var(--ov-meet-font-weight-normal); + } + } + } + } + } + + @include ov-mobile-down { + padding: var(--ov-meet-spacing-lg); + + .page-header { + flex-direction: column; + text-align: center; + gap: var(--ov-meet-spacing-sm); + + .page-icon { + align-self: center; + margin-top: 0; + } + + .page-title-group { + .page-title { + font-size: var(--ov-meet-font-size-xl); + } + + .page-description { + font-size: var(--ov-meet-font-size-md); + } + } + } + + .page-content { + .room-basic-creation-form { + .action-buttons { + flex-direction: column; + + .create-button, + .advanced-button { + max-width: none; + width: 100%; + } + } + } + } + } + + @include ov-tablet-down { + .page-content { + .room-basic-creation-form { + .action-buttons { + flex-direction: column; + + .create-button, + .advanced-button { + max-width: none; + } + } + } + } + } +} diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.ts new file mode 100644 index 0000000..5fadda7 --- /dev/null +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-basic-creation/room-basic-creation.component.ts @@ -0,0 +1,61 @@ +import { Component, OnDestroy, Output, EventEmitter } from '@angular/core'; +import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'ov-room-basic-creation', + standalone: true, + imports: [ + ReactiveFormsModule, + MatButtonModule, + MatIconModule, + MatInputModule, + MatFormFieldModule, + MatTooltipModule + ], + templateUrl: './room-basic-creation.component.html', + styleUrl: './room-basic-creation.component.scss' +}) +export class RoomBasicCreationComponent implements OnDestroy { + @Output() createRoom = new EventEmitter(); + @Output() openAdvancedMode = new EventEmitter(); + + roomCreationForm: FormGroup; + + private destroy$ = new Subject(); + + constructor(private fb: FormBuilder) { + this.roomCreationForm = this.fb.group({ + roomIdPrefix: ['', [Validators.maxLength(50)]] + }); + + this.roomCreationForm.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => { + // Optional: Save form data to local storage or service if needed + }); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + onCreateRoom() { + if (this.roomCreationForm.valid) { + const formValue = this.roomCreationForm.value; + this.createRoom.emit(formValue.roomIdPrefix || undefined); + } + } + + onOpenAdvancedMode() { + this.openAdvancedMode.emit(); + } + + get isFormValid(): boolean { + return this.roomCreationForm.valid && !this.roomCreationForm.pending; + } +} diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html index b76796e..f2ba9c9 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.html @@ -6,14 +6,16 @@ editMode ? 'Edit your room settings' : 'Create and configure your video room in a few simple steps' }}

- - + @if (!isBasicCreation()) { + + + }
@@ -41,21 +43,30 @@ } @else { - @switch (currentStep()?.id) { - @case ('basic') { - - } - @case ('recording') { - - } - @case ('recordingTrigger') { - - } - @case ('recordingLayout') { - - } - @case ('preferences') { - + @if (isBasicCreation()) { + + + } @else { + + @switch (currentStep()?.id) { + @case ('roomDetails') { + + } + @case ('recording') { + + } + @case ('recordingTrigger') { + + } + @case ('recordingLayout') { + + } + @case ('preferences') { + + } } } } @@ -63,15 +74,29 @@
- - + @if (isBasicCreation()) { +
+ +
+ } @else { + + + }
} diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.scss index d50b069..548c478 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.scss +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.scss @@ -5,6 +5,7 @@ @include ov-page-content; min-height: 600px; gap: 0; + padding-top: 0; } .wizard-header { @@ -37,7 +38,30 @@ } .wizard-footer { - margin-top: auto; + flex: 1; + display: flex; + justify-content: center; + .basic-nav, + .wizard-nav { + width: 100%; + max-width: 650px; + display: flex; + flex-direction: column; + } + + .basic-nav .wizard-navigation { + padding: var(--ov-meet-spacing-md) 0 0 0; + } + .cancel-button { + @include ov-button-base; + border-radius: var(--ov-meet-radius-sm); + min-width: 120px; + color: var(--ov-meet-text-secondary); + border-color: var(--ov-meet-border-color-strong); + &:hover { + background-color: var(--ov-meet-surface-hover); + } + } } .toggle-label { diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.ts index 54fc84d..b5c63c6 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/room-wizard.component.ts @@ -9,11 +9,12 @@ import { StepIndicatorComponent, WizardNavComponent } from '@lib/components'; import { WizardNavigationConfig, WizardStep } from '@lib/models'; import { NavigationService, NotificationService, RoomService, RoomWizardStateService } from '@lib/services'; import { MeetRoomOptions } from '@lib/typings/ce'; -import { RoomWizardBasicInfoComponent } from './steps/basic-info/basic-info.component'; +import { RoomWizardRoomDetailsComponent } from './steps/room-details/room-details.component'; import { RecordingLayoutComponent } from './steps/recording-layout/recording-layout.component'; import { RecordingPreferencesComponent } from './steps/recording-preferences/recording-preferences.component'; import { RecordingTriggerComponent } from './steps/recording-trigger/recording-trigger.component'; import { RoomPreferencesComponent } from './steps/room-preferences/room-preferences.component'; +import { RoomBasicCreationComponent } from '../room-basic-creation/room-basic-creation.component'; @Component({ selector: 'ov-room-wizard', @@ -26,7 +27,8 @@ import { RoomPreferencesComponent } from './steps/room-preferences/room-preferen MatIconModule, MatProgressSpinnerModule, MatSlideToggleModule, - RoomWizardBasicInfoComponent, + RoomBasicCreationComponent, + RoomWizardRoomDetailsComponent, RecordingPreferencesComponent, RecordingTriggerComponent, RecordingLayoutComponent, @@ -38,9 +40,9 @@ import { RoomPreferencesComponent } from './steps/room-preferences/room-preferen export class RoomWizardComponent implements OnInit { editMode: boolean = false; roomId?: string; - existingRoomData?: MeetRoomOptions; + existingRoomData?: MeetRoomOptions; // Edit mode isCreatingRoom = signal(false); - + isBasicCreation = signal(true); steps: Signal; currentStep: Signal; currentStepIndex: Signal; @@ -89,6 +91,9 @@ export class RoomWizardComponent implements OnInit { try { const { roomIdPrefix, autoDeletionDate, preferences } = await this.roomService.getRoom(this.roomId); this.existingRoomData = { roomIdPrefix, autoDeletionDate, preferences }; + if (this.existingRoomData) { + this.isBasicCreation.set(false); + } } catch (error) { console.error('Error loading room data:', error); // Navigate back to rooms list if room not found @@ -96,10 +101,19 @@ export class RoomWizardComponent implements OnInit { } } + onOpenAdvancedMode() { + this.isBasicCreation.set(false); + this.wizardService.goToStep(0); // Reset to first step + } + onPrevious() { this.wizardService.goToPreviousStep(); } + onBack() { + this.isBasicCreation.set(true); + } + onNext() { this.wizardService.goToNextStep(); } @@ -113,6 +127,22 @@ export class RoomWizardComponent implements OnInit { await this.navigationService.navigateTo('rooms', undefined, true); } + async createRoom(roomIdPrefix?: string) { + try { + // Call the room service to create a new room + const { moderatorRoomUrl } = await this.roomService.createRoom({ roomIdPrefix }); + await this.navigationService.redirectTo(moderatorRoomUrl); + } catch (error) { + const errorMessage = `Failed to create room ${roomIdPrefix}`; + this.notificationService.showSnackbar(errorMessage); + console.error(errorMessage, error); + } finally { + this.wizardService.resetWizard(); + // Deactivate loading state + this.isCreatingRoom.set(false); + } + } + async onFinish() { const roomOptions = this.wizardService.roomOptions(); console.log('Wizard completed with data:', roomOptions); diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.html b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.html similarity index 86% rename from frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.html rename to frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.html index 4e1ad78..13c4779 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.html +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.html @@ -1,25 +1,25 @@ -
+
video_chat
-

Basic Information

+

Room Details

- Configure your room's basic settings including name prefix and automatic deletion date + Configure your room's details including name prefix and automatic deletion date

-
+ Room Name Prefix label Optional prefix for room names. Leave empty for default naming. - @if (basicInfoForm.get('roomIdPrefix')?.hasError('maxlength')) { + @if (roomDetailsForm.get('roomIdPrefix')?.hasError('maxlength')) { Room name prefix cannot exceed 50 characters } @@ -42,7 +42,7 @@ matSuffix mat-icon-button type="button" - [disabled]="basicInfoForm.get('autoDeletionDate')?.disabled" + [disabled]="roomDetailsForm.get('autoDeletionDate')?.disabled" (click)="clearDeletionDate()" matTooltip="Clear date selection" class="clear-date-button" @@ -60,7 +60,7 @@ - @if (basicInfoForm.get('autoDeletionDate')?.value) { + @if (roomDetailsForm.get('autoDeletionDate')?.value) {
@@ -89,7 +89,7 @@ access_time
- @if (!basicInfoForm.hasError('minFutureDateTime')) { + @if (!roomDetailsForm.hasError('minFutureDateTime')) {
auto_delete Room will be deleted at {{ getFormattedDateTime() }} diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.scss similarity index 97% rename from frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.scss rename to frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.scss index cee34fc..cc1f22d 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.scss +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.scss @@ -1,6 +1,6 @@ @import '../../../../../../../../../../src/assets/styles/design-tokens'; -.basic-info-step { +.room-details-step { @include ov-page-content; @include ov-container; @@ -41,7 +41,7 @@ .step-content { // margin-bottom: var(--ov-meet-spacing-xl); - .basic-info-form { + .room-details-form { @include ov-grid-responsive(280px); gap: var(--ov-meet-spacing-lg); @@ -144,7 +144,7 @@ } .step-content { - .basic-info-form { + .room-details-form { display: flex; flex-direction: column; gap: var(--ov-meet-spacing-md); @@ -170,7 +170,7 @@ @include ov-tablet-down { .step-content { - .basic-info-form { + .room-details-form { grid-template-columns: 1fr; } } diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.spec.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.spec.ts similarity index 54% rename from frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.spec.ts rename to frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.spec.ts index 8a44951..711b584 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.spec.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.spec.ts @@ -1,18 +1,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { RoomWizardBasicInfoComponent } from './basic-info.component'; +import { RoomWizardRoomDetailsComponent } from './room-details.component'; describe('BasicInfoComponent', () => { - let component: RoomWizardBasicInfoComponent; - let fixture: ComponentFixture; + let component: RoomWizardRoomDetailsComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [RoomWizardBasicInfoComponent] + imports: [RoomWizardRoomDetailsComponent] }) .compileComponents(); - fixture = TestBed.createComponent(RoomWizardBasicInfoComponent); + fixture = TestBed.createComponent(RoomWizardRoomDetailsComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.ts similarity index 83% rename from frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.ts rename to frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.ts index 6e6a1e3..c58610e 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/basic-info/basic-info.component.ts +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/room-wizard/steps/room-details/room-details.component.ts @@ -13,7 +13,7 @@ import { MeetRoomOptions } from '@lib/typings/ce'; import { Subject, takeUntil } from 'rxjs'; @Component({ - selector: 'ov-room-wizard-basic-info', + selector: 'ov-room-wizard-room-details', standalone: true, imports: [ ReactiveFormsModule, @@ -26,11 +26,11 @@ import { Subject, takeUntil } from 'rxjs'; MatSelectModule, MatTooltipModule ], - templateUrl: './basic-info.component.html', - styleUrl: './basic-info.component.scss' + templateUrl: './room-details.component.html', + styleUrl: './room-details.component.scss' }) -export class RoomWizardBasicInfoComponent implements OnDestroy { - basicInfoForm: FormGroup; +export class RoomWizardRoomDetailsComponent implements OnDestroy { + roomDetailsForm: FormGroup; // Arrays for time selection hours = Array.from({ length: 24 }, (_, i) => ({ value: i, display: i.toString().padStart(2, '0') })); @@ -40,9 +40,9 @@ export class RoomWizardBasicInfoComponent implements OnDestroy { constructor(private wizardService: RoomWizardStateService) { const currentStep = this.wizardService.currentStep(); - this.basicInfoForm = currentStep!.formGroup; + this.roomDetailsForm = currentStep!.formGroup; - this.basicInfoForm.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => { + this.roomDetailsForm.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => { this.saveFormData(value); }); } @@ -71,7 +71,7 @@ export class RoomWizardBasicInfoComponent implements OnDestroy { }; // Always save to wizard state (including when values are cleared) - this.wizardService.updateStepData('basic', stepData); + this.wizardService.updateStepData('roomDetails', stepData); } get minDate(): Date { @@ -81,11 +81,11 @@ export class RoomWizardBasicInfoComponent implements OnDestroy { } get hasDateSelected(): boolean { - return !!this.basicInfoForm.get('autoDeletionDate')?.value; + return !!this.roomDetailsForm.get('autoDeletionDate')?.value; } getFormattedDateTime(): string { - const formValue = this.basicInfoForm.value; + const formValue = this.roomDetailsForm.value; if (!formValue.autoDeletionDate) { return ''; } @@ -109,7 +109,7 @@ export class RoomWizardBasicInfoComponent implements OnDestroy { } clearDeletionDate() { - this.basicInfoForm.patchValue({ + this.roomDetailsForm.patchValue({ autoDeletionDate: null, autoDeletionHour: 23, autoDeletionMinute: 59 diff --git a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.scss index 50be7ec..e69de29 100644 --- a/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.scss +++ b/frontend/projects/shared-meet-components/src/lib/pages/console/rooms/rooms.component.scss @@ -1,219 +0,0 @@ -// @import '../../../../../../../src/assets/styles/design-tokens'; - -// Use page loading utility -// .loading-container { -// @extend .ov-page-loading; - -// .loading-content .loading-header .loading-title .loading-icon { -// color: var(--ov-meet-icon-rooms); -// } -// } - -// Use table page actions utility -// .rooms-actions { -// @extend .ov-table-page-actions; - -// .create-room-btn { -// @include ov-button-base; - -// mat-icon { -// @include ov-icon(md); -// margin-right: var(--ov-meet-spacing-sm); -// } -// } -// } - -// Use search field utility -// .search-bar { -// .search-field { -// @extend .ov-search-field; -// min-width: 400px; -// max-width: 500px; -// } -// } - -// Use table page container utility -// .rooms-table-container { -// @extend .ov-table-page-container; -// } - -// Responsive table utilities -// .table-wrapper { -// &.desktop-view { -// display: block; - -// @include ov-tablet-down { -// display: none; -// } -// } - -// &.mobile-view { -// display: none; - -// @include ov-tablet-down { -// display: block; -// } -// } -// } - -// // Use data table utility -// .rooms-table { -// @extend .ov-data-table; - -// .mat-mdc-header-cell { -// &.room-header { -// @extend .primary-header; -// } - -// &.actions-header { -// @extend .actions-header; -// } -// } - -// .mat-mdc-cell { -// &.room-cell { -// @extend .primary-cell; -// } - -// &.actions-cell { -// @extend .actions-cell; -// } -// } -// } - -// Use mobile card utilities -// .mobile-rooms-list { -// display: flex; -// flex-direction: column; -// gap: var(--ov-meet-spacing-md); - -// .room-mobile-card { -// @include ov-card; -// @include ov-theme-transition; - -// &:hover { -// @include ov-hover-lift(-2px); -// } - -// .room-card-header { -// display: flex; -// justify-content: space-between; -// align-items: flex-start; -// margin-bottom: var(--ov-meet-spacing-sm); - -// .room-title { -// @extend .primary-text; -// } - -// .room-status { -// @extend .ov-status-badge; -// } -// } - -// .room-card-content { -// display: flex; -// flex-direction: column; -// gap: var(--ov-meet-spacing-xs); - -// .room-detail { -// display: flex; -// justify-content: space-between; -// font-size: var(--ov-meet-font-size-sm); - -// .detail-label { -// color: var(--ov-meet-text-secondary); -// } - -// .detail-value { -// color: var(--ov-meet-text-primary); -// } -// } -// } - -// .room-card-actions { -// @extend .ov-action-buttons; -// margin-top: var(--ov-meet-spacing-md); -// padding-top: var(--ov-meet-spacing-md); -// border-top: 1px solid var(--ov-meet-border-color-light); -// } -// } -// } - -// // Use info display and status utilities -// .room-info { -// @extend .ov-info-display; -// } - -// .status-badge { -// @extend .ov-status-badge; -// } - -// .participant-count { -// @extend .ov-date-info; -// } - -// .creation-date { -// @extend .ov-date-info; -// } - -// // Use action buttons utility -// .action-buttons { -// @extend .ov-action-buttons; - -// .mat-mdc-icon-button { -// &.primary-action { -// color: var(--ov-meet-color-primary); -// } - -// &.room-preferences-btn { -// color: var(--ov-meet-icon-settings); -// } - -// &.copy-link-btn { -// color: var(--ov-meet-text-secondary); -// } - -// &.view-recordings-btn { -// color: var(--ov-meet-icon-recordings); -// } - -// &.delete-room-btn { -// color: var(--ov-meet-color-error); -// } -// } -// } - -// // Use empty state utility -// .no-rooms-state { -// @extend .ov-empty-state; - -// .empty-icon { -// @include ov-icon(xl); -// color: var(--ov-meet-text-hint); -// margin-bottom: var(--ov-meet-spacing-lg); -// display: block; -// } - -// .getting-started-actions { -// display: flex; -// flex-direction: column; -// gap: var(--ov-meet-spacing-md); -// align-items: center; - -// button { -// @include ov-button-base; - -// mat-icon { -// @include ov-icon(md); -// margin-right: var(--ov-meet-spacing-sm); -// } -// } -// } -// } - -// // Use focus utilities -// .mat-mdc-checkbox, -// .mat-mdc-icon-button, -// .mat-mdc-button { -// @extend .ov-focus-visible; -// } diff --git a/frontend/projects/shared-meet-components/src/lib/services/wizard-state.service.ts b/frontend/projects/shared-meet-components/src/lib/services/wizard-state.service.ts index 6d56623..7161915 100644 --- a/frontend/projects/shared-meet-components/src/lib/services/wizard-state.service.ts +++ b/frontend/projects/shared-meet-components/src/lib/services/wizard-state.service.ts @@ -65,10 +65,10 @@ export class RoomWizardStateService { // Define wizard steps const baseSteps: WizardStep[] = [ { - id: 'basic', + id: 'roomDetails', label: 'Room Details', isCompleted: editMode, // In edit mode, mark as completed but not editable - isActive: !editMode, // Start with basic step active in create mode + isActive: !editMode, // Start with roomDetails step active in create mode isVisible: true, formGroup: this.formBuilder.group( { @@ -174,7 +174,7 @@ export class RoomWizardStateService { ]; this._steps.set(baseSteps); - const initialStepIndex = editMode ? 1 : 0; // Skip basic step in edit mode + const initialStepIndex = editMode ? 1 : 0; // Skip roomDetails step in edit mode this._currentStepIndex.set(initialStepIndex); // Update step visibility after index is set @@ -192,7 +192,7 @@ export class RoomWizardStateService { let updatedOptions: MeetRoomOptions; switch (stepId) { - case 'basic': + case 'roomDetails': updatedOptions = { ...currentOptions }; @@ -360,9 +360,10 @@ export class RoomWizardStateService { return { showPrevious: !isFirstStep, showNext: !isLastStep, - showCancel: true, + showCancel: false, + showBack: true, showFinish: isLastStep, - showSkipAndFinish: !isEditMode && isFirstStep, + showSkipAndFinish: false, // Skip and finish is not used in this wizard disableFinish: isSomeStepInvalid, nextLabel: 'Next', previousLabel: 'Previous', @@ -373,13 +374,13 @@ export class RoomWizardStateService { /** * Checks if the wizard is in edit mode. - * Edit mode is determined by whether the basic step is completed and its form is disabled. + * Edit mode is determined by whether the roomDetails step is completed and its form is disabled. * @returns True if in edit mode, false otherwise */ private isEditMode(): boolean { const visibleSteps = this._visibleSteps(); - const basicStep = visibleSteps.find((step) => step.id === 'basic'); - const isEditMode = !!basicStep && basicStep.isCompleted && basicStep.formGroup.disabled; + const roomDetailsStep = visibleSteps.find((step) => step.id === 'roomDetails'); + const isEditMode = !!roomDetailsStep && roomDetailsStep.isCompleted && roomDetailsStep.formGroup.disabled; return isEditMode; }