]>
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 | ||
48 | $localize`Please type the display name of the video channel (${videoChannel.displayName}) to confirm`, | |
49 | ||
d88c490d C |
50 | videoChannel.displayName, |
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() | |
71 | ||
72 | return this.videoChannelService.listAccountVideoChannels(user.account, null, true, this.search) | |
73 | })).subscribe(res => { | |
8165d00a | 74 | this.videoChannels = res.data |
4f5d0459 | 75 | this.totalItems = res.total |
3d527ba1 RK |
76 | |
77 | // chart data | |
78 | this.videoChannelsChartData = this.videoChannels.map(v => ({ | |
8165d00a RK |
79 | labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()), |
80 | datasets: [ | |
81 | { | |
66357162 C |
82 | label: $localize`Views for the day`, |
83 | data: v.viewsPerDay.map(day => day.views), | |
84 | fill: false, | |
85 | borderColor: '#c6c6c6' | |
8165d00a RK |
86 | } |
87 | ] | |
3d527ba1 RK |
88 | } as ChartData)) |
89 | ||
90 | // chart options that depend on chart data: | |
91 | // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here | |
92 | this.videoChannelsMinimumDailyViews = min( | |
66357162 C |
93 | // compute local minimum daily views for each channel, by their "views" attribute |
94 | this.videoChannels.map(v => minBy( | |
3d527ba1 RK |
95 | v.viewsPerDay, |
96 | day => day.views | |
97 | ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute | |
98 | ) | |
4f926722 | 99 | |
3d527ba1 | 100 | this.videoChannelsMaximumDailyViews = max( |
66357162 C |
101 | // compute local maximum daily views for each channel, by their "views" attribute |
102 | this.videoChannels.map(v => maxBy( | |
3d527ba1 RK |
103 | v.viewsPerDay, |
104 | day => day.views | |
105 | ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute | |
106 | ) | |
4f926722 C |
107 | |
108 | this.buildChartOptions() | |
8165d00a | 109 | }) |
08c1efbe | 110 | } |
4f926722 C |
111 | |
112 | private buildChartOptions () { | |
113 | this.chartOptions = { | |
114 | legend: { | |
115 | display: false | |
116 | }, | |
117 | scales: { | |
118 | xAxes: [{ | |
119 | display: false | |
120 | }], | |
121 | yAxes: [{ | |
122 | display: false, | |
123 | ticks: { | |
124 | min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), | |
125 | max: Math.max(1, this.videoChannelsMaximumDailyViews) | |
126 | } | |
127 | }] | |
128 | }, | |
129 | layout: { | |
130 | padding: { | |
131 | left: 15, | |
132 | right: 15, | |
133 | top: 10, | |
134 | bottom: 0 | |
135 | } | |
136 | }, | |
137 | elements: { | |
138 | point: { | |
139 | radius: 0 | |
140 | } | |
141 | }, | |
142 | tooltips: { | |
143 | mode: 'index', | |
144 | intersect: false, | |
145 | custom: function (tooltip: any) { | |
146 | if (!tooltip) return | |
147 | // disable displaying the color box | |
148 | tooltip.displayColors = false | |
149 | }, | |
150 | callbacks: { | |
151 | label: (tooltip: any, data: any) => `${tooltip.value} views` | |
152 | } | |
153 | }, | |
154 | hover: { | |
155 | mode: 'index', | |
156 | intersect: false | |
157 | } | |
158 | } | |
159 | } | |
08c1efbe | 160 | } |