aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.html2
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts132
2 files changed, 77 insertions, 57 deletions
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
index d97c35eff..5bef4a6ed 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
@@ -26,7 +26,7 @@
26 26
27<div class="no-results" i18n *ngIf="totalItems === 0">No channel found.</div> 27<div class="no-results" i18n *ngIf="totalItems === 0">No channel found.</div>
28 28
29<div class="video-channels"> 29<div class="video-channels" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [dataObservable]="onChannelDataSubject.asObservable()">
30 <div *ngFor="let videoChannel of videoChannels; let i = index" class="video-channel"> 30 <div *ngFor="let videoChannel of videoChannels; let i = index" class="video-channel">
31 <my-actor-avatar [actor]="videoChannel" actorType="channel" [internalHref]="[ '/c', videoChannel.nameWithHost ]" size="80"></my-actor-avatar> 31 <my-actor-avatar [actor]="videoChannel" actorType="channel" [internalHref]="[ '/c', videoChannel.nameWithHost ]" size="80"></my-actor-avatar>
32 32
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
index ece59c2ff..633720a6c 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
@@ -1,8 +1,8 @@
1import { ChartData, ChartOptions, TooltipItem, TooltipModel } from 'chart.js' 1import { ChartData, ChartOptions, TooltipItem, TooltipModel } from 'chart.js'
2import { max, maxBy, min, minBy } from 'lodash-es' 2import { max, maxBy, min, minBy } from 'lodash-es'
3import { mergeMap } from 'rxjs/operators' 3import { Subject } from 'rxjs'
4import { Component } from '@angular/core' 4import { Component } from '@angular/core'
5import { AuthService, ConfirmService, Notifier, ScreenService } from '@app/core' 5import { AuthService, ComponentPagination, ConfirmService, hasMoreItems, Notifier, ScreenService } from '@app/core'
6import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' 6import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
7 7
8@Component({ 8@Component({
@@ -15,13 +15,19 @@ export class MyVideoChannelsComponent {
15 videoChannels: VideoChannel[] = [] 15 videoChannels: VideoChannel[] = []
16 16
17 videoChannelsChartData: ChartData[] 17 videoChannelsChartData: ChartData[]
18 videoChannelsMinimumDailyViews = 0
19 videoChannelsMaximumDailyViews: number
20 18
21 chartOptions: ChartOptions 19 chartOptions: ChartOptions
22 20
23 search: string 21 search: string
24 22
23 onChannelDataSubject = new Subject<any>()
24
25 pagination: ComponentPagination = {
26 currentPage: 1,
27 itemsPerPage: 10,
28 totalItems: null
29 }
30
25 constructor ( 31 constructor (
26 private authService: AuthService, 32 private authService: AuthService,
27 private notifier: Notifier, 33 private notifier: Notifier,
@@ -36,7 +42,12 @@ export class MyVideoChannelsComponent {
36 42
37 onSearch (search: string) { 43 onSearch (search: string) {
38 this.search = search 44 this.search = search
39 this.loadVideoChannels() 45
46 this.pagination.currentPage = 1
47 this.videoChannels = []
48
49 this.authService.userInformationLoaded
50 .subscribe(() => this.loadMoreVideoChannels())
40 } 51 }
41 52
42 async deleteVideoChannel (videoChannel: VideoChannel) { 53 async deleteVideoChannel (videoChannel: VideoChannel) {
@@ -56,7 +67,7 @@ channel with the same name (${videoChannel.name})!`,
56 this.videoChannelService.removeVideoChannel(videoChannel) 67 this.videoChannelService.removeVideoChannel(videoChannel)
57 .subscribe({ 68 .subscribe({
58 next: () => { 69 next: () => {
59 this.loadVideoChannels() 70 this.videoChannels = this.videoChannels.filter(c => c.id !== videoChannel.id)
60 this.notifier.success($localize`Video channel ${videoChannel.displayName} deleted.`) 71 this.notifier.success($localize`Video channel ${videoChannel.displayName} deleted.`)
61 }, 72 },
62 73
@@ -64,58 +75,67 @@ channel with the same name (${videoChannel.name})!`,
64 }) 75 })
65 } 76 }
66 77
67 private loadVideoChannels () { 78 onNearOfBottom () {
68 this.authService.userInformationLoaded 79 if (!hasMoreItems(this.pagination)) return
69 .pipe(mergeMap(() => { 80
70 const user = this.authService.getUser() 81 this.pagination.currentPage += 1
71 const options = {
72 account: user.account,
73 withStats: true,
74 search: this.search,
75 sort: '-updatedAt'
76 }
77 82
78 return this.videoChannelService.listAccountVideoChannels(options) 83 this.loadMoreVideoChannels()
79 })).subscribe(res => { 84 }
80 this.videoChannels = res.data 85
81 this.totalItems = res.total 86 private loadMoreVideoChannels () {
82 87 const user = this.authService.getUser()
83 // chart data 88 const options = {
84 this.videoChannelsChartData = this.videoChannels.map(v => ({ 89 account: user.account,
85 labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()), 90 withStats: true,
86 datasets: [ 91 search: this.search,
87 { 92 componentPagination: this.pagination,
88 label: $localize`Views for the day`, 93 sort: '-updatedAt'
89 data: v.viewsPerDay.map(day => day.views), 94 }
90 fill: false, 95
91 borderColor: '#c6c6c6' 96 return this.videoChannelService.listAccountVideoChannels(options)
92 } 97 .subscribe(res => {
93 ] 98 this.videoChannels = this.videoChannels.concat(res.data)
94 } as ChartData)) 99 this.totalItems = res.total
95 100
96 // chart options that depend on chart data: 101 // chart data
97 // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here 102 this.videoChannelsChartData = this.videoChannels.map(v => ({
98 this.videoChannelsMinimumDailyViews = min( 103 labels: v.viewsPerDay.map(day => day.date.toLocaleDateString()),
99 // compute local minimum daily views for each channel, by their "views" attribute 104 datasets: [
100 this.videoChannels.map(v => minBy( 105 {
101 v.viewsPerDay, 106 label: $localize`Views for the day`,
102 day => day.views 107 data: v.viewsPerDay.map(day => day.views),
103 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute 108 fill: false,
104 ) 109 borderColor: '#c6c6c6'
105 110 }
106 this.videoChannelsMaximumDailyViews = max( 111 ]
107 // compute local maximum daily views for each channel, by their "views" attribute 112 } as ChartData))
108 this.videoChannels.map(v => maxBy( 113
109 v.viewsPerDay, 114 this.buildChartOptions()
110 day => day.views 115
111 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute 116 this.onChannelDataSubject.next(res.data)
112 ) 117 })
113
114 this.buildChartOptions()
115 })
116 } 118 }
117 119
118 private buildChartOptions () { 120 private buildChartOptions () {
121 // chart options that depend on chart data:
122 // we don't want to skew values and have min at 0, so we define what the floor/ceiling is here
123 const videoChannelsMinimumDailyViews = min(
124 // compute local minimum daily views for each channel, by their "views" attribute
125 this.videoChannels.map(v => minBy(
126 v.viewsPerDay,
127 day => day.views
128 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute
129 )
130
131 const videoChannelsMaximumDailyViews = max(
132 // compute local maximum daily views for each channel, by their "views" attribute
133 this.videoChannels.map(v => maxBy(
134 v.viewsPerDay,
135 day => day.views
136 ).views) // the object returned is a ViewPerDate, so we still need to get the views attribute
137 )
138
119 this.chartOptions = { 139 this.chartOptions = {
120 plugins: { 140 plugins: {
121 legend: { 141 legend: {
@@ -141,8 +161,8 @@ channel with the same name (${videoChannel.name})!`,
141 }, 161 },
142 y: { 162 y: {
143 display: false, 163 display: false,
144 min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), 164 min: Math.max(0, videoChannelsMinimumDailyViews - (3 * videoChannelsMaximumDailyViews / 100)),
145 max: Math.max(1, this.videoChannelsMaximumDailyViews) 165 max: Math.max(1, videoChannelsMaximumDailyViews)
146 } 166 }
147 }, 167 },
148 layout: { 168 layout: {