From 1f20622f2b087eaf8738d60fae00a44b9c558ca3 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 7 Jun 2019 16:59:53 +0200 Subject: Improve registration * Add ability to set the user display name * Use display name to guess the username/channel name * Add explanations about what is the purpose of a username/channel name * Add a loader at the "done" step --- .../my-account-profile.component.ts | 2 +- .../+register/register-step-channel.component.html | 34 ++++++++++++---------- .../+register/register-step-channel.component.ts | 30 ++++++++++++++----- .../+register/register-step-user.component.html | 19 ++++++++++++ .../+register/register-step-user.component.ts | 19 +++++++++++- .../app/+signup/+register/register.component.html | 6 ++++ .../app/+signup/+register/register.component.scss | 23 +++++++++++++++ .../form-validators/user-validators.service.ts | 33 ++++++++++++--------- client/src/app/shared/misc/loader.component.html | 2 +- client/src/app/shared/misc/loader.component.scss | 14 ++++----- client/src/app/shared/users/user.service.ts | 16 ++++++++++ .../video-import-torrent.component.ts | 1 - 12 files changed, 153 insertions(+), 46 deletions(-) (limited to 'client') diff --git a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts index a9503ed1b..fcad5a6c2 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts @@ -30,7 +30,7 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit { ngOnInit () { this.buildForm({ - 'display-name': this.userValidatorsService.USER_DISPLAY_NAME, + 'display-name': this.userValidatorsService.USER_DISPLAY_NAME_REQUIRED, description: this.userValidatorsService.USER_DESCRIPTION }) diff --git a/client/src/app/+signup/+register/register-step-channel.component.html b/client/src/app/+signup/+register/register-step-channel.component.html index 68ea4473a..253374f87 100644 --- a/client/src/app/+signup/+register/register-step-channel.component.html +++ b/client/src/app/+signup/+register/register-step-channel.component.html @@ -11,6 +11,21 @@

+
+ + +
+ +
+ +
+ {{ formErrors.displayName }} +
+
+
@@ -24,6 +39,10 @@
+
+ The channel name is a unique identifier of your channel on this instance. It's like an address mail, so other people can find your channel. +
+
{{ formErrors.name }}
@@ -32,19 +51,4 @@ Channel name cannot be the same than your account name. You can click on the first step to update your account name. - -
- - -
- -
- -
- {{ formErrors.displayName }} -
-
diff --git a/client/src/app/+signup/+register/register-step-channel.component.ts b/client/src/app/+signup/+register/register-step-channel.component.ts index 9e13f75b3..e434b91a7 100644 --- a/client/src/app/+signup/+register/register-step-channel.component.ts +++ b/client/src/app/+signup/+register/register-step-channel.component.ts @@ -1,8 +1,10 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import { AuthService } from '@app/core' -import { FormReactive, VideoChannelValidatorsService } from '@app/shared' +import { FormReactive, UserService, VideoChannelValidatorsService } from '@app/shared' import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' import { FormGroup } from '@angular/forms' +import { pairwise } from 'rxjs/operators' +import { concat, of } from 'rxjs' @Component({ selector: 'my-register-step-channel', @@ -16,6 +18,7 @@ export class RegisterStepChannelComponent extends FormReactive implements OnInit constructor ( protected formValidatorService: FormValidatorService, private authService: AuthService, + private userService: UserService, private videoChannelValidatorsService: VideoChannelValidatorsService ) { super() @@ -25,16 +28,29 @@ export class RegisterStepChannelComponent extends FormReactive implements OnInit return window.location.host } - isSameThanUsername () { - return this.username && this.username === this.form.value['name'] - } - ngOnInit () { this.buildForm({ - name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME, - displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME + displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, + name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME }) setTimeout(() => this.formBuilt.emit(this.form)) + + concat( + of(''), + this.form.get('displayName').valueChanges + ).pipe(pairwise()) + .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue)) + } + + isSameThanUsername () { + return this.username && this.username === this.form.value['name'] + } + + private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) { + const name = this.form.value['name'] || '' + + const newName = this.userService.getNewUsername(oldDisplayName, newDisplayName, name) + this.form.patchValue({ name: newName }) } } diff --git a/client/src/app/+signup/+register/register-step-user.component.html b/client/src/app/+signup/+register/register-step-user.component.html index cd0c78bfa..47b3be8cc 100644 --- a/client/src/app/+signup/+register/register-step-user.component.html +++ b/client/src/app/+signup/+register/register-step-user.component.html @@ -1,5 +1,20 @@
+
+ + +
+ +
+ +
+ {{ formErrors.displayName }} +
+
+
@@ -13,6 +28,10 @@
+
+ The username is a unique identifier of your account on this instance. It's like an address mail, so other people can find you. +
+
{{ formErrors.username }}
diff --git a/client/src/app/+signup/+register/register-step-user.component.ts b/client/src/app/+signup/+register/register-step-user.component.ts index 3825ae371..3b71fd3c4 100644 --- a/client/src/app/+signup/+register/register-step-user.component.ts +++ b/client/src/app/+signup/+register/register-step-user.component.ts @@ -1,8 +1,10 @@ import { Component, EventEmitter, OnInit, Output } from '@angular/core' import { AuthService } from '@app/core' -import { FormReactive, UserValidatorsService } from '@app/shared' +import { FormReactive, UserService, UserValidatorsService } from '@app/shared' import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' import { FormGroup } from '@angular/forms' +import { pairwise } from 'rxjs/operators' +import { concat, of } from 'rxjs' @Component({ selector: 'my-register-step-user', @@ -15,6 +17,7 @@ export class RegisterStepUserComponent extends FormReactive implements OnInit { constructor ( protected formValidatorService: FormValidatorService, private authService: AuthService, + private userService: UserService, private userValidatorsService: UserValidatorsService ) { super() @@ -26,6 +29,7 @@ export class RegisterStepUserComponent extends FormReactive implements OnInit { ngOnInit () { this.buildForm({ + displayName: this.userValidatorsService.USER_DISPLAY_NAME_REQUIRED, username: this.userValidatorsService.USER_USERNAME, password: this.userValidatorsService.USER_PASSWORD, email: this.userValidatorsService.USER_EMAIL, @@ -33,5 +37,18 @@ export class RegisterStepUserComponent extends FormReactive implements OnInit { }) setTimeout(() => this.formBuilt.emit(this.form)) + + concat( + of(''), + this.form.get('displayName').valueChanges + ).pipe(pairwise()) + .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue)) + } + + private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) { + const username = this.form.value['username'] || '' + + const newUsername = this.userService.getNewUsername(oldDisplayName, newDisplayName, username) + this.form.patchValue({ username: newUsername }) } } diff --git a/client/src/app/+signup/+register/register.component.html b/client/src/app/+signup/+register/register.component.html index 24def68c1..d7e47c1a8 100644 --- a/client/src/app/+signup/+register/register.component.html +++ b/client/src/app/+signup/+register/register.component.html @@ -27,6 +27,12 @@ +
+ + +
PeerTube is creating your account...
+
+
{{ error }}
diff --git a/client/src/app/+signup/+register/register.component.scss b/client/src/app/+signup/+register/register.component.scss index 6f61b78f7..8d14992e7 100644 --- a/client/src/app/+signup/+register/register.component.scss +++ b/client/src/app/+signup/+register/register.component.scss @@ -56,3 +56,26 @@ button { @include peertube-button; @include orange-button; } + +.name-information { + margin-top: 10px; +} + +.done-loader { + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + + my-loader { + margin-bottom: 20px; + + /deep/ .loader div { + border-color: var(--mainColor) transparent transparent transparent; + } + + & + div { + font-size: 15px; + } + } +} diff --git a/client/src/app/shared/forms/form-validators/user-validators.service.ts b/client/src/app/shared/forms/form-validators/user-validators.service.ts index 6589b2580..2dafb1816 100644 --- a/client/src/app/shared/forms/form-validators/user-validators.service.ts +++ b/client/src/app/shared/forms/form-validators/user-validators.service.ts @@ -12,7 +12,7 @@ export class UserValidatorsService { readonly USER_VIDEO_QUOTA: BuildFormValidator readonly USER_VIDEO_QUOTA_DAILY: BuildFormValidator readonly USER_ROLE: BuildFormValidator - readonly USER_DISPLAY_NAME: BuildFormValidator + readonly USER_DISPLAY_NAME_REQUIRED: BuildFormValidator readonly USER_DESCRIPTION: BuildFormValidator readonly USER_TERMS: BuildFormValidator @@ -85,18 +85,7 @@ export class UserValidatorsService { } } - this.USER_DISPLAY_NAME = { - VALIDATORS: [ - Validators.required, - Validators.minLength(1), - Validators.maxLength(50) - ], - MESSAGES: { - 'required': this.i18n('Display name is required.'), - 'minlength': this.i18n('Display name must be at least 1 character long.'), - 'maxlength': this.i18n('Display name cannot be more than 50 characters long.') - } - } + this.USER_DISPLAY_NAME_REQUIRED = this.getDisplayName(true) this.USER_DESCRIPTION = { VALIDATORS: [ @@ -129,4 +118,22 @@ export class UserValidatorsService { } } } + + private getDisplayName (required: boolean) { + const control = { + VALIDATORS: [ + Validators.minLength(1), + Validators.maxLength(120) + ], + MESSAGES: { + 'required': this.i18n('Display name is required.'), + 'minlength': this.i18n('Display name must be at least 1 character long.'), + 'maxlength': this.i18n('Display name cannot be more than 50 characters long.') + } + } + + if (required) control.VALIDATORS.push(Validators.required) + + return control + } } diff --git a/client/src/app/shared/misc/loader.component.html b/client/src/app/shared/misc/loader.component.html index b8b7ad343..ca8ed063e 100644 --- a/client/src/app/shared/misc/loader.component.html +++ b/client/src/app/shared/misc/loader.component.html @@ -1,5 +1,5 @@
-
+
diff --git a/client/src/app/shared/misc/loader.component.scss b/client/src/app/shared/misc/loader.component.scss index ddb64f07a..ffac9c707 100644 --- a/client/src/app/shared/misc/loader.component.scss +++ b/client/src/app/shared/misc/loader.component.scss @@ -3,14 +3,14 @@ // Thanks to https://loading.io/css/ (CC0 License) -.lds-ring { +.loader { display: inline-block; position: relative; width: 50px; height: 50px; } -.lds-ring div { +.loader div { box-sizing: border-box; display: block; position: absolute; @@ -19,23 +19,23 @@ margin: 6px; border: 4px solid; border-radius: 50%; - animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; + animation: loader 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; border-color: #999999 transparent transparent transparent; } -.lds-ring div:nth-child(1) { +.loader div:nth-child(1) { animation-delay: -0.45s; } -.lds-ring div:nth-child(2) { +.loader div:nth-child(2) { animation-delay: -0.3s; } -.lds-ring div:nth-child(3) { +.loader div:nth-child(3) { animation-delay: -0.15s; } -@keyframes lds-ring { +@keyframes loader { 0% { transform: rotate(0deg); } diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts index 20883456f..70ff9a058 100644 --- a/client/src/app/shared/users/user.service.ts +++ b/client/src/app/shared/users/user.service.ts @@ -136,6 +136,22 @@ export class UserService { .pipe(catchError(res => this.restExtractor.handleError(res))) } + getNewUsername (oldDisplayName: string, newDisplayName: string, currentUsername: string) { + // Don't update display name, the user seems to have changed it + if (this.displayNameToUsername(oldDisplayName) !== currentUsername) return currentUsername + + return this.displayNameToUsername(newDisplayName) + } + + displayNameToUsername (displayName: string) { + if (!displayName) return '' + + return displayName + .toLowerCase() + .replace(/\s/g, '_') + .replace(/[^a-z0-9_.]/g, '') + } + /* ###### Admin methods ###### */ addUser (userCreate: UserCreate) { diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts index ed9cb5840..e47624dd6 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts @@ -100,7 +100,6 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca previewUrl: null })) - this.hydrateFormFromVideo() }, -- cgit v1.2.3