aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+my-account/my-account-video-channels
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/+my-account/my-account-video-channels')
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts83
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html105
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss67
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts19
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts138
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts41
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html35
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss115
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts159
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts25
10 files changed, 0 insertions, 787 deletions
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts
deleted file mode 100644
index a68f79b47..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts
+++ /dev/null
@@ -1,83 +0,0 @@
1import { Component, OnInit } from '@angular/core'
2import { Router } from '@angular/router'
3import { AuthService, Notifier } from '@app/core'
4import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
5import { VideoChannelCreate } from '../../../../../shared/models/videos'
6import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
7import { I18n } from '@ngx-translate/i18n-polyfill'
8import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
9import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators/video-channel-validators.service'
10
11@Component({
12 selector: 'my-account-video-channel-create',
13 templateUrl: './my-account-video-channel-edit.component.html',
14 styleUrls: [ './my-account-video-channel-edit.component.scss' ]
15})
16export class MyAccountVideoChannelCreateComponent extends MyAccountVideoChannelEdit implements OnInit {
17 error: string
18
19 constructor (
20 protected formValidatorService: FormValidatorService,
21 private authService: AuthService,
22 private videoChannelValidatorsService: VideoChannelValidatorsService,
23 private notifier: Notifier,
24 private router: Router,
25 private videoChannelService: VideoChannelService,
26 private i18n: I18n
27 ) {
28 super()
29 }
30
31 get instanceHost () {
32 return window.location.host
33 }
34
35 ngOnInit () {
36 this.buildForm({
37 name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME,
38 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME,
39 description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION,
40 support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT
41 })
42 }
43
44 formValidated () {
45 this.error = undefined
46
47 const body = this.form.value
48 const videoChannelCreate: VideoChannelCreate = {
49 name: body.name,
50 displayName: body['display-name'],
51 description: body.description || null,
52 support: body.support || null
53 }
54
55 this.videoChannelService.createVideoChannel(videoChannelCreate).subscribe(
56 () => {
57 this.authService.refreshUserInformation()
58
59 this.notifier.success(
60 this.i18n('Video channel {{videoChannelName}} created.', { videoChannelName: videoChannelCreate.displayName })
61 )
62 this.router.navigate([ '/my-account', 'video-channels' ])
63 },
64
65 err => {
66 if (err.status === 409) {
67 this.error = this.i18n('This name already exists on this instance.')
68 return
69 }
70
71 this.error = err.message
72 }
73 )
74 }
75
76 isCreation () {
77 return true
78 }
79
80 getFormButtonTitle () {
81 return this.i18n('Create')
82 }
83}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html
deleted file mode 100644
index 048d143cd..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html
+++ /dev/null
@@ -1,105 +0,0 @@
1<nav aria-label="breadcrumb">
2 <ol class="breadcrumb">
3 <li class="breadcrumb-item">
4 <a routerLink="/my-account/video-channels" i18n>My Channels</a>
5 </li>
6
7 <ng-container *ngIf="isCreation()">
8 <li class="breadcrumb-item active" i18n>Create</li>
9 </ng-container>
10 <ng-container *ngIf="!isCreation()">
11 <li class="breadcrumb-item active" i18n>Edit</li>
12 <li class="breadcrumb-item active" aria-current="page">
13 <a *ngIf="videoChannelToUpdate" [routerLink]="[ '/my-account/video-channels/update', videoChannelToUpdate?.nameWithHost ]">{{ videoChannelToUpdate?.displayName }}</a>
14 </li>
15 </ng-container>
16 </ol>
17</nav>
18
19<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
20
21<form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
22
23 <div class="form-row"> <!-- channel grid -->
24 <div class="form-group col-12 col-lg-4 col-xl-3">
25 <div *ngIf="isCreation()" class="video-channel-title" i18n>NEW CHANNEL</div>
26 <div *ngIf="!isCreation() && videoChannelToUpdate" class="video-channel-title" i18n>CHANNEL</div>
27 </div>
28
29 <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
30
31 <div class="form-group" *ngIf="isCreation()">
32 <label i18n for="name">Name</label>
33 <div class="input-group">
34 <input
35 type="text" id="name" i18n-placeholder placeholder="Example: my_channel"
36 formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" class="form-control"
37 >
38 <div class="input-group-append">
39 <span class="input-group-text">@{{ instanceHost }}</span>
40 </div>
41 </div>
42 <div *ngIf="formErrors['name']" class="form-error">
43 {{ formErrors['name'] }}
44 </div>
45 </div>
46
47 <my-actor-avatar-info
48 *ngIf="!isCreation() && videoChannelToUpdate"
49 [actor]="videoChannelToUpdate" (avatarChange)="onAvatarChange($event)"
50 ></my-actor-avatar-info>
51
52 <div class="form-group">
53 <label i18n for="display-name">Display name</label>
54 <input
55 type="text" id="display-name" class="form-control"
56 formControlName="display-name" [ngClass]="{ 'input-error': formErrors['display-name'] }"
57 >
58 <div *ngIf="formErrors['display-name']" class="form-error">
59 {{ formErrors['display-name'] }}
60 </div>
61 </div>
62
63 <div class="form-group">
64 <label i18n for="description">Description</label>
65 <textarea
66 id="description" formControlName="description" class="form-control"
67 [ngClass]="{ 'input-error': formErrors['description'] }"
68 ></textarea>
69 <div *ngIf="formErrors.description" class="form-error">
70 {{ formErrors.description }}
71 </div>
72 </div>
73
74 <div class="form-group">
75 <label for="support">Support</label>
76 <my-help
77 helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support your channel (membership platform...).<br /><br />
78 When you will upload a video in this channel, the video support field will be automatically filled by this text."
79 ></my-help>
80 <my-markdown-textarea
81 id="support" formControlName="support" textareaMaxWidth="500px" markdownType="enhanced"
82 [classes]="{ 'input-error': formErrors['support'] }"
83 ></my-markdown-textarea>
84 <div *ngIf="formErrors.support" class="form-error">
85 {{ formErrors.support }}
86 </div>
87 </div>
88
89 <div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()">
90 <my-peertube-checkbox
91 inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate"
92 i18n-labelText labelText="Overwrite support field of all videos of this channel"
93 ></my-peertube-checkbox>
94 </div>
95
96 </div>
97 </div>
98
99 <div class="form-row"> <!-- submit placement block -->
100 <div class="col-md-7 col-xl-5"></div>
101 <div class="col-md-5 col-xl-5 d-inline-flex">
102 <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
103 </div>
104 </div>
105</form>
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss
deleted file mode 100644
index 8f8af655c..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.scss
+++ /dev/null
@@ -1,67 +0,0 @@
1@import '_variables';
2@import '_mixins';
3
4label {
5 font-weight: $font-regular;
6 font-size: 100%;
7}
8
9.video-channel-title {
10 @include settings-big-title;
11}
12
13my-actor-avatar-info {
14 display: block;
15 margin-bottom: 20px;
16}
17
18.input-group {
19 @include peertube-input-group(fit-content);
20}
21
22.input-group-append {
23 height: 30px;
24}
25
26input {
27 &[type=text] {
28 @include peertube-input-text(340px);
29
30 display: block;
31
32 &#name {
33 width: auto;
34 flex-grow: 1;
35 }
36 }
37
38 &[type=submit] {
39 @include peertube-button;
40 @include orange-button;
41 margin-left: auto;
42 }
43}
44
45textarea {
46 @include peertube-textarea(500px, 150px);
47
48 display: block;
49}
50
51.peertube-select-container {
52 @include peertube-select-container(340px);
53}
54
55.breadcrumb {
56 @include breadcrumb;
57}
58
59@media screen and (max-width: $small-view) {
60 input[type=text]#name {
61 width: auto !important;
62 }
63
64 label[for=name] + div, textarea {
65 width: 100%;
66 }
67}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
deleted file mode 100644
index 355cb4f55..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
+++ /dev/null
@@ -1,19 +0,0 @@
1import { FormReactive } from '@app/shared'
2import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
3
4export abstract class MyAccountVideoChannelEdit extends FormReactive {
5 // We need it even in the create component because it's used in the edit template
6 videoChannelToUpdate: VideoChannel
7 instanceHost: string
8
9 abstract isCreation (): boolean
10 abstract getFormButtonTitle (): string
11
12 // We need this method so angular does not complain in child template that doesn't need this
13 onAvatarChange (formData: FormData) { /* empty */ }
14
15 // Should be implemented by the child
16 isBulkUpdateVideosDisplayed () {
17 return false
18 }
19}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
deleted file mode 100644
index 9c948b367..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
+++ /dev/null
@@ -1,138 +0,0 @@
1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { AuthService, Notifier, ServerService } from '@app/core'
4import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
5import { VideoChannelUpdate } from '../../../../../shared/models/videos'
6import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
7import { Subscription } from 'rxjs'
8import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
9import { I18n } from '@ngx-translate/i18n-polyfill'
10import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
11import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators/video-channel-validators.service'
12import { ServerConfig } from '@shared/models'
13
14@Component({
15 selector: 'my-account-video-channel-update',
16 templateUrl: './my-account-video-channel-edit.component.html',
17 styleUrls: [ './my-account-video-channel-edit.component.scss' ]
18})
19export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelEdit implements OnInit, OnDestroy {
20 error: string
21 videoChannelToUpdate: VideoChannel
22
23 private paramsSub: Subscription
24 private oldSupportField: string
25 private serverConfig: ServerConfig
26
27 constructor (
28 protected formValidatorService: FormValidatorService,
29 private authService: AuthService,
30 private videoChannelValidatorsService: VideoChannelValidatorsService,
31 private notifier: Notifier,
32 private router: Router,
33 private route: ActivatedRoute,
34 private videoChannelService: VideoChannelService,
35 private i18n: I18n,
36 private serverService: ServerService
37 ) {
38 super()
39 }
40
41 ngOnInit () {
42 this.serverConfig = this.serverService.getTmpConfig()
43 this.serverService.getConfig()
44 .subscribe(config => this.serverConfig = config)
45
46 this.buildForm({
47 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME,
48 description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION,
49 support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT,
50 bulkVideosSupportUpdate: null
51 })
52
53 this.paramsSub = this.route.params.subscribe(routeParams => {
54 const videoChannelId = routeParams['videoChannelId']
55
56 this.videoChannelService.getVideoChannel(videoChannelId).subscribe(
57 videoChannelToUpdate => {
58 this.videoChannelToUpdate = videoChannelToUpdate
59
60 this.oldSupportField = videoChannelToUpdate.support
61
62 this.form.patchValue({
63 'display-name': videoChannelToUpdate.displayName,
64 description: videoChannelToUpdate.description,
65 support: videoChannelToUpdate.support
66 })
67 },
68
69 err => this.error = err.message
70 )
71 })
72 }
73
74 ngOnDestroy () {
75 if (this.paramsSub) this.paramsSub.unsubscribe()
76 }
77
78 formValidated () {
79 this.error = undefined
80
81 const body = this.form.value
82 const videoChannelUpdate: VideoChannelUpdate = {
83 displayName: body['display-name'],
84 description: body.description || null,
85 support: body.support || null,
86 bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false
87 }
88
89 this.videoChannelService.updateVideoChannel(this.videoChannelToUpdate.name, videoChannelUpdate).subscribe(
90 () => {
91 this.authService.refreshUserInformation()
92
93 this.notifier.success(
94 this.i18n('Video channel {{videoChannelName}} updated.', { videoChannelName: videoChannelUpdate.displayName })
95 )
96
97 this.router.navigate([ '/my-account', 'video-channels' ])
98 },
99
100 err => this.error = err.message
101 )
102 }
103
104 onAvatarChange (formData: FormData) {
105 this.videoChannelService.changeVideoChannelAvatar(this.videoChannelToUpdate.name, formData)
106 .subscribe(
107 data => {
108 this.notifier.success(this.i18n('Avatar changed.'))
109
110 this.videoChannelToUpdate.updateAvatar(data.avatar)
111 },
112
113 err => this.notifier.error(err.message)
114 )
115 }
116
117 get maxAvatarSize () {
118 return this.serverConfig.avatar.file.size.max
119 }
120
121 get avatarExtensions () {
122 return this.serverConfig.avatar.file.extensions.join(',')
123 }
124
125 isCreation () {
126 return false
127 }
128
129 getFormButtonTitle () {
130 return this.i18n('Update')
131 }
132
133 isBulkUpdateVideosDisplayed () {
134 if (this.oldSupportField === undefined) return false
135
136 return this.oldSupportField !== this.form.value['support']
137 }
138}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts
deleted file mode 100644
index 94037e18f..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels-routing.module.ts
+++ /dev/null
@@ -1,41 +0,0 @@
1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router'
3import { MyAccountVideoChannelUpdateComponent } from './my-account-video-channel-update.component'
4import { MyAccountVideoChannelCreateComponent } from './my-account-video-channel-create.component'
5import { MyAccountVideoChannelsComponent } from './my-account-video-channels.component'
6
7const myAccountVideoChannelsRoutes: Routes = [
8 {
9 path: '',
10 component: MyAccountVideoChannelsComponent,
11 data: {
12 meta: {
13 title: 'Account video channels'
14 }
15 }
16 },
17 {
18 path: 'create',
19 component: MyAccountVideoChannelCreateComponent,
20 data: {
21 meta: {
22 title: 'Create new video channel'
23 }
24 }
25 },
26 {
27 path: 'update/:videoChannelId',
28 component: MyAccountVideoChannelUpdateComponent,
29 data: {
30 meta: {
31 title: 'Update video channel'
32 }
33 }
34 }
35]
36
37@NgModule({
38 imports: [ RouterModule.forChild(myAccountVideoChannelsRoutes) ],
39 exports: [ RouterModule ]
40})
41export class MyAccountVideoChannelsRoutingModule {}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html
deleted file mode 100644
index b2e8210d3..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html
+++ /dev/null
@@ -1,35 +0,0 @@
1<h1 class="sr-only" i18n>My channels</h1>
2<div class="video-channels-header">
3 <a class="create-button" routerLink="create">
4 <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
5 <ng-container i18n>Create video channel</ng-container>
6 </a>
7</div>
8
9<div class="video-channels">
10 <div *ngFor="let videoChannel of videoChannels; let i = index" class="video-channel">
11 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]">
12 <img [src]="videoChannel.avatarUrl" alt="Avatar" />
13 </a>
14
15 <div class="video-channel-info">
16 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" class="video-channel-names" i18n-title title="Channel page">
17 <div class="video-channel-display-name">{{ videoChannel.displayName }}</div>
18 <div class="video-channel-name">{{ videoChannel.nameWithHost }}</div>
19 </a>
20
21 <div i18n class="video-channel-followers">{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div>
22
23 <div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div>
24
25 <div class="video-channel-buttons">
26 <my-edit-button [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button>
27 <my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button>
28 </div>
29
30 <div *ngIf="!isInSmallView" class="w-100 d-flex justify-content-end">
31 <p-chart *ngIf="videoChannelsChartData && videoChannelsChartData[i]" type="line" [data]="videoChannelsChartData[i]" [options]="chartOptions" width="40vw" height="100px"></p-chart>
32 </div>
33 </div>
34 </div>
35</div>
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss
deleted file mode 100644
index 76fb2cde0..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.scss
+++ /dev/null
@@ -1,115 +0,0 @@
1@import '_variables';
2@import '_mixins';
3
4.create-button {
5 @include create-button;
6}
7
8::ng-deep .action-button {
9 &.action-button-edit {
10 margin-right: 10px;
11 }
12}
13
14.video-channel {
15 @include row-blocks;
16 padding-bottom: 0;
17
18 img {
19 @include avatar(80px);
20
21 margin-right: 10px;
22 }
23
24 .video-channel-info {
25 flex-grow: 1;
26
27 a.video-channel-names {
28 @include disable-default-a-behaviour;
29
30 width: fit-content;
31 display: flex;
32 align-items: baseline;
33 color: pvar(--mainForegroundColor);
34
35 .video-channel-display-name {
36 font-weight: $font-semibold;
37 font-size: 18px;
38 }
39
40 .video-channel-name {
41 font-size: 14px;
42 color: $grey-actor-name;
43 margin-left: 5px;
44 }
45
46 .video-channel-followers {
47
48 }
49 }
50 }
51
52 .video-channel-buttons {
53 margin-top: 10px;
54 min-width: 190px;
55 }
56}
57
58.video-channels-header {
59 text-align: right;
60 margin: 20px 0 50px;
61}
62
63::ng-deep .chartjs-render-monitor {
64 position: relative;
65 top: 1px;
66}
67
68@media screen and (max-width: $small-view) {
69 .video-channels-header {
70 text-align: center;
71 }
72
73 .video-channel {
74 padding-bottom: 10px;
75
76 .video-channel-info {
77 padding-bottom: 10px;
78 text-align: center;
79
80 .video-channel-names {
81 flex-direction: column;
82 align-items: center !important;
83 margin: auto;
84
85 .video-channel-name {
86 margin-left: 0px !important;
87 }
88 }
89 }
90
91 img {
92 margin-right: 0;
93 }
94
95 .video-channel-buttons {
96 align-self: center;
97 }
98 }
99}
100
101@media screen and (min-width: breakpoint(lg)) {
102 :host-context(.main-col:not(.expanded)) {
103 .video-channel-buttons {
104 float: right;
105 }
106 }
107}
108
109@media screen and (min-width: $small-view) {
110 :host-context(.expanded) {
111 .video-channel-buttons {
112 float: right;
113 }
114 }
115}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
deleted file mode 100644
index 9caefe5b1..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
+++ /dev/null
@@ -1,159 +0,0 @@
1import { Component, OnInit } from '@angular/core'
2import { Notifier } from '@app/core'
3import { AuthService } from '../../core/auth'
4import { ConfirmService } from '../../core/confirm'
5import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
6import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
7import { ScreenService } from '@app/shared/misc/screen.service'
8import { User } from '@app/shared'
9import { flatMap } from 'rxjs/operators'
10import { I18n } from '@ngx-translate/i18n-polyfill'
11import { min, minBy, max, maxBy } from 'lodash-es'
12import { ChartData } from 'chart.js'
13
14@Component({
15 selector: 'my-account-video-channels',
16 templateUrl: './my-account-video-channels.component.html',
17 styleUrls: [ './my-account-video-channels.component.scss' ]
18})
19export class MyAccountVideoChannelsComponent implements OnInit {
20 videoChannels: VideoChannel[] = []
21 videoChannelsChartData: ChartData[]
22 videoChannelsMinimumDailyViews = 0
23 videoChannelsMaximumDailyViews: number
24
25 private user: User
26
27 constructor (
28 private authService: AuthService,
29 private notifier: Notifier,
30 private confirmService: ConfirmService,
31 private videoChannelService: VideoChannelService,
32 private screenService: ScreenService,
33 private i18n: I18n
34 ) {}
35
36 ngOnInit () {
37 this.user = this.authService.getUser()
38
39 this.loadVideoChannels()
40 }
41
42 get isInSmallView () {
43 return this.screenService.isInSmallView()
44 }
45
46 get chartOptions () {
47 return {
48 legend: {
49 display: false
50 },
51 scales: {
52 xAxes: [{
53 display: false
54 }],
55 yAxes: [{
56 display: false,
57 ticks: {
58 min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)),
59 max: Math.max(1, this.videoChannelsMaximumDailyViews)
60 }
61 }]
62 },
63 layout: {
64 padding: {
65 left: 15,
66 right: 15,
67 top: 10,
68 bottom: 0
69 }
70 },
71 elements: {
72 point: {
73 radius: 0
74 }
75 },
76 tooltips: {
77 mode: 'index',
78 intersect: false,
79 custom: function (tooltip: any) {
80 if (!tooltip) return
81 // disable displaying the color box
82 tooltip.displayColors = false
83 },
84 callbacks: {
85 label: (tooltip: any, data: any) => `${tooltip.value} views`
86 }
87 },
88 hover: {
89 mode: 'index',
90 intersect: false
91 }
92 }
93 }
94
95 async deleteVideoChannel (videoChannel: VideoChannel) {
96 const res = await this.confirmService.confirmWithInput(
97 this.i18n(
98 // tslint:disable
99 'Do you really want to delete {{channelDisplayName}}? It will delete {{videosCount}} videos uploaded in this channel, and you will not be able to create another channel with the same name ({{channelName}})!',
100 { channelDisplayName: videoChannel.displayName, videosCount: videoChannel.videosCount, channelName: videoChannel.name }
101 ),
102 this.i18n(
103 'Please type the display name of the video channel ({{displayName}}) to confirm',
104 { displayName: videoChannel.displayName }
105 ),
106 videoChannel.displayName,
107 this.i18n('Delete')
108 )
109 if (res === false) return
110
111 this.videoChannelService.removeVideoChannel(videoChannel)
112 .subscribe(
113 () => {
114 this.loadVideoChannels()
115 this.notifier.success(
116 this.i18n('Video channel {{videoChannelName}} deleted.', { videoChannelName: videoChannel.displayName })
117 )
118 },
119
120 error => this.notifier.error(error.message)
121 )
122 }
123
124 private loadVideoChannels () {
125 this.authService.userInformationLoaded
126 .pipe(flatMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true)))
127 .subscribe(res => {
128 this.videoChannels = res.data
129
130 // chart data
131 this.videoChannelsChartData = this.videoChannels.map(v => ({
132 labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()),
133 datasets: [
134 {
135 label: this.i18n('Views for the day'),
136 data: v.viewsPerDay.map(day => day.views),
137 fill: false,
138 borderColor: "#c6c6c6"
139 }
140 ]
141 } as ChartData))
142
143 // chart options that depend on chart data:
144 // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here
145 this.videoChannelsMinimumDailyViews = min(
146 this.videoChannels.map(v => minBy( // compute local minimum daily views for each channel, by their "views" attribute
147 v.viewsPerDay,
148 day => day.views
149 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute
150 )
151 this.videoChannelsMaximumDailyViews = max(
152 this.videoChannels.map(v => maxBy( // compute local maximum daily views for each channel, by their "views" attribute
153 v.viewsPerDay,
154 day => day.views
155 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute
156 )
157 })
158 }
159}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts
deleted file mode 100644
index 87d6b762f..000000000
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.module.ts
+++ /dev/null
@@ -1,25 +0,0 @@
1import { NgModule } from '@angular/core'
2import { ChartModule } from 'primeng/chart'
3import { MyAccountVideoChannelsRoutingModule } from './my-account-video-channels-routing.module'
4import { MyAccountVideoChannelsComponent } from './my-account-video-channels.component'
5import { MyAccountVideoChannelCreateComponent } from './my-account-video-channel-create.component'
6import { MyAccountVideoChannelUpdateComponent } from './my-account-video-channel-update.component'
7import { SharedModule } from '@app/shared'
8
9@NgModule({
10 imports: [
11 MyAccountVideoChannelsRoutingModule,
12 SharedModule,
13 ChartModule
14 ],
15
16 declarations: [
17 MyAccountVideoChannelsComponent,
18 MyAccountVideoChannelCreateComponent,
19 MyAccountVideoChannelUpdateComponent
20 ],
21
22 exports: [],
23 providers: []
24})
25export class MyAccountVideoChannelsModule { }