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