frontend: Extract login logic from RoomGeneratorComponent to LoginComponent and refactor code
This commit is contained in:
parent
a7c4b84a03
commit
592356bec3
@ -0,0 +1,72 @@
|
|||||||
|
<div class="section1" [style]="{ '--background-image-url': 'url(' + backgroundImageUrl + ')' }">
|
||||||
|
<mat-toolbar id="header"> </mat-toolbar>
|
||||||
|
<div class="openvidu-slogan-container">
|
||||||
|
<a href="https://openvidu.io/" target="_blank">
|
||||||
|
<img id="form-img" [src]="openviduLogoUrl" />
|
||||||
|
</a>
|
||||||
|
<h4 id="slogan-text">Videoconference rooms in one click</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-container">
|
||||||
|
<div class="grid">
|
||||||
|
<form [formGroup]="loginForm" novalidate (ngSubmit)="login()" id="form-login" class="form login">
|
||||||
|
<div class="form-field" id="login-username">
|
||||||
|
<label for="login-username" [ngClass]="{ error: loginErrorMessage }">
|
||||||
|
<mat-icon matTooltip="Username">person</mat-icon>
|
||||||
|
<span class="hidden">Username</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
formControlName="username"
|
||||||
|
autocomplete="off"
|
||||||
|
type="text"
|
||||||
|
name="username"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="Username"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-field" id="login-password">
|
||||||
|
<label for="login-password" [ngClass]="{ error: loginErrorMessage }">
|
||||||
|
<mat-icon matTooltip="Password">lock</mat-icon>
|
||||||
|
<span class="hidden">Password</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
formControlName="password"
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
class="form-input"
|
||||||
|
placeholder="Password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
@if (loginErrorMessage) {
|
||||||
|
<div class="loginError" id="login-error">{{ loginErrorMessage }}</div>
|
||||||
|
}
|
||||||
|
<div class="form-field">
|
||||||
|
<button mat-button id="join-btn" type="submit" [disabled]="loginForm.invalid">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-toolbar class="footer">
|
||||||
|
<span>
|
||||||
|
Photo by
|
||||||
|
<a
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
href="https://unsplash.com/@danielleone?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"
|
||||||
|
>
|
||||||
|
Daniel Leone
|
||||||
|
</a>
|
||||||
|
on
|
||||||
|
<a
|
||||||
|
href="https://unsplash.com/s/photos/mountain?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Unsplash
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<div id="meet-version">
|
||||||
|
<span>{{ version }}</span>
|
||||||
|
</div>
|
||||||
|
</mat-toolbar>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,255 @@
|
|||||||
|
$loginBorderRadius: 0.35rem;
|
||||||
|
$loginColor: #e6e6e6;
|
||||||
|
$loginError: #770000;
|
||||||
|
$loginInputBackgroundColor: #434a52;
|
||||||
|
$loginInputHoverBackgroundColor: #3c4249;
|
||||||
|
$loginLabelBackgroundColor: #363b41;
|
||||||
|
$loginSubmitBackgroundColor: #0087a9;
|
||||||
|
$loginSubmitDisabledBackgroundColor: #264b55;
|
||||||
|
|
||||||
|
$loginSubmitColor: #eee;
|
||||||
|
$loginSubmitDisabledColor: #bdbdbd;
|
||||||
|
|
||||||
|
$loginSubmitHoverBackgroundColor: #006a85;
|
||||||
|
$iconFill: #606468;
|
||||||
|
$formGap: 0.375rem;
|
||||||
|
|
||||||
|
.section1 {
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2)),
|
||||||
|
var(--background-image-url) top center no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
color: $loginColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header,
|
||||||
|
.footer {
|
||||||
|
background-color: transparent;
|
||||||
|
color: $loginColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginError {
|
||||||
|
font-size: 14px;
|
||||||
|
color: $loginError;
|
||||||
|
text-shadow: 0.2px 0px #ffffff;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginError mat-icon {
|
||||||
|
vertical-align: bottom;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
font-size: 9px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a {
|
||||||
|
color: $loginColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#meet-version,
|
||||||
|
#logout-content {
|
||||||
|
right: 15px;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 25px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: #ffffff;
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extra small devices (phones, 600px and down) */
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
#header_img,
|
||||||
|
.ovVersion,
|
||||||
|
.footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.openvidu-slogan-container {
|
||||||
|
margin-top: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#form-img {
|
||||||
|
max-width: 290px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extra large devices (large laptops and desktops, 1200px and up) */
|
||||||
|
@media only screen and (min-width: 1200px) {
|
||||||
|
.section1 {
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
inline-size: 90%;
|
||||||
|
margin-inline: auto;
|
||||||
|
max-inline-size: 26rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icons {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
block-size: 1em;
|
||||||
|
display: inline-block;
|
||||||
|
fill: $iconFill;
|
||||||
|
inline-size: 1em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
background-image: none;
|
||||||
|
border: 0;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='submit'] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: grid;
|
||||||
|
gap: $formGap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form input[type='password'],
|
||||||
|
.form input[type='text'],
|
||||||
|
.form button[type='submit'] {
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
color: $loginColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login label.error {
|
||||||
|
background-color: $loginError;
|
||||||
|
}
|
||||||
|
.login label,
|
||||||
|
.login input[type='text'],
|
||||||
|
.login input[type='password'] {
|
||||||
|
border-radius: $loginBorderRadius;
|
||||||
|
padding: 0.85rem;
|
||||||
|
}
|
||||||
|
#room-name-input {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login button[type='submit'] {
|
||||||
|
border-radius: $loginBorderRadius;
|
||||||
|
padding: 0.4rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login button:disabled[type='submit'] {
|
||||||
|
cursor: auto;
|
||||||
|
color: $loginSubmitDisabledColor !important;
|
||||||
|
background-color: $loginSubmitDisabledBackgroundColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login label {
|
||||||
|
background-color: $loginLabelBackgroundColor;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
padding-inline: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login input[type='password'],
|
||||||
|
.login input[type='text'] {
|
||||||
|
background-color: $loginInputBackgroundColor;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login input[type='password']:focus,
|
||||||
|
.login input[type='password']:hover,
|
||||||
|
.login input[type='text']:focus,
|
||||||
|
.login input[type='text']:hover {
|
||||||
|
background-color: $loginInputHoverBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login button[type='submit'] {
|
||||||
|
background-color: $loginSubmitBackgroundColor;
|
||||||
|
color: $loginSubmitColor;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login button[type='submit']:focus,
|
||||||
|
.login button[type='submit']:hover {
|
||||||
|
background-color: $loginSubmitHoverBackgroundColor;
|
||||||
|
}
|
||||||
|
#clear-room-name-btn {
|
||||||
|
height: auto;
|
||||||
|
background-color: $loginInputBackgroundColor;
|
||||||
|
border-radius: 0;
|
||||||
|
color: $loginColor;
|
||||||
|
mat-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#room-name-generator-btn {
|
||||||
|
height: auto;
|
||||||
|
background-color: $loginInputBackgroundColor;
|
||||||
|
border-radius: $loginBorderRadius;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
color: $loginColor;
|
||||||
|
mat-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background-color: $loginInputHoverBackgroundColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-block: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { LoginComponent } from './login.component';
|
||||||
|
|
||||||
|
describe('LoginComponent', () => {
|
||||||
|
let component: LoginComponent;
|
||||||
|
let fixture: ComponentFixture<LoginComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [LoginComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(LoginComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
import { NgClass } from '@angular/common';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { MatButton } from '@angular/material/button';
|
||||||
|
import { MatIcon } from '@angular/material/icon';
|
||||||
|
import { MatToolbar } from '@angular/material/toolbar';
|
||||||
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { ContextService, AuthService } from '../../services/index';
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-login',
|
||||||
|
standalone: true,
|
||||||
|
imports: [MatToolbar, MatTooltip, MatIcon, FormsModule, ReactiveFormsModule, NgClass, MatButton],
|
||||||
|
templateUrl: './login.component.html',
|
||||||
|
styleUrl: './login.component.scss'
|
||||||
|
})
|
||||||
|
export class LoginComponent {
|
||||||
|
version = '';
|
||||||
|
openviduLogoUrl = '';
|
||||||
|
backgroundImageUrl = '';
|
||||||
|
|
||||||
|
loginForm = new FormGroup({
|
||||||
|
username: new FormControl('', [Validators.required, Validators.minLength(4)]),
|
||||||
|
password: new FormControl('', [Validators.required, Validators.minLength(4)])
|
||||||
|
});
|
||||||
|
loginErrorMessage: string | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private router: Router,
|
||||||
|
private authService: AuthService,
|
||||||
|
private contextService: ContextService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
this.version = this.contextService.getVersion();
|
||||||
|
this.openviduLogoUrl = this.contextService.getOpenViduLogoUrl();
|
||||||
|
this.backgroundImageUrl = this.contextService.getBackgroundImageUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
async login() {
|
||||||
|
this.loginErrorMessage = undefined;
|
||||||
|
const { username, password } = this.loginForm.value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: Replace with user login
|
||||||
|
await this.authService.adminLogin(username!, password!);
|
||||||
|
this.router.navigate(['']);
|
||||||
|
} catch (error) {
|
||||||
|
if ((error as HttpErrorResponse).status === 429) {
|
||||||
|
this.loginErrorMessage = 'Too many login attempts. Please try again later';
|
||||||
|
} else {
|
||||||
|
this.loginErrorMessage = 'Invalid username or password';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<div class="section1" [style]="{ '--background-image-url': 'url(' + backgroundImageUrl + ')' }">
|
<div class="section1" [style]="{ '--background-image-url': 'url(' + backgroundImageUrl + ')' }">
|
||||||
<mat-toolbar id="header">
|
<mat-toolbar id="header">
|
||||||
@if (isUserLogged) {
|
@if (username) {
|
||||||
<div id="logout-content">
|
<div id="logout-content">
|
||||||
<span>Hi {{ username }}, do you want to logout?</span>
|
<span>Hi {{ username }}, do you want to logout?</span>
|
||||||
<button matTooltip="Logout" mat-icon-button id="logout-btn" (click)="logout()">
|
<button matTooltip="Logout" mat-icon-button id="logout-btn" (click)="logout()">
|
||||||
@ -15,115 +15,56 @@
|
|||||||
</a>
|
</a>
|
||||||
<h4 id="slogan-text">Videoconference rooms in one click</h4>
|
<h4 id="slogan-text">Videoconference rooms in one click</h4>
|
||||||
</div>
|
</div>
|
||||||
@if (!loading) {
|
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
@if (isPrivateAccess && !isUserLogged) {
|
<form [formGroup]="roomForm" novalidate (ngSubmit)="goToVideoRoom()" id="form-room" class="form room-prefix">
|
||||||
<form [formGroup]="loginForm" novalidate (ngSubmit)="login()" id="form-login" class="form login">
|
<div class="form-field">
|
||||||
<div class="form-field" id="login-username">
|
<label for="room-name-input" [ngClass]="{ error: roomForm.get('roomNamePrefix')?.invalid }">
|
||||||
<label for="login-username" [ngClass]="{ error: loginError }">
|
<mat-icon matTooltip="Room name prefix">video_camera_front</mat-icon>
|
||||||
<mat-icon matTooltip="Username">person</mat-icon>
|
<span class="hidden">Room name prefix</span></label
|
||||||
<span class="hidden">Username</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
formControlName="username"
|
|
||||||
autocomplete="off"
|
|
||||||
type="text"
|
|
||||||
name="username"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="Username"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="form-field" id="login-password">
|
|
||||||
<label for="login-password" [ngClass]="{ error: loginError }">
|
|
||||||
<mat-icon matTooltip="Password">lock</mat-icon>
|
|
||||||
<span class="hidden">Password</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
formControlName="password"
|
|
||||||
type="password"
|
|
||||||
name="password"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="Password"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
@if (loginError) {
|
|
||||||
<div class="roomError" id="login-error">Authentication failed. Try again.</div>
|
|
||||||
}
|
|
||||||
<div class="form-field">
|
|
||||||
<button mat-button id="join-btn" type="submit" [disabled]="loginForm.invalid">Login</button>
|
|
||||||
</div>
|
|
||||||
@if (serverConnectionError) {
|
|
||||||
<div class="roomError" id="serverConnectionError">
|
|
||||||
<mat-icon>error</mat-icon>
|
|
||||||
<span>Server connection failed!</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
@if (isUserLogged || !isPrivateAccess) {
|
|
||||||
<form
|
|
||||||
[formGroup]="roomForm"
|
|
||||||
novalidate
|
|
||||||
(ngSubmit)="goToVideoRoom()"
|
|
||||||
id="form-room"
|
|
||||||
class="form login"
|
|
||||||
>
|
>
|
||||||
<div class="form-field">
|
<input
|
||||||
<label for="room-name-input" [ngClass]="{ error: roomForm.get('roomNamePrefix')?.invalid }">
|
formControlName="roomNamePrefix"
|
||||||
<mat-icon matTooltip="Room name">video_camera_front</mat-icon>
|
autocomplete="off"
|
||||||
<span class="hidden">Room Name</span></label
|
id="room-name-input"
|
||||||
>
|
type="text"
|
||||||
<input
|
name="roomNamePrefix"
|
||||||
formControlName="roomNamePrefix"
|
class="form-input"
|
||||||
autocomplete="off"
|
placeholder="Room name prefix"
|
||||||
id="room-name-input"
|
/>
|
||||||
type="text"
|
@if (roomForm.get('roomNamePrefix')?.value) {
|
||||||
name="roomNamePrefix"
|
<button
|
||||||
class="form-input"
|
matSuffix
|
||||||
placeholder="Room Name"
|
mat-icon-button
|
||||||
(keydown)="keyDown($event)"
|
aria-label="Clear"
|
||||||
/>
|
id="clear-room-name-btn"
|
||||||
@if (roomForm.get('roomNamePrefix')?.value) {
|
(click)="clearRoomName()"
|
||||||
<button
|
>
|
||||||
matSuffix
|
<mat-icon>close</mat-icon>
|
||||||
mat-icon-button
|
</button>
|
||||||
aria-label="Clear"
|
}
|
||||||
id="clear-room-name-btn"
|
<button
|
||||||
(click)="clearRoomName()"
|
matTooltip="Generate room name prefix"
|
||||||
>
|
mat-icon-button
|
||||||
<mat-icon>close</mat-icon>
|
id="room-name-generator-btn"
|
||||||
</button>
|
(click)="generateRoomName($event)"
|
||||||
}
|
>
|
||||||
<button
|
<mat-icon>cached</mat-icon>
|
||||||
matTooltip="Generate room name prefix"
|
</button>
|
||||||
mat-icon-button
|
</div>
|
||||||
id="room-name-generator-btn"
|
@if (roomForm.get('roomNamePrefix')?.hasError('required')) {
|
||||||
(click)="generateRoomName($event)"
|
<div class="roomError" id="requiredNameError">Room name is required</div>
|
||||||
>
|
|
||||||
<mat-icon>cached</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@if (roomForm.get('roomNamePrefix')?.hasError('required')) {
|
|
||||||
<div class="roomError" id="requiredNameError">Room name is required</div>
|
|
||||||
}
|
|
||||||
@if (roomForm.get('roomNamePrefix')?.hasError('minlength')) {
|
|
||||||
<div class="roomError" id="shortNameError">Room name is too short!</div>
|
|
||||||
}
|
|
||||||
<div class="form-field">
|
|
||||||
<button mat-button id="join-btn" type="submit" [disabled]="roomForm.invalid">JOIN</button>
|
|
||||||
</div>
|
|
||||||
@if (serverConnectionError) {
|
|
||||||
<div class="roomError" id="serverConnectionError">
|
|
||||||
<mat-icon>error</mat-icon>
|
|
||||||
<span>Server connection failed!</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</form>
|
|
||||||
}
|
}
|
||||||
</div>
|
@if (roomForm.get('roomNamePrefix')?.hasError('minlength')) {
|
||||||
|
<div class="roomError" id="shortNameError">Room name is too short!</div>
|
||||||
|
}
|
||||||
|
<div class="form-field">
|
||||||
|
<button mat-button id="join-btn" type="submit" [disabled]="roomForm.invalid">JOIN</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
|
|
||||||
<mat-toolbar class="footer">
|
<mat-toolbar class="footer">
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
$loginBorderRadus: 0.35rem;
|
$formBorderRadius: 0.35rem;
|
||||||
$loginColor: #e6e6e6;
|
$formColor: #e6e6e6;
|
||||||
$loginError: #770000;
|
$formError: #770000;
|
||||||
$loginInputBackgroundColor: #434a52;
|
$formInputBackgroundColor: #434a52;
|
||||||
$loginInputHoverBackgroundColor: #3c4249;
|
$formInputHoverBackgroundColor: #3c4249;
|
||||||
$loginLabelBackgroundColor: #363b41;
|
$formLabelBackgroundColor: #363b41;
|
||||||
$loginSubmitBackgroundColor: #0087a9;
|
$formSubmitBackgroundColor: #0087a9;
|
||||||
$loginSubmitDisabledBackgroundColor: #264b55;
|
$formSubmitDisabledBackgroundColor: #264b55;
|
||||||
|
|
||||||
$loginSubmitColor: #eee;
|
$formSubmitColor: #eee;
|
||||||
$loginSubmitDisabledColor: #bdbdbd;
|
$formSubmitDisabledColor: #bdbdbd;
|
||||||
|
|
||||||
$loginSubmitHoverBackgroundColor: #006a85;
|
$formSubmitHoverBackgroundColor: #006a85;
|
||||||
$iconFill: #606468;
|
$iconFill: #606468;
|
||||||
$formGap: 0.375rem;
|
$formGap: 0.375rem;
|
||||||
|
|
||||||
@ -22,18 +22,18 @@ $formGap: 0.375rem;
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
color: $loginColor;
|
color: $formColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header,
|
#header,
|
||||||
.footer {
|
.footer {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: $loginColor;
|
color: $formColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.roomError {
|
.roomError {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: $loginError;
|
color: $formError;
|
||||||
text-shadow: 0.2px 0px #ffffff;
|
text-shadow: 0.2px 0px #ffffff;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -52,7 +52,7 @@ $formGap: 0.375rem;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer a {
|
.footer a {
|
||||||
color: $loginColor;
|
color: $formColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
#meet-version,
|
#meet-version,
|
||||||
@ -160,89 +160,90 @@ input[type='submit'] {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login {
|
.room-prefix {
|
||||||
color: $loginColor;
|
color: $formColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login label.error {
|
.room-prefix label.error {
|
||||||
background-color: $loginError;
|
background-color: $formError;
|
||||||
}
|
}
|
||||||
.login label,
|
.room-prefix label,
|
||||||
.login input[type='text'],
|
.room-prefix input[type='text'],
|
||||||
.login input[type='password'] {
|
.room-prefix input[type='password'] {
|
||||||
border-radius: $loginBorderRadus;
|
border-radius: $formBorderRadius;
|
||||||
padding: 0.85rem;
|
padding: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#room-name-input {
|
#room-name-input {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login button[type='submit'] {
|
.room-prefix button[type='submit'] {
|
||||||
border-radius: $loginBorderRadus;
|
border-radius: $formBorderRadius;
|
||||||
padding: 0.4rem;
|
padding: 0.4rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login button:disabled[type='submit'] {
|
.room-prefix button:disabled[type='submit'] {
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
color: $loginSubmitDisabledColor !important;
|
color: $formSubmitDisabledColor !important;
|
||||||
background-color: $loginSubmitDisabledBackgroundColor !important;
|
background-color: $formSubmitDisabledBackgroundColor !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login label {
|
.room-prefix label {
|
||||||
background-color: $loginLabelBackgroundColor;
|
background-color: $formLabelBackgroundColor;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
padding-inline: 1.25rem;
|
padding-inline: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login input[type='password'],
|
.room-prefix input[type='password'],
|
||||||
.login input[type='text'] {
|
.room-prefix input[type='text'] {
|
||||||
background-color: $loginInputBackgroundColor;
|
background-color: $formInputBackgroundColor;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login input[type='password']:focus,
|
.room-prefix input[type='password']:focus,
|
||||||
.login input[type='password']:hover,
|
.room-prefix input[type='password']:hover,
|
||||||
.login input[type='text']:focus,
|
.room-prefix input[type='text']:focus,
|
||||||
.login input[type='text']:hover {
|
.room-prefix input[type='text']:hover {
|
||||||
background-color: $loginInputHoverBackgroundColor;
|
background-color: $formInputHoverBackgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login button[type='submit'] {
|
.room-prefix button[type='submit'] {
|
||||||
background-color: $loginSubmitBackgroundColor;
|
background-color: $formSubmitBackgroundColor;
|
||||||
color: $loginSubmitColor;
|
color: $formSubmitColor;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login button[type='submit']:focus,
|
.room-prefix button[type='submit']:focus,
|
||||||
.login button[type='submit']:hover {
|
.room-prefix button[type='submit']:hover {
|
||||||
background-color: $loginSubmitHoverBackgroundColor;
|
background-color: $formSubmitHoverBackgroundColor;
|
||||||
}
|
}
|
||||||
#clear-room-name-btn {
|
#clear-room-name-btn {
|
||||||
height: auto;
|
height: auto;
|
||||||
background-color: $loginInputBackgroundColor;
|
background-color: $formInputBackgroundColor;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
color: $loginColor;
|
color: $formColor;
|
||||||
mat-icon {
|
mat-icon {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#room-name-generator-btn {
|
#room-name-generator-btn {
|
||||||
height: auto;
|
height: auto;
|
||||||
background-color: $loginInputBackgroundColor;
|
background-color: $formInputBackgroundColor;
|
||||||
border-radius: $loginBorderRadus;
|
border-radius: $formBorderRadius;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
color: $loginColor;
|
color: $formColor;
|
||||||
mat-icon {
|
mat-icon {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $loginInputHoverBackgroundColor;
|
background-color: $formInputHoverBackgroundColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,11 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import {
|
import { FormGroup, Validators, FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms';
|
||||||
FormBuilder,
|
|
||||||
FormGroup,
|
|
||||||
UntypedFormBuilder,
|
|
||||||
Validators,
|
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule
|
|
||||||
} from '@angular/forms';
|
|
||||||
import { MatIcon } from '@angular/material/icon';
|
import { MatIcon } from '@angular/material/icon';
|
||||||
import { MatTooltip } from '@angular/material/tooltip';
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
import { MatIconButton, MatButton } from '@angular/material/button';
|
import { MatIconButton, MatButton } from '@angular/material/button';
|
||||||
import { NgClass } from '@angular/common';
|
import { NgClass } from '@angular/common';
|
||||||
import { MatToolbar } from '@angular/material/toolbar';
|
import { MatToolbar } from '@angular/material/toolbar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
import { ContextService, HttpService } from '../../services/index';
|
import { ContextService, HttpService } from '../../services/index';
|
||||||
import { OpenViduMeetRoom, OpenViduMeetRoomOptions } from '../../typings/ce/room';
|
import { OpenViduMeetRoom, OpenViduMeetRoomOptions } from '../../typings/ce/room';
|
||||||
import { animals, colors, Config, uniqueNamesGenerator } from 'unique-names-generator';
|
import { animals, colors, Config, uniqueNamesGenerator } from 'unique-names-generator';
|
||||||
@ -25,68 +17,29 @@ import { animals, colors, Config, uniqueNamesGenerator } from 'unique-names-gene
|
|||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [MatToolbar, MatIconButton, MatTooltip, MatIcon, FormsModule, ReactiveFormsModule, NgClass, MatButton]
|
imports: [MatToolbar, MatIconButton, MatTooltip, MatIcon, FormsModule, ReactiveFormsModule, NgClass, MatButton]
|
||||||
})
|
})
|
||||||
export class RoomCreatorComponent implements OnInit, OnDestroy {
|
export class RoomCreatorComponent implements OnInit {
|
||||||
version = '';
|
version = '';
|
||||||
openviduLogoUrl = '';
|
openviduLogoUrl = '';
|
||||||
backgroundImageUrl = '';
|
backgroundImageUrl = '';
|
||||||
|
|
||||||
roomForm: FormGroup;
|
roomForm = new FormGroup({
|
||||||
loginForm: FormGroup;
|
roomNamePrefix: new FormControl(this.getRandomName(), [Validators.required, Validators.minLength(6)])
|
||||||
isPrivateAccess = false;
|
});
|
||||||
username = '';
|
username = '';
|
||||||
loginError = false;
|
|
||||||
serverConnectionError = false;
|
|
||||||
isUserLogged = false;
|
|
||||||
loading = true;
|
|
||||||
private queryParamSubscription!: Subscription;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
public formBuilder: UntypedFormBuilder,
|
|
||||||
private httpService: HttpService,
|
private httpService: HttpService,
|
||||||
// private callService: ConfigService,
|
|
||||||
private fb: FormBuilder,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private contextService: ContextService
|
private contextService: ContextService
|
||||||
) {
|
) {}
|
||||||
this.loginForm = this.fb.group({
|
|
||||||
username: [
|
|
||||||
/*this.storageService.getParticipantName() ??*/ '',
|
|
||||||
[Validators.required, Validators.minLength(4)]
|
|
||||||
],
|
|
||||||
password: ['', [Validators.required, Validators.minLength(4)]]
|
|
||||||
});
|
|
||||||
|
|
||||||
this.roomForm = this.fb.group({
|
|
||||||
roomNamePrefix: [this.getRandomName(), [Validators.required, Validators.minLength(6)]]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.version = this.contextService.getVersion();
|
this.version = this.contextService.getVersion();
|
||||||
this.openviduLogoUrl = this.contextService.getOpenViduLogoUrl();
|
this.openviduLogoUrl = this.contextService.getOpenViduLogoUrl();
|
||||||
this.backgroundImageUrl = this.contextService.getBackgroundImageUrl();
|
this.backgroundImageUrl = this.contextService.getBackgroundImageUrl();
|
||||||
this.subscribeToQueryParams();
|
|
||||||
|
|
||||||
try {
|
// TODO: Retrieve actual username
|
||||||
// await this.callService.initialize();
|
this.username = 'user';
|
||||||
// this.isPrivateAccess = this.callService.isPrivateAccess();
|
|
||||||
|
|
||||||
if (this.isPrivateAccess) {
|
|
||||||
this.isUserLogged = true;
|
|
||||||
this.loginError = false;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.isUserLogged = false;
|
|
||||||
// this.serverConnectionError = true;
|
|
||||||
this.loginError = true;
|
|
||||||
} finally {
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
if (this.queryParamSubscription) this.queryParamSubscription.unsubscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generateRoomName(event: any) {
|
generateRoomName(event: any) {
|
||||||
@ -98,34 +51,9 @@ export class RoomCreatorComponent implements OnInit, OnDestroy {
|
|||||||
this.roomForm.get('roomNamePrefix')?.setValue('');
|
this.roomForm.get('roomNamePrefix')?.setValue('');
|
||||||
}
|
}
|
||||||
|
|
||||||
keyDown(event: KeyboardEvent) {
|
|
||||||
if (event.keyCode === 13) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.goToVideoRoom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async login() {
|
|
||||||
// Invoked when login form is valid
|
|
||||||
this.loginError = false;
|
|
||||||
this.username = this.loginForm.get('username')?.value;
|
|
||||||
const password = this.loginForm.get('password')?.value;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.httpService.userLogin({ username: this.username, password });
|
|
||||||
this.isUserLogged = true;
|
|
||||||
} catch (error) {
|
|
||||||
this.isUserLogged = false;
|
|
||||||
this.loginError = true;
|
|
||||||
console.error('Error doing login ', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async logout() {
|
async logout() {
|
||||||
try {
|
try {
|
||||||
await this.httpService.userLogout();
|
await this.httpService.userLogout();
|
||||||
this.loginError = false;
|
|
||||||
this.isUserLogged = false;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error doing logout ', error);
|
console.error('Error doing logout ', error);
|
||||||
}
|
}
|
||||||
@ -137,7 +65,7 @@ export class RoomCreatorComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const roomNamePrefix = this.roomForm.get('roomNamePrefix')?.value.replace(/ /g, '-');
|
const roomNamePrefix = this.roomForm.get('roomNamePrefix')?.value!.replace(/ /g, '-');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Fix expiration date
|
// TODO: Fix expiration date
|
||||||
@ -148,8 +76,6 @@ export class RoomCreatorComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
const room: OpenViduMeetRoom = await this.httpService.createRoom(options);
|
const room: OpenViduMeetRoom = await this.httpService.createRoom(options);
|
||||||
|
|
||||||
this.roomForm.get('roomNamePrefix')?.setValue(roomNamePrefix);
|
|
||||||
|
|
||||||
const accessRoomUrl = new URL(room.moderatorRoomUrl);
|
const accessRoomUrl = new URL(room.moderatorRoomUrl);
|
||||||
const secret = accessRoomUrl.searchParams.get('secret');
|
const secret = accessRoomUrl.searchParams.get('secret');
|
||||||
const roomName = accessRoomUrl.pathname;
|
const roomName = accessRoomUrl.pathname;
|
||||||
@ -160,16 +86,6 @@ export class RoomCreatorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToQueryParams(): void {
|
|
||||||
// this.queryParamSubscription = this.route.queryParams.subscribe((params) => {
|
|
||||||
// const roomName = params['roomName'];
|
|
||||||
// if (roomName) {
|
|
||||||
// this.loginError = true;
|
|
||||||
// this.roomForm.get('roomNamePrefix')?.setValue(roomName.replace(/[^\w-]/g, ''));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
private getRandomName(): string {
|
private getRandomName(): string {
|
||||||
const configName: Config = {
|
const configName: Config = {
|
||||||
dictionaries: [colors, animals],
|
dictionaries: [colors, animals],
|
||||||
|
|||||||
@ -25,9 +25,11 @@ import {
|
|||||||
SecurityPreferencesComponent,
|
SecurityPreferencesComponent,
|
||||||
VideoRoomComponent
|
VideoRoomComponent
|
||||||
} from '../pages';
|
} from '../pages';
|
||||||
|
import { LoginComponent } from '@lib/pages/login/login.component';
|
||||||
|
|
||||||
export const baseRoutes: Routes = [
|
export const baseRoutes: Routes = [
|
||||||
{ path: '', component: RoomCreatorComponent },
|
{ path: '', component: RoomCreatorComponent },
|
||||||
|
{ path: 'login', component: LoginComponent },
|
||||||
{ path: 'disconnected', component: DisconnectedComponent },
|
{ path: 'disconnected', component: DisconnectedComponent },
|
||||||
{ path: 'unauthorized', component: UnauthorizedComponent },
|
{ path: 'unauthorized', component: UnauthorizedComponent },
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user