{ "version": 3, "sources": ["src/app/sms/services/sms-unread-message.service.ts"], "sourcesContent": ["import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { WebsocketInit } from '@app/core/models/connection-status';\nimport { WsService } from '@app/core/services/ws.service';\nimport { NOTIFICATION_TYPE, SMSMessage, STREAM_UPDATE_TYPE, UnreadCount } from '@app/sms/models/sms.models';\nimport { environment } from '@environment/environment';\nimport { BehaviorSubject, catchError, combineLatest, filter, from, map, mergeMap, of, switchMap, toArray } from 'rxjs';\n\nimport { SMSService } from './sms.service';\n\n/**\n * Handles the logic managing \"unread\" and \"read\" messages which\n * includes:\n * - Marking messages as \"read\"\n *\n * @export\n * @class SMSUnreadMessageService\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class SMSUnreadMessageService implements WebsocketInit {\n private readonly unreadCountSubject = new BehaviorSubject({});\n public readonly unreadCount$ = this.unreadCountSubject.asObservable();\n\n private readonly unreadPhoneNumberCountSubject: BehaviorSubject = new BehaviorSubject({});\n public readonly unreadPhoneNumberCount$ = this.unreadPhoneNumberCountSubject.asObservable();\n\n constructor(\n private httpClient: HttpClient,\n private webSocketService: WsService,\n private smsService: SMSService\n ) {\n // Update whenever our conversation list _or_ localNumbers gets updated\n combineLatest([this.smsService.data$, this.smsService.localNumbers$]).subscribe(([conversations]) => {\n // Iterate over each conversation and update the corresponding unread count for that number. Conversation ids are\n // auto-incremented integers so we need to specially format phone numbers in this dictionary to avoid collisions.\n const count: UnreadCount = {};\n for (const conversation of conversations) {\n count[conversation.conversationId] = conversation.unreadMessageCount;\n }\n this.unreadCountSubject.next({ ...this.unreadCountSubject.value, ...count });\n });\n\n // Any time the unread count changes, also recalculate the unread count for our phone numbers\n this.unreadCount$\n .pipe(\n map((unreadCount) => ({ unreadCount, conversationIds: Object.keys(unreadCount) })),\n switchMap(({ unreadCount, conversationIds }) =>\n from(conversationIds).pipe(\n mergeMap((id) => this.smsService.getCachedConversationWithId(id)),\n filter((result): result is NonNullable => result !== null), // Type guard to filter out null results\n toArray(), // Collect all non-null results into a single array\n map((results) => ({ unreadCount, conversations: results })) // Combine unreadCount and results\n )\n )\n )\n .subscribe(({ unreadCount, conversations }) => {\n const phoneCount: UnreadCount = {};\n for (const conversation of conversations) {\n phoneCount[conversation.local] =\n (phoneCount[conversation.local] || 0) + (unreadCount[conversation.conversationId] || 0);\n }\n this.unreadPhoneNumberCountSubject.next({ ...this.unreadPhoneNumberCountSubject.value, ...phoneCount });\n });\n }\n\n bindSocketEvents() {\n this.webSocketService.socket.on('SMSConversationReadMarkerUpdated', (data: { conversationId: string }) => {\n this.setUnreadCount(data.conversationId, 0);\n });\n\n this.webSocketService.socket.on('SMSMessageReceived', (message: SMSMessage) => {\n // Filter out any notification messages that aren't streamupdate type. Standard messages won't have the `notification`\n // prop set and when it is set, only stream updates should be processed.\n if (\n message.type === NOTIFICATION_TYPE ||\n (message.notification?.type && message.notification.type !== STREAM_UPDATE_TYPE)\n ) {\n return;\n }\n\n // When a message is received on the socket, check it see if we're currently rendering that conversation.\n // If not, increment the unread count.\n // TODO: We may want to eventually make this more sophisticated so if the conversationId _does_ match the current\n // conversation, we still may increment the count if the user isn't scrolled to the bottom of the conversation.\n if (message.conversationId && document.location.href.search(message.conversationId) === -1) {\n this.incrementUnreadCount(message.conversationId);\n }\n });\n\n this.webSocketService.socket.on('SMSMessageSent', (data: { conversationId: string }) => {\n this.updateReadMarker(data.conversationId);\n });\n }\n\n public getUnreadCount(conversationId: string): number {\n return this.unreadCountSubject.getValue()[conversationId] || 0;\n }\n\n private incrementUnreadCount(conversationId: string) {\n const count = this.getUnreadCount(conversationId) + 1;\n this.setUnreadCount(conversationId, count);\n }\n\n private setUnreadCount(conversationId: string, count: number) {\n const unreadCount = this.unreadCountSubject.getValue();\n unreadCount[conversationId] = count;\n\n // Any time the unread count is updated manually we should also update the value on the conversation\n // in case it is read\n this.smsService.updateConversationById(conversationId, { unreadMessageCount: count }).finally(() => {\n this.unreadCountSubject.next({ ...unreadCount });\n });\n }\n\n public updateReadMarker(conversationId: string) {\n // Passing `null` for body will update the read marker on the server to the latest message's timestamp\n return this.httpClient\n .put(`${environment.messageHubGateway}/sms/conversations/${conversationId}/read-marker`, {})\n .pipe(\n catchError(() => {\n return of();\n })\n )\n .subscribe(() => {\n this.setUnreadCount(conversationId, 0);\n });\n }\n\n public updateAllConversationsReadMarker() {\n return this.httpClient.put(`${environment.messageHubGateway}/sms/messages/read-marker`, {}).subscribe();\n }\n}\n"], "mappings": "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", "names": ["SMSUnreadMessageService", "constructor", "httpClient", "webSocketService", "smsService", "unreadCountSubject", "BehaviorSubject", "unreadCount$", "asObservable", "unreadPhoneNumberCountSubject", "unreadPhoneNumberCount$", "combineLatest", "data$", "localNumbers$", "subscribe", "conversations", "count", "conversation", "conversationId", "unreadMessageCount", "next", "__spreadValues", "value", "pipe", "map", "unreadCount", "conversationIds", "Object", "keys", "switchMap", "from", "mergeMap", "id", "getCachedConversationWithId", "filter", "result", "toArray", "results", "phoneCount", "local", "bindSocketEvents", "socket", "on", "data", "setUnreadCount", "message", "type", "NOTIFICATION_TYPE", "notification", "STREAM_UPDATE_TYPE", "document", "location", "href", "search", "incrementUnreadCount", "updateReadMarker", "getUnreadCount", "getValue", "updateConversationById", "finally", "put", "environment", "messageHubGateway", "catchError", "of", "updateAllConversationsReadMarker", "\u0275\u0275inject", "HttpClient", "WsService", "SMSService", "factory", "\u0275fac", "providedIn"] }