]>
Commit | Line | Data |
---|---|---|
67ed6552 C |
1 | import { ChartData } from 'chart.js' |
2 | import { max, maxBy, min, minBy } from 'lodash-es' | |
66357162 C |
3 | import { Subject } from 'rxjs' |
4 | import { debounceTime, mergeMap } from 'rxjs/operators' | |
67ed6552 C |
5 | import { Component, OnInit } from '@angular/core' |
6 | import { AuthService, ConfirmService, Notifier, ScreenService, User } from '@app/core' | |
7 | import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' | |
08c1efbe C |
8 | |
9 | @Component({ | |
17119e4a C |
10 | templateUrl: './my-video-channels.component.html', |
11 | styleUrls: [ './my-video-channels.component.scss' ] | |
08c1efbe | 12 | }) |
17119e4a | 13 | export class MyVideoChannelsComponent implements OnInit { |
4f5d0459 RK |
14 | totalItems: number |
15 | ||
08c1efbe | 16 | videoChannels: VideoChannel[] = [] |
3d527ba1 | 17 | videoChannelsChartData: ChartData[] |
8165d00a RK |
18 | videoChannelsMinimumDailyViews = 0 |
19 | videoChannelsMaximumDailyViews: number | |
08c1efbe | 20 | |
4f5d0459 RK |
21 | channelsSearch: string |
22 | channelsSearchChanged = new Subject<string>() | |
23 | ||
4f926722 C |
24 | chartOptions: any |
25 | ||
08c1efbe C |
26 | private user: User |
27 | ||
28 | constructor ( | |
29 | private authService: AuthService, | |
f8b2c1b4 | 30 | private notifier: Notifier, |
08c1efbe | 31 | private confirmService: ConfirmService, |
b1d40cff | 32 | private videoChannelService: VideoChannelService, |
66357162 C |
33 | private screenService: ScreenService |
34 | ) {} | |
08c1efbe C |
35 | |
36 | ngOnInit () { | |
37 | this.user = this.authService.getUser() | |
38 | ||
39 | this.loadVideoChannels() | |
4f5d0459 RK |
40 | |
41 | this.channelsSearchChanged | |
42 | .pipe(debounceTime(500)) | |
43 | .subscribe(() => { | |
44 | this.loadVideoChannels() | |
45 | }) | |
08c1efbe C |
46 | } |
47 | ||
8165d00a RK |
48 | get isInSmallView () { |
49 | return this.screenService.isInSmallView() | |
50 | } | |
51 | ||
225a7682 | 52 | resetSearch () { |
4f5d0459 RK |
53 | this.channelsSearch = '' |
54 | this.onChannelsSearchChanged() | |
55 | } | |
56 | ||
57 | onChannelsSearchChanged () { | |
58 | this.channelsSearchChanged.next() | |
59 | } | |
60 | ||
08c1efbe C |
61 | async deleteVideoChannel (videoChannel: VideoChannel) { |
62 | const res = await this.confirmService.confirmWithInput( | |
66357162 C |
63 | $localize`Do you really want to delete ${videoChannel.displayName}? |
64 | It will delete ${videoChannel.videosCount} videos uploaded in this channel, and you will not be able to create another | |
65 | channel with the same name (${videoChannel.name})!`, | |
66 | ||
67 | $localize`Please type the display name of the video channel (${videoChannel.displayName}) to confirm`, | |
68 | ||
d88c490d C |
69 | videoChannel.displayName, |
70 | ||
66357162 | 71 | $localize`Delete` |
08c1efbe C |
72 | ) |
73 | if (res === false) return | |
74 | ||
75 | this.videoChannelService.removeVideoChannel(videoChannel) | |
76 | .subscribe( | |
f8b2c1b4 | 77 | () => { |
08c1efbe | 78 | this.loadVideoChannels() |
66357162 | 79 | this.notifier.success($localize`Video channel ${videoChannel.displayName} deleted.`) |
08c1efbe C |
80 | }, |
81 | ||
f8b2c1b4 | 82 | error => this.notifier.error(error.message) |
08c1efbe C |
83 | ) |
84 | } | |
85 | ||
86 | private loadVideoChannels () { | |
87 | this.authService.userInformationLoaded | |
66357162 | 88 | .pipe(mergeMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account, null, true, this.channelsSearch))) |
8165d00a RK |
89 | .subscribe(res => { |
90 | this.videoChannels = res.data | |
4f5d0459 | 91 | this.totalItems = res.total |
3d527ba1 RK |
92 | |
93 | // chart data | |
94 | this.videoChannelsChartData = this.videoChannels.map(v => ({ | |
8165d00a RK |
95 | labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()), |
96 | datasets: [ | |
97 | { | |
66357162 C |
98 | label: $localize`Views for the day`, |
99 | data: v.viewsPerDay.map(day => day.views), | |
100 | fill: false, | |
101 | borderColor: '#c6c6c6' | |
8165d00a RK |
102 | } |
103 | ] | |
3d527ba1 RK |
104 | } as ChartData)) |
105 | ||
106 | // chart options that depend on chart data: | |
107 | // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here | |
108 | this.videoChannelsMinimumDailyViews = min( | |
66357162 C |
109 | // compute local minimum daily views for each channel, by their "views" attribute |
110 | this.videoChannels.map(v => minBy( | |
3d527ba1 RK |
111 | v.viewsPerDay, |
112 | day => day.views | |
113 | ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute | |
114 | ) | |
4f926722 | 115 | |
3d527ba1 | 116 | this.videoChannelsMaximumDailyViews = max( |
66357162 C |
117 | // compute local maximum daily views for each channel, by their "views" attribute |
118 | this.videoChannels.map(v => maxBy( | |
3d527ba1 RK |
119 | v.viewsPerDay, |
120 | day => day.views | |
121 | ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute | |
122 | ) | |
4f926722 C |
123 | |
124 | this.buildChartOptions() | |
8165d00a | 125 | }) |
08c1efbe | 126 | } |
4f926722 C |
127 | |
128 | private buildChartOptions () { | |
129 | this.chartOptions = { | |
130 | legend: { | |
131 | display: false | |
132 | }, | |
133 | scales: { | |
134 | xAxes: [{ | |
135 | display: false | |
136 | }], | |
137 | yAxes: [{ | |
138 | display: false, | |
139 | ticks: { | |
140 | min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), | |
141 | max: Math.max(1, this.videoChannelsMaximumDailyViews) | |
142 | } | |
143 | }] | |
144 | }, | |
145 | layout: { | |
146 | padding: { | |
147 | left: 15, | |
148 | right: 15, | |
149 | top: 10, | |
150 | bottom: 0 | |
151 | } | |
152 | }, | |
153 | elements: { | |
154 | point: { | |
155 | radius: 0 | |
156 | } | |
157 | }, | |
158 | tooltips: { | |
159 | mode: 'index', | |
160 | intersect: false, | |
161 | custom: function (tooltip: any) { | |
162 | if (!tooltip) return | |
163 | // disable displaying the color box | |
164 | tooltip.displayColors = false | |
165 | }, | |
166 | callbacks: { | |
167 | label: (tooltip: any, data: any) => `${tooltip.value} views` | |
168 | } | |
169 | }, | |
170 | hover: { | |
171 | mode: 'index', | |
172 | intersect: false | |
173 | } | |
174 | } | |
175 | } | |
08c1efbe | 176 | } |