]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/videos/+video-watch/comment/video-comments.component.ts
Rewrite infinite scroll
[github/Chocobozzz/PeerTube.git] / client / src / app / videos / +video-watch / comment / video-comments.component.ts
CommitLineData
339632b4 1import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'
4cb6d457 2import { ConfirmService } from '@app/core'
4635f59d 3import { NotificationsService } from 'angular2-notifications'
4cb6d457 4import { VideoComment as VideoCommentInterface, VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model'
4635f59d
C
5import { AuthService } from '../../../core/auth'
6import { ComponentPagination } from '../../../shared/rest/component-pagination.model'
7import { User } from '../../../shared/users'
8import { SortField } from '../../../shared/video/sort-field.type'
47564bbe 9import { VideoDetails } from '../../../shared/video/video-details.model'
4635f59d
C
10import { VideoComment } from './video-comment.model'
11import { VideoCommentService } from './video-comment.service'
12
13@Component({
14 selector: 'my-video-comments',
15 templateUrl: './video-comments.component.html',
16 styleUrls: ['./video-comments.component.scss']
17})
339632b4 18export class VideoCommentsComponent implements OnChanges {
47564bbe 19 @Input() video: VideoDetails
4635f59d
C
20 @Input() user: User
21
22 comments: VideoComment[] = []
23 sort: SortField = '-createdAt'
24 componentPagination: ComponentPagination = {
25 currentPage: 1,
7416fbf3 26 itemsPerPage: 10,
4635f59d
C
27 totalItems: null
28 }
29 inReplyToCommentId: number
30 threadComments: { [ id: number ]: VideoCommentThreadTree } = {}
31 threadLoading: { [ id: number ]: boolean } = {}
32
33 constructor (
34 private authService: AuthService,
35 private notificationsService: NotificationsService,
4cb6d457 36 private confirmService: ConfirmService,
4635f59d
C
37 private videoCommentService: VideoCommentService
38 ) {}
39
339632b4
C
40 ngOnChanges (changes: SimpleChanges) {
41 if (changes['video']) {
42 this.loadVideoComments()
47564bbe 43 }
4635f59d
C
44 }
45
4cb6d457 46 viewReplies (comment: VideoCommentInterface) {
4635f59d
C
47 this.threadLoading[comment.id] = true
48
49 this.videoCommentService.getVideoThreadComments(this.video.id, comment.id)
50 .subscribe(
51 res => {
52 this.threadComments[comment.id] = res
53 this.threadLoading[comment.id] = false
54 },
55
56 err => this.notificationsService.error('Error', err.message)
57 )
58 }
59
7416fbf3
C
60 loadMoreComments () {
61 this.videoCommentService.getVideoCommentThreads(this.video.id, this.componentPagination, this.sort)
62 .subscribe(
63 res => {
64 this.comments = this.comments.concat(res.comments)
65 this.componentPagination.totalItems = res.totalComments
66 },
67
68 err => this.notificationsService.error('Error', err.message)
69 )
70 }
71
4635f59d
C
72 onCommentThreadCreated (comment: VideoComment) {
73 this.comments.unshift(comment)
74 }
75
76 onWantedToReply (comment: VideoComment) {
77 this.inReplyToCommentId = comment.id
78 }
79
80 onResetReply () {
81 this.inReplyToCommentId = undefined
82 }
83
4cb6d457
C
84 onThreadCreated (commentTree: VideoCommentThreadTree) {
85 this.viewReplies(commentTree.comment)
86 }
87
88 onWantedToDelete (commentToDelete: VideoComment) {
89 let message = 'Do you really want to delete this comment?'
90 if (commentToDelete.totalReplies !== 0) message += `${commentToDelete.totalReplies} would be deleted too.`
91
92 this.confirmService.confirm(message, 'Delete').subscribe(
93 res => {
94 if (res === false) return
95
96 this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id)
97 .subscribe(
98 () => {
99 // Delete the comment in the tree
100 if (commentToDelete.inReplyToCommentId) {
101 const thread = this.threadComments[commentToDelete.threadId]
102 if (!thread) {
103 console.error(`Cannot find thread ${commentToDelete.threadId} of the comment to delete ${commentToDelete.id}`)
104 return
105 }
106
107 this.deleteLocalCommentThread(thread, commentToDelete)
108 return
109 }
110
111 // Delete the thread
112 this.comments = this.comments.filter(c => c.id !== commentToDelete.id)
113 this.componentPagination.totalItems--
114 },
115
116 err => this.notificationsService.error('Error', err.message)
117 )
118 }
119 )
120 }
121
4635f59d
C
122 isUserLoggedIn () {
123 return this.authService.isLoggedIn()
124 }
7416fbf3
C
125
126 onNearOfBottom () {
127 this.componentPagination.currentPage++
128
129 if (this.hasMoreComments()) {
130 this.loadMoreComments()
131 }
132 }
133
4cb6d457 134 private hasMoreComments () {
7416fbf3
C
135 // No results
136 if (this.componentPagination.totalItems === 0) return false
137
138 // Not loaded yet
139 if (!this.componentPagination.totalItems) return true
140
141 const maxPage = this.componentPagination.totalItems / this.componentPagination.itemsPerPage
142 return maxPage > this.componentPagination.currentPage
143 }
4cb6d457
C
144
145 private deleteLocalCommentThread (parentComment: VideoCommentThreadTree, commentToDelete: VideoComment) {
146 for (const commentChild of parentComment.children) {
147 if (commentChild.comment.id === commentToDelete.id) {
148 parentComment.children = parentComment.children.filter(c => c.comment.id !== commentToDelete.id)
149 return
150 }
151
152 this.deleteLocalCommentThread(commentChild, commentToDelete)
153 }
154 }
339632b4
C
155
156 private loadVideoComments () {
157 if (this.video.commentsEnabled === true) {
158 // Reset all our fields
159 this.comments = []
160 this.threadComments = {}
161 this.threadLoading = {}
162 this.inReplyToCommentId = undefined
0cd4344f
C
163 this.componentPagination.currentPage = 1
164 this.componentPagination.totalItems = null
339632b4
C
165
166 this.loadMoreComments()
167 }
168 }
4635f59d 169}