@churchapps/apphelper
Version:
Library of helper functions for React and NextJS ChurchApps
176 lines • 6.57 kB
JavaScript
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
});
}
// 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) => {
console.log('🔔 NotificationService: New private message received, updating counts');
this.debouncedLoadNotificationCounts();
});
// Handler for general notifications
SocketHelper.addHandler("notification", "NotificationService-Notification", (data) => {
console.log('🔔 NotificationService: New notification received, updating counts');
this.debouncedLoadNotificationCounts();
});
// 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) {
console.log('🔔 NotificationService: Message update affecting current user, updating counts');
this.debouncedLoadNotificationCounts();
}
});
// Handler for reconnect events
SocketHelper.addHandler("reconnect", "NotificationService-Reconnect", (data) => {
console.log('🔔 NotificationService: WebSocket reconnected, refreshing counts');
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);
// 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 => {
try {
listener(this.counts);
}
catch (error) {
console.error("❌ Error in notification listener:", 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