aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-06-07 16:59:53 +0200
committerChocobozzz <me@florianbigard.com>2019-06-07 17:05:42 +0200
commit1f20622f2b087eaf8738d60fae00a44b9c558ca3 (patch)
tree1c8554623665ca96b8a1e6f2a6bcb8c1b5a83c2e /client/src
parent1a03bea0c42fa1064ce4770157b4fd2e3edd5565 (diff)
downloadPeerTube-1f20622f2b087eaf8738d60fae00a44b9c558ca3.tar.gz
PeerTube-1f20622f2b087eaf8738d60fae00a44b9c558ca3.tar.zst
PeerTube-1f20622f2b087eaf8738d60fae00a44b9c558ca3.zip
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
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts2
-rw-r--r--client/src/app/+signup/+register/register-step-channel.component.html34
-rw-r--r--client/src/app/+signup/+register/register-step-channel.component.ts30
-rw-r--r--client/src/app/+signup/+register/register-step-user.component.html19
-rw-r--r--client/src/app/+signup/+register/register-step-user.component.ts19
-rw-r--r--client/src/app/+signup/+register/register.component.html6
-rw-r--r--client/src/app/+signup/+register/register.component.scss23
-rw-r--r--client/src/app/shared/forms/form-validators/user-validators.service.ts33
-rw-r--r--client/src/app/shared/misc/loader.component.html2
-rw-r--r--client/src/app/shared/misc/loader.component.scss14
-rw-r--r--client/src/app/shared/users/user.service.ts16
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts1
12 files changed, 153 insertions, 46 deletions
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 {
30 30
31 ngOnInit () { 31 ngOnInit () {
32 this.buildForm({ 32 this.buildForm({
33 'display-name': this.userValidatorsService.USER_DISPLAY_NAME, 33 'display-name': this.userValidatorsService.USER_DISPLAY_NAME_REQUIRED,
34 description: this.userValidatorsService.USER_DESCRIPTION 34 description: this.userValidatorsService.USER_DESCRIPTION
35 }) 35 })
36 36
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
@@ -12,6 +12,21 @@
12 </div> 12 </div>
13 13
14 <div class="form-group"> 14 <div class="form-group">
15 <label for="displayName" i18n>Channel display name</label>
16
17 <div class="input-group">
18 <input
19 type="text" id="displayName"
20 formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }"
21 >
22 </div>
23
24 <div *ngIf="formErrors.displayName" class="form-error">
25 {{ formErrors.displayName }}
26 </div>
27 </div>
28
29 <div class="form-group">
15 <label for="name" i18n>Channel name</label> 30 <label for="name" i18n>Channel name</label>
16 31
17 <div class="input-group"> 32 <div class="input-group">
@@ -24,6 +39,10 @@
24 </div> 39 </div>
25 </div> 40 </div>
26 41
42 <div class="name-information" i18n>
43 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.
44 </div>
45
27 <div *ngIf="formErrors.name" class="form-error"> 46 <div *ngIf="formErrors.name" class="form-error">
28 {{ formErrors.name }} 47 {{ formErrors.name }}
29 </div> 48 </div>
@@ -32,19 +51,4 @@
32 Channel name cannot be the same than your account name. You can click on the first step to update your account name. 51 Channel name cannot be the same than your account name. You can click on the first step to update your account name.
33 </div> 52 </div>
34 </div> 53 </div>
35
36 <div class="form-group">
37 <label for="displayName" i18n>Channel display name</label>
38
39 <div class="input-group">
40 <input
41 type="text" id="displayName"
42 formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }"
43 >
44 </div>
45
46 <div *ngIf="formErrors.displayName" class="form-error">
47 {{ formErrors.displayName }}
48 </div>
49 </div>
50</form> 54</form>
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 @@
1import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' 1import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
2import { AuthService } from '@app/core' 2import { AuthService } from '@app/core'
3import { FormReactive, VideoChannelValidatorsService } from '@app/shared' 3import { FormReactive, UserService, VideoChannelValidatorsService } from '@app/shared'
4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' 4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
5import { FormGroup } from '@angular/forms' 5import { FormGroup } from '@angular/forms'
6import { pairwise } from 'rxjs/operators'
7import { concat, of } from 'rxjs'
6 8
7@Component({ 9@Component({
8 selector: 'my-register-step-channel', 10 selector: 'my-register-step-channel',
@@ -16,6 +18,7 @@ export class RegisterStepChannelComponent extends FormReactive implements OnInit
16 constructor ( 18 constructor (
17 protected formValidatorService: FormValidatorService, 19 protected formValidatorService: FormValidatorService,
18 private authService: AuthService, 20 private authService: AuthService,
21 private userService: UserService,
19 private videoChannelValidatorsService: VideoChannelValidatorsService 22 private videoChannelValidatorsService: VideoChannelValidatorsService
20 ) { 23 ) {
21 super() 24 super()
@@ -25,16 +28,29 @@ export class RegisterStepChannelComponent extends FormReactive implements OnInit
25 return window.location.host 28 return window.location.host
26 } 29 }
27 30
28 isSameThanUsername () {
29 return this.username && this.username === this.form.value['name']
30 }
31
32 ngOnInit () { 31 ngOnInit () {
33 this.buildForm({ 32 this.buildForm({
34 name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME, 33 displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME,
35 displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME 34 name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME
36 }) 35 })
37 36
38 setTimeout(() => this.formBuilt.emit(this.form)) 37 setTimeout(() => this.formBuilt.emit(this.form))
38
39 concat(
40 of(''),
41 this.form.get('displayName').valueChanges
42 ).pipe(pairwise())
43 .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue))
44 }
45
46 isSameThanUsername () {
47 return this.username && this.username === this.form.value['name']
48 }
49
50 private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) {
51 const name = this.form.value['name'] || ''
52
53 const newName = this.userService.getNewUsername(oldDisplayName, newDisplayName, name)
54 this.form.patchValue({ name: newName })
39 } 55 }
40} 56}
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,6 +1,21 @@
1<form role="form" [formGroup]="form"> 1<form role="form" [formGroup]="form">
2 2
3 <div class="form-group"> 3 <div class="form-group">
4 <label for="displayName" i18n>Display name</label>
5
6 <div class="input-group">
7 <input
8 type="text" id="displayName" placeholder="John Doe"
9 formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }"
10 >
11 </div>
12
13 <div *ngIf="formErrors.displayName" class="form-error">
14 {{ formErrors.displayName }}
15 </div>
16 </div>
17
18 <div class="form-group">
4 <label for="username" i18n>Username</label> 19 <label for="username" i18n>Username</label>
5 20
6 <div class="input-group"> 21 <div class="input-group">
@@ -13,6 +28,10 @@
13 </div> 28 </div>
14 </div> 29 </div>
15 30
31 <div class="name-information" i18n>
32 The username is a unique identifier of your account on this instance. It's like an address mail, so other people can find you.
33 </div>
34
16 <div *ngIf="formErrors.username" class="form-error"> 35 <div *ngIf="formErrors.username" class="form-error">
17 {{ formErrors.username }} 36 {{ formErrors.username }}
18 </div> 37 </div>
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 @@
1import { Component, EventEmitter, OnInit, Output } from '@angular/core' 1import { Component, EventEmitter, OnInit, Output } from '@angular/core'
2import { AuthService } from '@app/core' 2import { AuthService } from '@app/core'
3import { FormReactive, UserValidatorsService } from '@app/shared' 3import { FormReactive, UserService, UserValidatorsService } from '@app/shared'
4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' 4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
5import { FormGroup } from '@angular/forms' 5import { FormGroup } from '@angular/forms'
6import { pairwise } from 'rxjs/operators'
7import { concat, of } from 'rxjs'
6 8
7@Component({ 9@Component({
8 selector: 'my-register-step-user', 10 selector: 'my-register-step-user',
@@ -15,6 +17,7 @@ export class RegisterStepUserComponent extends FormReactive implements OnInit {
15 constructor ( 17 constructor (
16 protected formValidatorService: FormValidatorService, 18 protected formValidatorService: FormValidatorService,
17 private authService: AuthService, 19 private authService: AuthService,
20 private userService: UserService,
18 private userValidatorsService: UserValidatorsService 21 private userValidatorsService: UserValidatorsService
19 ) { 22 ) {
20 super() 23 super()
@@ -26,6 +29,7 @@ export class RegisterStepUserComponent extends FormReactive implements OnInit {
26 29
27 ngOnInit () { 30 ngOnInit () {
28 this.buildForm({ 31 this.buildForm({
32 displayName: this.userValidatorsService.USER_DISPLAY_NAME_REQUIRED,
29 username: this.userValidatorsService.USER_USERNAME, 33 username: this.userValidatorsService.USER_USERNAME,
30 password: this.userValidatorsService.USER_PASSWORD, 34 password: this.userValidatorsService.USER_PASSWORD,
31 email: this.userValidatorsService.USER_EMAIL, 35 email: this.userValidatorsService.USER_EMAIL,
@@ -33,5 +37,18 @@ export class RegisterStepUserComponent extends FormReactive implements OnInit {
33 }) 37 })
34 38
35 setTimeout(() => this.formBuilt.emit(this.form)) 39 setTimeout(() => this.formBuilt.emit(this.form))
40
41 concat(
42 of(''),
43 this.form.get('displayName').valueChanges
44 ).pipe(pairwise())
45 .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue))
46 }
47
48 private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) {
49 const username = this.form.value['username'] || ''
50
51 const newUsername = this.userService.getNewUsername(oldDisplayName, newDisplayName, username)
52 this.form.patchValue({ username: newUsername })
36 } 53 }
37} 54}
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 @@
27 </cdk-step> 27 </cdk-step>
28 28
29 <cdk-step i18n-label label="Done" editable="false"> 29 <cdk-step i18n-label label="Done" editable="false">
30 <div *ngIf="!signupDone && !error" class="done-loader">
31 <my-loader [loading]="true"></my-loader>
32
33 <div i18n>PeerTube is creating your account...</div>
34 </div>
35
30 <div *ngIf="error" class="alert alert-danger">{{ error }}</div> 36 <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
31 </cdk-step> 37 </cdk-step>
32 </my-custom-stepper> 38 </my-custom-stepper>
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 {
56 @include peertube-button; 56 @include peertube-button;
57 @include orange-button; 57 @include orange-button;
58} 58}
59
60.name-information {
61 margin-top: 10px;
62}
63
64.done-loader {
65 display: flex;
66 justify-content: center;
67 flex-direction: column;
68 align-items: center;
69
70 my-loader {
71 margin-bottom: 20px;
72
73 /deep/ .loader div {
74 border-color: var(--mainColor) transparent transparent transparent;
75 }
76
77 & + div {
78 font-size: 15px;
79 }
80 }
81}
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 {
12 readonly USER_VIDEO_QUOTA: BuildFormValidator 12 readonly USER_VIDEO_QUOTA: BuildFormValidator
13 readonly USER_VIDEO_QUOTA_DAILY: BuildFormValidator 13 readonly USER_VIDEO_QUOTA_DAILY: BuildFormValidator
14 readonly USER_ROLE: BuildFormValidator 14 readonly USER_ROLE: BuildFormValidator
15 readonly USER_DISPLAY_NAME: BuildFormValidator 15 readonly USER_DISPLAY_NAME_REQUIRED: BuildFormValidator
16 readonly USER_DESCRIPTION: BuildFormValidator 16 readonly USER_DESCRIPTION: BuildFormValidator
17 readonly USER_TERMS: BuildFormValidator 17 readonly USER_TERMS: BuildFormValidator
18 18
@@ -85,18 +85,7 @@ export class UserValidatorsService {
85 } 85 }
86 } 86 }
87 87
88 this.USER_DISPLAY_NAME = { 88 this.USER_DISPLAY_NAME_REQUIRED = this.getDisplayName(true)
89 VALIDATORS: [
90 Validators.required,
91 Validators.minLength(1),
92 Validators.maxLength(50)
93 ],
94 MESSAGES: {
95 'required': this.i18n('Display name is required.'),
96 'minlength': this.i18n('Display name must be at least 1 character long.'),
97 'maxlength': this.i18n('Display name cannot be more than 50 characters long.')
98 }
99 }
100 89
101 this.USER_DESCRIPTION = { 90 this.USER_DESCRIPTION = {
102 VALIDATORS: [ 91 VALIDATORS: [
@@ -129,4 +118,22 @@ export class UserValidatorsService {
129 } 118 }
130 } 119 }
131 } 120 }
121
122 private getDisplayName (required: boolean) {
123 const control = {
124 VALIDATORS: [
125 Validators.minLength(1),
126 Validators.maxLength(120)
127 ],
128 MESSAGES: {
129 'required': this.i18n('Display name is required.'),
130 'minlength': this.i18n('Display name must be at least 1 character long.'),
131 'maxlength': this.i18n('Display name cannot be more than 50 characters long.')
132 }
133 }
134
135 if (required) control.VALIDATORS.push(Validators.required)
136
137 return control
138 }
132} 139}
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 @@
1<div *ngIf="loading"> 1<div *ngIf="loading">
2 <div class="lds-ring"> 2 <div class="loader">
3 <div></div> 3 <div></div>
4 <div></div> 4 <div></div>
5 <div></div> 5 <div></div>
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 @@
3 3
4// Thanks to https://loading.io/css/ (CC0 License) 4// Thanks to https://loading.io/css/ (CC0 License)
5 5
6.lds-ring { 6.loader {
7 display: inline-block; 7 display: inline-block;
8 position: relative; 8 position: relative;
9 width: 50px; 9 width: 50px;
10 height: 50px; 10 height: 50px;
11} 11}
12 12
13.lds-ring div { 13.loader div {
14 box-sizing: border-box; 14 box-sizing: border-box;
15 display: block; 15 display: block;
16 position: absolute; 16 position: absolute;
@@ -19,23 +19,23 @@
19 margin: 6px; 19 margin: 6px;
20 border: 4px solid; 20 border: 4px solid;
21 border-radius: 50%; 21 border-radius: 50%;
22 animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; 22 animation: loader 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
23 border-color: #999999 transparent transparent transparent; 23 border-color: #999999 transparent transparent transparent;
24} 24}
25 25
26.lds-ring div:nth-child(1) { 26.loader div:nth-child(1) {
27 animation-delay: -0.45s; 27 animation-delay: -0.45s;
28} 28}
29 29
30.lds-ring div:nth-child(2) { 30.loader div:nth-child(2) {
31 animation-delay: -0.3s; 31 animation-delay: -0.3s;
32} 32}
33 33
34.lds-ring div:nth-child(3) { 34.loader div:nth-child(3) {
35 animation-delay: -0.15s; 35 animation-delay: -0.15s;
36} 36}
37 37
38@keyframes lds-ring { 38@keyframes loader {
39 0% { 39 0% {
40 transform: rotate(0deg); 40 transform: rotate(0deg);
41 } 41 }
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 {
136 .pipe(catchError(res => this.restExtractor.handleError(res))) 136 .pipe(catchError(res => this.restExtractor.handleError(res)))
137 } 137 }
138 138
139 getNewUsername (oldDisplayName: string, newDisplayName: string, currentUsername: string) {
140 // Don't update display name, the user seems to have changed it
141 if (this.displayNameToUsername(oldDisplayName) !== currentUsername) return currentUsername
142
143 return this.displayNameToUsername(newDisplayName)
144 }
145
146 displayNameToUsername (displayName: string) {
147 if (!displayName) return ''
148
149 return displayName
150 .toLowerCase()
151 .replace(/\s/g, '_')
152 .replace(/[^a-z0-9_.]/g, '')
153 }
154
139 /* ###### Admin methods ###### */ 155 /* ###### Admin methods ###### */
140 156
141 addUser (userCreate: UserCreate) { 157 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
100 previewUrl: null 100 previewUrl: null
101 })) 101 }))
102 102
103
104 this.hydrateFormFromVideo() 103 this.hydrateFormFromVideo()
105 }, 104 },
106 105