Files
frontend/src/stores/message/ReadReceiptManager.ts

92 lines
2.5 KiB
TypeScript
Raw Normal View History

/**
*
*
*/
import { messageService } from '../../services/messageService';
import { messageRepository } from '../../data/repositories/MessageRepository';
import type { MessageStateManager } from './MessageStateManager';
export interface ReadReceiptResult {
conversationId: string;
lastReadSeq: number;
success: boolean;
}
export class ReadReceiptManager {
private pendingOperations: Map<string, Promise<void>> = new Map();
private stateManager: MessageStateManager | null = null;
setStateManager(manager: MessageStateManager): void {
this.stateManager = manager;
}
async markAsRead(
conversationId: string,
lastSeq: number
): Promise<ReadReceiptResult> {
const existing = this.pendingOperations.get(conversationId);
if (existing) {
await existing;
}
if (!this.stateManager) {
throw new Error('StateManager not set');
}
const version = this.stateManager.beginReadOperation(conversationId);
const promise = this.executeMarkAsRead(conversationId, lastSeq, version);
this.pendingOperations.set(conversationId, promise);
try {
await promise;
return { conversationId, lastReadSeq: lastSeq, success: true };
} catch (error) {
console.error('[ReadReceiptManager] Failed to mark as read:', error);
return { conversationId, lastReadSeq: lastSeq, success: false };
} finally {
this.pendingOperations.delete(conversationId);
this.stateManager.endReadOperation(conversationId);
}
}
private async executeMarkAsRead(
conversationId: string,
lastSeq: number,
version: number
): Promise<void> {
await messageService.markAsRead(conversationId, lastSeq);
await messageRepository.markConversationAsRead(conversationId);
if (this.stateManager) {
this.stateManager.updateConversation(conversationId, {
unreadCount: 0,
});
}
}
async markAllAsRead(): Promise<void> {
if (!this.stateManager) return;
const conversations = this.stateManager.getConversations();
const unreadConversations = conversations.filter(c => c.unreadCount > 0);
await Promise.all(
unreadConversations.map(conv =>
this.markAsRead(conv.id, conv.lastSeq)
)
);
}
isPending(conversationId: string): boolean {
return this.pendingOperations.has(conversationId);
}
reset(): void {
this.pendingOperations.clear();
}
}
export const readReceiptManager = new ReadReceiptManager();