UNPKG

@churchapps/apphelper

Version:

Library of helper functions for React and NextJS ChurchApps

196 lines 7.12 kB
import { SocketHelper } from "./SocketHelper"; import { ApiHelper } from "@churchapps/helpers"; export class NotificationService { constructor() { this.counts = { notificationCount: 0, pmCount: 0 }; this.listeners = []; this.isInitialized = false; this.currentPersonId = null; this.loadTimeout = null; } static getInstance() { if (!NotificationService.instance) { NotificationService.instance = new NotificationService(); } return NotificationService.instance; } /** * Initialize the notification service with user context */ async initialize(context) { if (this.isInitialized) { return; } try { // Store current person ID for conversation counting this.currentPersonId = context?.person?.id || null; // Initialize WebSocket connection await SocketHelper.init(); // Set person/church context for websocket if (context?.person?.id && context?.userChurch?.church?.id) { SocketHelper.setPersonChurch({ personId: context.person.id, churchId: context.userChurch.church.id }); } else { console.warn("⚠️ NotificationService: Missing person/church IDs, cannot set socket context"); } // Register handlers for notification updates this.registerWebSocketHandlers(); // Load initial notification counts await this.loadNotificationCounts(); this.isInitialized = true; } catch (error) { console.error("❌ Failed to initialize NotificationService:", error); throw error; } } /** * Register websocket handlers for real-time notification updates */ registerWebSocketHandlers() { // Handler for new private messages SocketHelper.addHandler("privateMessage", "NotificationService-PM", (data) => { try { this.debouncedLoadNotificationCounts(); } catch (error) { console.error("❌ NotificationService: Error calling debouncedLoadNotificationCounts:", error); } }); // Handler for general notifications SocketHelper.addHandler("notification", "NotificationService-Notification", (data) => { try { this.debouncedLoadNotificationCounts(); } catch (error) { console.error("❌ NotificationService: Error calling debouncedLoadNotificationCounts:", error); } }); // Handler for message updates that could affect notification counts SocketHelper.addHandler("message", "NotificationService-MessageUpdate", (data) => { // Only update counts if the message update involves the current person if (data?.message?.personId === this.currentPersonId || data?.notifyPersonId === this.currentPersonId) { try { this.debouncedLoadNotificationCounts(); } catch (error) { console.error("❌ NotificationService: Error calling debouncedLoadNotificationCounts:", error); } } }); // Handler for reconnect events SocketHelper.addHandler("reconnect", "NotificationService-Reconnect", (data) => { this.loadNotificationCounts(); // Don't debounce reconnect - need immediate update }); } /** * Load notification counts from the API with debouncing */ debouncedLoadNotificationCounts() { if (this.loadTimeout) { clearTimeout(this.loadTimeout); } this.loadTimeout = setTimeout(() => { this.loadNotificationCounts(); }, 300); // 300ms debounce } /** * Load notification counts from the API */ async loadNotificationCounts() { try { // Use the unreadCount endpoint which returns both notification and PM counts const counts = await ApiHelper.get("/notifications/unreadCount", "MessagingApi"); const newCounts = { notificationCount: counts?.notificationCount || 0, pmCount: counts?.pmCount || 0 }; // Update counts and notify listeners this.updateCounts(newCounts); } catch (error) { console.error("❌ Failed to load notification counts:", error); console.error("❌ Error details:", { message: error.message, status: error.status, response: error.response }); // Don't throw - just log the error and keep existing counts } } /** * Update counts and notify all listeners */ updateCounts(newCounts) { const countsChanged = this.counts.notificationCount !== newCounts.notificationCount || this.counts.pmCount !== newCounts.pmCount; if (countsChanged) { this.counts = { ...newCounts }; // Notify all listeners this.listeners.forEach((listener, index) => { try { listener(this.counts); } catch (error) { console.error(`❌ Error in notification listener ${index}:`, error); } }); } } /** * Subscribe to notification count changes */ subscribe(listener) { this.listeners.push(listener); // Immediately call with current counts listener(this.counts); // Return unsubscribe function return () => { this.listeners = this.listeners.filter(l => l !== listener); }; } /** * Get current notification counts */ getCounts() { return { ...this.counts }; } /** * Manually refresh notification counts */ async refresh() { await this.loadNotificationCounts(); } /** * Cleanup the service */ cleanup() { // Clear any pending timeout if (this.loadTimeout) { clearTimeout(this.loadTimeout); this.loadTimeout = null; } // Remove websocket handlers SocketHelper.removeHandler("NotificationService-PM"); SocketHelper.removeHandler("NotificationService-Notification"); SocketHelper.removeHandler("NotificationService-MessageUpdate"); SocketHelper.removeHandler("NotificationService-Reconnect"); // Clear listeners this.listeners = []; // Reset state this.counts = { notificationCount: 0, pmCount: 0 }; this.currentPersonId = null; this.isInitialized = false; } /** * Check if service is initialized */ isReady() { return this.isInitialized && SocketHelper.isConnected(); } } //# sourceMappingURL=NotificationService.js.map