aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/app/+my-account/my-account-history/my-account-history.component.html15
-rw-r--r--client/src/app/+my-account/my-account-history/my-account-history.component.scss68
-rw-r--r--client/src/app/+my-account/my-account-history/my-account-history.component.ts66
-rw-r--r--client/src/app/+my-account/my-account-routing.module.ts10
-rw-r--r--client/src/app/+my-account/my-account-videos/my-account-videos.component.scss2
-rw-r--r--client/src/app/+my-account/my-account.component.ts6
-rw-r--r--client/src/app/+my-account/my-account.module.ts4
-rw-r--r--client/src/app/shared/menu/top-menu-dropdown.component.html5
-rw-r--r--client/src/app/shared/menu/top-menu-dropdown.component.scss4
-rw-r--r--client/src/app/shared/menu/top-menu-dropdown.component.ts14
-rw-r--r--client/src/app/shared/shared.module.ts2
-rw-r--r--client/src/app/shared/users/user-history.service.ts45
12 files changed, 234 insertions, 7 deletions
diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.html b/client/src/app/+my-account/my-account-history/my-account-history.component.html
new file mode 100644
index 000000000..653b33f89
--- /dev/null
+++ b/client/src/app/+my-account/my-account-history/my-account-history.component.html
@@ -0,0 +1,15 @@
1<div i18n *ngIf="pagination.totalItems === 0">You don't have history yet.</div>
2
3<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" class="videos" #videosElement>
4 <div *ngFor="let videos of videoPages;" class="videos-page">
5 <div class="video" *ngFor="let video of videos">
6 <my-video-thumbnail [video]="video"></my-video-thumbnail>
7
8 <div class="video-info">
9 <a tabindex="-1" class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
10 <span i18n class="video-info-date-views">{{ video.views | myNumberFormatter }} views</span>
11 <a tabindex="-1" class="video-info-account" [routerLink]="[ '/accounts', video.byAccount ]">{{ video.byAccount }}</a>
12 </div>
13 </div>
14 </div>
15</div>
diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.scss b/client/src/app/+my-account/my-account-history/my-account-history.component.scss
new file mode 100644
index 000000000..115bb0e5c
--- /dev/null
+++ b/client/src/app/+my-account/my-account-history/my-account-history.component.scss
@@ -0,0 +1,68 @@
1@import '_variables';
2@import '_mixins';
3
4.video {
5 @include row-blocks;
6
7 my-video-thumbnail {
8 margin-right: 10px;
9 }
10
11 .video-info {
12 flex-grow: 1;
13
14 .video-info-name {
15 @include disable-default-a-behaviour;
16
17 color: var(--mainForegroundColor);
18 display: block;
19 width: fit-content;
20 font-size: 18px;
21 font-weight: $font-semibold;
22 }
23
24 .video-info-date-views {
25 font-size: 14px;
26 }
27
28 .video-info-account {
29 @include disable-default-a-behaviour;
30
31 display: block;
32 width: fit-content;
33 overflow: hidden;
34 text-overflow: ellipsis;
35 white-space: nowrap;
36 font-size: 14px;
37 color: #585858;
38
39 &:hover {
40 color: #303030;
41 }
42 }
43 }
44}
45
46@media screen and (max-width: $small-view) {
47 .video {
48 flex-direction: column;
49 height: auto;
50 text-align: center;
51
52 .video-info-name {
53 margin: auto;
54 }
55
56 input[type=checkbox] {
57 display: none;
58 }
59
60 my-video-thumbnail {
61 margin-right: 0;
62 }
63
64 .video-buttons {
65 margin-top: 10px;
66 }
67 }
68}
diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.ts b/client/src/app/+my-account/my-account-history/my-account-history.component.ts
new file mode 100644
index 000000000..508552167
--- /dev/null
+++ b/client/src/app/+my-account/my-account-history/my-account-history.component.ts
@@ -0,0 +1,66 @@
1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { Location } from '@angular/common'
4import { immutableAssign } from '@app/shared/misc/utils'
5import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
6import { NotificationsService } from 'angular2-notifications'
7import { AuthService } from '../../core/auth'
8import { ConfirmService } from '../../core/confirm'
9import { AbstractVideoList } from '../../shared/video/abstract-video-list'
10import { VideoService } from '../../shared/video/video.service'
11import { I18n } from '@ngx-translate/i18n-polyfill'
12import { ScreenService } from '@app/shared/misc/screen.service'
13import { UserHistoryService } from '@app/shared/users/user-history.service'
14
15@Component({
16 selector: 'my-account-history',
17 templateUrl: './my-account-history.component.html',
18 styleUrls: [ './my-account-history.component.scss' ]
19})
20export class MyAccountHistoryComponent extends AbstractVideoList implements OnInit, OnDestroy {
21 titlePage: string
22 currentRoute = '/my-account/history/videos'
23 pagination: ComponentPagination = {
24 currentPage: 1,
25 itemsPerPage: 5,
26 totalItems: null
27 }
28
29 protected baseVideoWidth = -1
30 protected baseVideoHeight = 155
31
32 constructor (
33 protected router: Router,
34 protected route: ActivatedRoute,
35 protected authService: AuthService,
36 protected notificationsService: NotificationsService,
37 protected location: Location,
38 protected screenService: ScreenService,
39 protected i18n: I18n,
40 private confirmService: ConfirmService,
41 private videoService: VideoService,
42 private userHistoryService: UserHistoryService
43 ) {
44 super()
45
46 this.titlePage = this.i18n('My videos history')
47 }
48
49 ngOnInit () {
50 super.ngOnInit()
51 }
52
53 ngOnDestroy () {
54 super.ngOnDestroy()
55 }
56
57 getVideosObservable (page: number) {
58 const newPagination = immutableAssign(this.pagination, { currentPage: page })
59
60 return this.userHistoryService.getUserVideosHistory(newPagination)
61 }
62
63 generateSyndicationList () {
64 throw new Error('Method not implemented.')
65 }
66}
diff --git a/client/src/app/+my-account/my-account-routing.module.ts b/client/src/app/+my-account/my-account-routing.module.ts
index 601e517b4..a2cbeaffc 100644
--- a/client/src/app/+my-account/my-account-routing.module.ts
+++ b/client/src/app/+my-account/my-account-routing.module.ts
@@ -13,6 +13,7 @@ import { MyAccountSubscriptionsComponent } from '@app/+my-account/my-account-sub
13import { MyAccountOwnershipComponent } from '@app/+my-account/my-account-ownership/my-account-ownership.component' 13import { MyAccountOwnershipComponent } from '@app/+my-account/my-account-ownership/my-account-ownership.component'
14import { MyAccountBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-blocklist.component' 14import { MyAccountBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-blocklist.component'
15import { MyAccountServerBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-server-blocklist.component' 15import { MyAccountServerBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-server-blocklist.component'
16import { MyAccountHistoryComponent } from '@app/+my-account/my-account-history/my-account-history.component'
16 17
17const myAccountRoutes: Routes = [ 18const myAccountRoutes: Routes = [
18 { 19 {
@@ -114,6 +115,15 @@ const myAccountRoutes: Routes = [
114 title: 'Muted instances' 115 title: 'Muted instances'
115 } 116 }
116 } 117 }
118 },
119 {
120 path: 'history/videos',
121 component: MyAccountHistoryComponent,
122 data: {
123 meta: {
124 title: 'Videos history'
125 }
126 }
117 } 127 }
118 ] 128 ]
119 } 129 }
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
index 2db81a3fe..a735562f8 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
@@ -97,7 +97,7 @@
97 } 97 }
98} 98}
99 99
100@media screen and (max-width: 800px) { 100@media screen and (max-width: $small-view) {
101 .video { 101 .video {
102 flex-direction: column; 102 flex-direction: column;
103 height: auto; 103 height: auto;
diff --git a/client/src/app/+my-account/my-account.component.ts b/client/src/app/+my-account/my-account.component.ts
index d9381ebfa..1bac9547d 100644
--- a/client/src/app/+my-account/my-account.component.ts
+++ b/client/src/app/+my-account/my-account.component.ts
@@ -21,7 +21,7 @@ export class MyAccountComponent {
21 children: [ 21 children: [
22 { 22 {
23 label: this.i18n('My channels'), 23 label: this.i18n('My channels'),
24 routerLink: '/my-account/videos' 24 routerLink: '/my-account/video-channels'
25 }, 25 },
26 { 26 {
27 label: this.i18n('My videos'), 27 label: this.i18n('My videos'),
@@ -30,6 +30,10 @@ export class MyAccountComponent {
30 { 30 {
31 label: this.i18n('My subscriptions'), 31 label: this.i18n('My subscriptions'),
32 routerLink: '/my-account/subscriptions' 32 routerLink: '/my-account/subscriptions'
33 },
34 {
35 label: this.i18n('My history'),
36 routerLink: '/my-account/history/videos'
33 } 37 }
34 ] 38 ]
35 } 39 }
diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts
index 017ebd57d..c05406438 100644
--- a/client/src/app/+my-account/my-account.module.ts
+++ b/client/src/app/+my-account/my-account.module.ts
@@ -21,6 +21,7 @@ import { MyAccountDangerZoneComponent } from '@app/+my-account/my-account-settin
21import { MyAccountSubscriptionsComponent } from '@app/+my-account/my-account-subscriptions/my-account-subscriptions.component' 21import { MyAccountSubscriptionsComponent } from '@app/+my-account/my-account-subscriptions/my-account-subscriptions.component'
22import { MyAccountBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-blocklist.component' 22import { MyAccountBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-blocklist.component'
23import { MyAccountServerBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-server-blocklist.component' 23import { MyAccountServerBlocklistComponent } from '@app/+my-account/my-account-blocklist/my-account-server-blocklist.component'
24import { MyAccountHistoryComponent } from '@app/+my-account/my-account-history/my-account-history.component'
24 25
25@NgModule({ 26@NgModule({
26 imports: [ 27 imports: [
@@ -49,7 +50,8 @@ import { MyAccountServerBlocklistComponent } from '@app/+my-account/my-account-b
49 MyAccountDangerZoneComponent, 50 MyAccountDangerZoneComponent,
50 MyAccountSubscriptionsComponent, 51 MyAccountSubscriptionsComponent,
51 MyAccountBlocklistComponent, 52 MyAccountBlocklistComponent,
52 MyAccountServerBlocklistComponent 53 MyAccountServerBlocklistComponent,
54 MyAccountHistoryComponent
53 ], 55 ],
54 56
55 exports: [ 57 exports: [
diff --git a/client/src/app/shared/menu/top-menu-dropdown.component.html b/client/src/app/shared/menu/top-menu-dropdown.component.html
index 2d6d1c4bf..d3c896019 100644
--- a/client/src/app/shared/menu/top-menu-dropdown.component.html
+++ b/client/src/app/shared/menu/top-menu-dropdown.component.html
@@ -4,7 +4,10 @@
4 <a *ngIf="menuEntry.routerLink" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page">{{ menuEntry.label }}</a> 4 <a *ngIf="menuEntry.routerLink" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page">{{ menuEntry.label }}</a>
5 5
6 <div *ngIf="!menuEntry.routerLink" ngbDropdown class="parent-entry" #dropdown="ngbDropdown" (mouseleave)="closeDropdownIfHovered(dropdown)"> 6 <div *ngIf="!menuEntry.routerLink" ngbDropdown class="parent-entry" #dropdown="ngbDropdown" (mouseleave)="closeDropdownIfHovered(dropdown)">
7 <span (mouseenter)="openDropdownOnHover(dropdown)" role="button" class="title-page" [ngClass]="{ active: !!suffixLabels[menuEntry.label] }" ngbDropdownToggle> 7 <span
8 (mouseenter)="openDropdownOnHover(dropdown)" [ngClass]="{ active: !!suffixLabels[menuEntry.label] }" ngbDropdownAnchor
9 (click)="dropdownAnchorClicked(dropdown)" role="button" class="title-page"
10 >
8 <ng-container i18n>{{ menuEntry.label }}</ng-container> 11 <ng-container i18n>{{ menuEntry.label }}</ng-container>
9 <ng-container *ngIf="!!suffixLabels[menuEntry.label]"> - {{ suffixLabels[menuEntry.label] }}</ng-container> 12 <ng-container *ngIf="!!suffixLabels[menuEntry.label]"> - {{ suffixLabels[menuEntry.label] }}</ng-container>
10 </span> 13 </span>
diff --git a/client/src/app/shared/menu/top-menu-dropdown.component.scss b/client/src/app/shared/menu/top-menu-dropdown.component.scss
index f3ef8f814..77159532f 100644
--- a/client/src/app/shared/menu/top-menu-dropdown.component.scss
+++ b/client/src/app/shared/menu/top-menu-dropdown.component.scss
@@ -12,3 +12,7 @@
12 position: relative; 12 position: relative;
13 top: 2px; 13 top: 2px;
14} 14}
15
16/deep/ .dropdown-menu {
17 margin-top: 0 !important;
18}
diff --git a/client/src/app/shared/menu/top-menu-dropdown.component.ts b/client/src/app/shared/menu/top-menu-dropdown.component.ts
index 272b721b2..e859c30dd 100644
--- a/client/src/app/shared/menu/top-menu-dropdown.component.ts
+++ b/client/src/app/shared/menu/top-menu-dropdown.component.ts
@@ -1,9 +1,8 @@
1import { Component, Input, OnDestroy, OnInit } from '@angular/core' 1import { Component, Input, OnDestroy, OnInit } from '@angular/core'
2import { filter, take } from 'rxjs/operators' 2import { filter, take } from 'rxjs/operators'
3import { NavigationStart, Router } from '@angular/router' 3import { NavigationEnd, Router } from '@angular/router'
4import { Subscription } from 'rxjs' 4import { Subscription } from 'rxjs'
5import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' 5import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
6import { drop } from 'lodash-es'
7 6
8export type TopMenuDropdownParam = { 7export type TopMenuDropdownParam = {
9 label: string 8 label: string
@@ -34,7 +33,7 @@ export class TopMenuDropdownComponent implements OnInit, OnDestroy {
34 this.updateChildLabels(window.location.pathname) 33 this.updateChildLabels(window.location.pathname)
35 34
36 this.routeSub = this.router.events 35 this.routeSub = this.router.events
37 .pipe(filter(event => event instanceof NavigationStart)) 36 .pipe(filter(event => event instanceof NavigationEnd))
38 .subscribe(() => this.updateChildLabels(window.location.pathname)) 37 .subscribe(() => this.updateChildLabels(window.location.pathname))
39 } 38 }
40 39
@@ -52,6 +51,15 @@ export class TopMenuDropdownComponent implements OnInit, OnDestroy {
52 .subscribe(e => this.openedOnHover = false) 51 .subscribe(e => this.openedOnHover = false)
53 } 52 }
54 53
54 dropdownAnchorClicked (dropdown: NgbDropdown) {
55 if (this.openedOnHover) {
56 this.openedOnHover = false
57 return
58 }
59
60 return dropdown.toggle()
61 }
62
55 closeDropdownIfHovered (dropdown: NgbDropdown) { 63 closeDropdownIfHovered (dropdown: NgbDropdown) {
56 if (this.openedOnHover === false) return 64 if (this.openedOnHover === false) return
57 65
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index 9810e9485..4a5d664db 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -62,6 +62,7 @@ import { UserBanModalComponent } from '@app/shared/moderation'
62import { UserModerationDropdownComponent } from '@app/shared/moderation/user-moderation-dropdown.component' 62import { UserModerationDropdownComponent } from '@app/shared/moderation/user-moderation-dropdown.component'
63import { BlocklistService } from '@app/shared/blocklist' 63import { BlocklistService } from '@app/shared/blocklist'
64import { TopMenuDropdownComponent } from '@app/shared/menu/top-menu-dropdown.component' 64import { TopMenuDropdownComponent } from '@app/shared/menu/top-menu-dropdown.component'
65import { UserHistoryService } from '@app/shared/users/user-history.service'
65 66
66@NgModule({ 67@NgModule({
67 imports: [ 68 imports: [
@@ -181,6 +182,7 @@ import { TopMenuDropdownComponent } from '@app/shared/menu/top-menu-dropdown.com
181 VideoChangeOwnershipValidatorsService, 182 VideoChangeOwnershipValidatorsService,
182 VideoAcceptOwnershipValidatorsService, 183 VideoAcceptOwnershipValidatorsService,
183 BlocklistService, 184 BlocklistService,
185 UserHistoryService,
184 186
185 I18nPrimengCalendarService, 187 I18nPrimengCalendarService,
186 ScreenService, 188 ScreenService,
diff --git a/client/src/app/shared/users/user-history.service.ts b/client/src/app/shared/users/user-history.service.ts
new file mode 100644
index 000000000..9ed25bfc7
--- /dev/null
+++ b/client/src/app/shared/users/user-history.service.ts
@@ -0,0 +1,45 @@
1import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core'
3import { environment } from '../../../environments/environment'
4import { RestExtractor } from '../rest/rest-extractor.service'
5import { RestService } from '../rest/rest.service'
6import { Video } from '../video/video.model'
7import { catchError, map, switchMap } from 'rxjs/operators'
8import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
9import { VideoService } from '@app/shared/video/video.service'
10import { ResultList } from '../../../../../shared'
11
12@Injectable()
13export class UserHistoryService {
14 static BASE_USER_VIDEOS_HISTORY_URL = environment.apiUrl + '/api/v1/users/me/history/videos'
15
16 constructor (
17 private authHttp: HttpClient,
18 private restExtractor: RestExtractor,
19 private restService: RestService,
20 private videoService: VideoService
21 ) {}
22
23 getUserVideosHistory (historyPagination: ComponentPagination) {
24 const pagination = this.restService.componentPaginationToRestPagination(historyPagination)
25
26 let params = new HttpParams()
27 params = this.restService.addRestGetParams(params, pagination)
28
29 return this.authHttp
30 .get<ResultList<Video>>(UserHistoryService.BASE_USER_VIDEOS_HISTORY_URL, { params })
31 .pipe(
32 switchMap(res => this.videoService.extractVideos(res)),
33 catchError(err => this.restExtractor.handleError(err))
34 )
35 }
36
37 deleteUserVideosHistory () {
38 return this.authHttp
39 .post(UserHistoryService.BASE_USER_VIDEOS_HISTORY_URL + '/remove', {})
40 .pipe(
41 map(() => this.restExtractor.extractDataBool()),
42 catchError(err => this.restExtractor.handleError(err))
43 )
44 }
45}