3 CommentThreadInterface,
6 InternalEventBusInterface,
7 } from '@proton/docs-shared'
8 import { CommentThreadState, CommentsEvent } from '@proton/docs-shared'
10 export class LocalCommentsState {
11 private threads: CommentThreadInterface[] = []
12 private unreadThreadIDs = new Set<string>()
14 constructor(private eventBus: InternalEventBusInterface) {}
16 getAllThreads(): CommentThreadInterface[] {
20 hasUnreadThreads(): boolean {
21 return this.unreadThreadIDs.size > 0
24 markThreadAsRead(id: string): void {
25 if (this.unreadThreadIDs.has(id)) {
26 this.unreadThreadIDs.delete(id)
27 this.notifyLocalListeners()
31 findThreadById(threadId: string): CommentThreadInterface | undefined {
32 return this.threads.find((thread) => thread.id === threadId)
35 addThread(thread: CommentThreadInterface, markUnread = false) {
36 this.threads = this.threads.filter((existing) => existing.id !== thread.id)
38 this.threads.push(thread)
41 this.unreadThreadIDs.add(thread.id)
44 this.notifyLocalListeners()
47 deleteThread(id: string): void {
48 this.threads = this.threads.filter((thread) => thread.id !== id)
50 if (this.unreadThreadIDs.has(id)) {
51 this.unreadThreadIDs.delete(id)
54 this.notifyLocalListeners()
57 resolveThread(threadId: string) {
58 const thread = this.findThreadById(threadId)
62 thread.state = CommentThreadState.Resolved
63 this.sortThreadsAndNotify()
67 unresolveThread(threadId: string) {
68 const thread = this.findThreadById(threadId)
72 thread.state = CommentThreadState.Active
73 this.sortThreadsAndNotify()
77 changeThreadState(threadId: string, state: CommentThreadState) {
78 const thread = this.findThreadById(threadId)
83 this.sortThreadsAndNotify()
87 addComment(comment: CommentInterface, threadID: string, markUnread = false): void {
88 const thread = this.findThreadById(threadID)
92 thread.comments.push(comment)
94 this.unreadThreadIDs.add(thread.id)
96 this.notifyLocalListeners()
99 editComment({ commentID, threadID, content, markThreadUnread = false }: EditCommentData): void {
100 const thread = this.findThreadById(threadID)
105 const comment = thread.comments.find((comment) => comment.id === commentID)
110 comment.content = content
112 if (markThreadUnread) {
113 this.unreadThreadIDs.add(thread.id)
116 this.notifyLocalListeners()
119 deleteComment({ commentID, threadID }: { commentID: string; threadID: string }): void {
120 const thread = this.findThreadById(threadID)
124 thread.comments = thread.comments.filter((comment) => comment.id !== commentID)
125 this.notifyLocalListeners()
128 replacePlaceholderThread(placeholderID: string, thread: CommentThreadInterface) {
129 const index = this.threads.findIndex((thread) => thread.id === placeholderID)
134 this.threads[index] = {
136 isPlaceholder: false,
139 this.notifyLocalListeners()
142 replacePlaceholderComment(placeholderID: string, comment: CommentInterface) {
143 this.threads.forEach((thread) => {
144 const index = thread.comments.findIndex((comment) => comment.id === placeholderID)
146 thread.comments[index] = {
148 isPlaceholder: false,
152 this.notifyLocalListeners()
155 sortThreadsAndNotify(): void {
156 this.threads.sort((a, b) => {
157 if (a.state === CommentThreadState.Resolved && b.state !== CommentThreadState.Resolved) {
159 } else if (a.state !== CommentThreadState.Resolved && b.state === CommentThreadState.Resolved) {
162 return a.createTime.milliseconds - b.createTime.milliseconds
165 this.notifyLocalListeners()
168 private notifyLocalListeners(): void {
169 this.eventBus.publish<CommentsChangedData>({
170 type: CommentsEvent.CommentsChanged,
172 hasUnreadThreads: this.hasUnreadThreads(),