@churchapps/apphelper 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Loading.d.ts +1 -0
- package/dist/components/Loading.d.ts.map +1 -1
- package/dist/components/Loading.js +1 -45
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/notes/Notes.js +27 -27
- package/dist/helpers/AnalyticsHelper.d.ts.map +1 -1
- package/dist/helpers/AnalyticsHelper.js +21 -6
- package/dist/helpers/AnalyticsHelper.js.map +1 -1
- package/dist/public/css/cropper.css +309 -309
- package/dist/public/css/styles.css +111 -111
- package/dist/public/locales/de.json +270 -0
- package/dist/public/locales/en.json +277 -0
- package/dist/public/locales/es.json +272 -0
- package/dist/public/locales/fr.json +270 -0
- package/dist/public/locales/hi.json +270 -0
- package/dist/public/locales/it.json +270 -0
- package/dist/public/locales/ko.json +270 -0
- package/dist/public/locales/no.json +270 -0
- package/dist/public/locales/pt.json +270 -0
- package/dist/public/locales/ru.json +270 -0
- package/dist/public/locales/tl.json +270 -0
- package/dist/public/locales/zh.json +270 -0
- package/package.json +72 -72
- package/public/css/cropper.css +309 -309
- package/public/css/styles.css +111 -111
- package/public/locales/de.json +269 -269
- package/public/locales/en.json +276 -276
- package/public/locales/es.json +272 -272
- package/public/locales/fr.json +269 -269
- package/public/locales/hi.json +269 -269
- package/public/locales/it.json +269 -269
- package/public/locales/ko.json +269 -269
- package/public/locales/no.json +269 -269
- package/public/locales/pt.json +269 -269
- package/public/locales/ru.json +269 -269
- package/public/locales/tl.json +269 -269
- package/public/locales/zh.json +269 -269
- package/src/components/DisplayBox.tsx +83 -83
- package/src/components/ErrorMessages.tsx +28 -28
- package/src/components/ExportLink.tsx +81 -81
- package/src/components/FloatingSupport.tsx +18 -18
- package/src/components/FormCardPayment.tsx +184 -184
- package/src/components/FormSubmissionEdit.tsx +168 -168
- package/src/components/HelpIcon.tsx +12 -12
- package/src/components/ImageEditor.tsx +161 -161
- package/src/components/InputBox.tsx +96 -96
- package/src/components/Loading.tsx +31 -77
- package/src/components/PageHeader.tsx +110 -110
- package/src/components/PersonAvatar.tsx +77 -77
- package/src/components/QuestionEdit.tsx +99 -99
- package/src/components/SmallButton.tsx +42 -42
- package/src/components/SupportModal.tsx +32 -32
- package/src/components/TabPanel.tsx +28 -28
- package/src/components/gallery/GalleryModal.tsx +173 -173
- package/src/components/gallery/StockPhotos.tsx +95 -95
- package/src/components/gallery/index.ts +1 -1
- package/src/components/header/Banner.tsx +11 -11
- package/src/components/header/PrimaryMenu.tsx +100 -100
- package/src/components/header/SecondaryMenu.tsx +23 -23
- package/src/components/header/SecondaryMenuAlt.tsx +40 -40
- package/src/components/header/SiteHeader.tsx +207 -207
- package/src/components/header/SupportDrawer.tsx +111 -111
- package/src/components/header/index.tsx +2 -2
- package/src/components/index.tsx +20 -20
- package/src/components/notes/AddNote.tsx +180 -180
- package/src/components/notes/Note.tsx +68 -68
- package/src/components/notes/Notes.tsx +208 -208
- package/src/components/notes/index.ts +3 -3
- package/src/components/wrapper/AppList.tsx +19 -19
- package/src/components/wrapper/ChurchList.tsx +154 -154
- package/src/components/wrapper/NavItem.tsx +47 -47
- package/src/components/wrapper/NewPrivateMessage.tsx +253 -253
- package/src/components/wrapper/Notifications.tsx +223 -223
- package/src/components/wrapper/PrivateMessageDetails.tsx +112 -112
- package/src/components/wrapper/PrivateMessages.tsx +576 -576
- package/src/components/wrapper/UserMenu.tsx +383 -383
- package/src/components/wrapper/index.tsx +8 -8
- package/src/helpers/AnalyticsHelper.ts +44 -32
- package/src/helpers/AppearanceHelper.ts +73 -73
- package/src/helpers/ArrayHelper.ts +87 -87
- package/src/helpers/CurrencyHelper.ts +10 -10
- package/src/helpers/DateHelper.ts +104 -104
- package/src/helpers/ErrorHelper.ts +43 -43
- package/src/helpers/EventHelper.ts +49 -49
- package/src/helpers/FileHelper.ts +31 -31
- package/src/helpers/Locale.ts +457 -457
- package/src/helpers/NotificationService.ts +296 -296
- package/src/helpers/PersonHelper.ts +62 -62
- package/src/helpers/SlugHelper.ts +37 -37
- package/src/helpers/SocketHelper.ts +296 -296
- package/src/helpers/UniqueIdHelper.ts +36 -36
- package/src/helpers/UserHelper.ts +107 -107
- package/src/helpers/createEmotionCache.ts +17 -17
- package/src/helpers/index.ts +58 -58
- package/src/hooks/index.ts +3 -3
- package/src/hooks/useMountedState.ts +16 -16
- package/src/hooks/useNotifications.ts +93 -93
- package/src/index.ts +2 -2
- package/src/types/interface-extensions.d.ts +11 -11
- package/tsconfig.json +31 -31
|
@@ -1,297 +1,297 @@
|
|
|
1
|
-
import { SocketHelper } from "./SocketHelper";
|
|
2
|
-
import { ApiHelper, UserContextInterface } from "@churchapps/helpers";
|
|
3
|
-
|
|
4
|
-
export interface NotificationCounts {
|
|
5
|
-
notificationCount: number;
|
|
6
|
-
pmCount: number;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class NotificationService {
|
|
10
|
-
private static instance: NotificationService;
|
|
11
|
-
private counts: NotificationCounts = { notificationCount: 0, pmCount: 0 };
|
|
12
|
-
private listeners: Array<(counts: NotificationCounts) => void> = [];
|
|
13
|
-
private isInitialized: boolean = false;
|
|
14
|
-
private currentPersonId: string | null = null;
|
|
15
|
-
private loadTimeout: any | null = null;
|
|
16
|
-
|
|
17
|
-
private constructor() {}
|
|
18
|
-
|
|
19
|
-
static getInstance(): NotificationService {
|
|
20
|
-
if (!NotificationService.instance) {
|
|
21
|
-
NotificationService.instance = new NotificationService();
|
|
22
|
-
}
|
|
23
|
-
return NotificationService.instance;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Initialize the notification service with user context
|
|
28
|
-
*/
|
|
29
|
-
/**
|
|
30
|
-
* Initialize the notification service with user context
|
|
31
|
-
*/
|
|
32
|
-
async initialize(context: UserContextInterface): Promise<void> {
|
|
33
|
-
if (this.isInitialized) {
|
|
34
|
-
console.log('🔔 NotificationService: Already initialized, skipping');
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
console.log('🔔 NotificationService: Starting initialization with context:', {
|
|
39
|
-
hasUser: !!context?.user,
|
|
40
|
-
hasPerson: !!context?.person,
|
|
41
|
-
hasUserChurch: !!context?.userChurch,
|
|
42
|
-
personId: context?.person?.id,
|
|
43
|
-
churchId: context?.userChurch?.church?.id
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
// Store current person ID for conversation counting
|
|
48
|
-
this.currentPersonId = context?.person?.id || null;
|
|
49
|
-
console.log('👤 NotificationService: Set current person ID:', this.currentPersonId);
|
|
50
|
-
|
|
51
|
-
// Initialize WebSocket connection
|
|
52
|
-
console.log('🔌 NotificationService: Initializing SocketHelper...');
|
|
53
|
-
await SocketHelper.init();
|
|
54
|
-
|
|
55
|
-
// Set person/church context for websocket
|
|
56
|
-
if (context?.person?.id && context?.userChurch?.church?.id) {
|
|
57
|
-
console.log('🔗 NotificationService: Setting person/church context in SocketHelper');
|
|
58
|
-
SocketHelper.setPersonChurch({
|
|
59
|
-
personId: context.person.id,
|
|
60
|
-
churchId: context.userChurch.church.id
|
|
61
|
-
});
|
|
62
|
-
} else {
|
|
63
|
-
console.warn('⚠️ NotificationService: Missing person/church IDs, cannot set socket context');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Register handlers for notification updates
|
|
67
|
-
console.log('📋 NotificationService: Registering WebSocket handlers');
|
|
68
|
-
this.registerWebSocketHandlers();
|
|
69
|
-
|
|
70
|
-
// Load initial notification counts
|
|
71
|
-
console.log('📊 NotificationService: Loading initial notification counts');
|
|
72
|
-
await this.loadNotificationCounts();
|
|
73
|
-
|
|
74
|
-
this.isInitialized = true;
|
|
75
|
-
console.log('✅ NotificationService: Initialization complete');
|
|
76
|
-
|
|
77
|
-
} catch (error) {
|
|
78
|
-
console.error("❌ Failed to initialize NotificationService:", error);
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Register websocket handlers for real-time notification updates
|
|
85
|
-
*/
|
|
86
|
-
/**
|
|
87
|
-
* Register websocket handlers for real-time notification updates
|
|
88
|
-
*/
|
|
89
|
-
/**
|
|
90
|
-
* Register websocket handlers for real-time notification updates
|
|
91
|
-
*/
|
|
92
|
-
private registerWebSocketHandlers(): void {
|
|
93
|
-
// Handler for new private messages
|
|
94
|
-
SocketHelper.addHandler("privateMessage", "NotificationService-PM", (data: any) => {
|
|
95
|
-
console.log('🔔 NotificationService: New private message received, updating counts');
|
|
96
|
-
console.log('📨 Private message data:', data);
|
|
97
|
-
console.log('🔄 NotificationService: About to call debouncedLoadNotificationCounts...');
|
|
98
|
-
try {
|
|
99
|
-
this.debouncedLoadNotificationCounts();
|
|
100
|
-
console.log('✅ NotificationService: debouncedLoadNotificationCounts called successfully');
|
|
101
|
-
} catch (error) {
|
|
102
|
-
console.error('❌ NotificationService: Error calling debouncedLoadNotificationCounts:', error);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Handler for general notifications
|
|
107
|
-
SocketHelper.addHandler("notification", "NotificationService-Notification", (data: any) => {
|
|
108
|
-
console.log('🔔 NotificationService: New notification received, updating counts');
|
|
109
|
-
console.log('📨 Notification data:', data);
|
|
110
|
-
console.log('🔄 NotificationService: About to call debouncedLoadNotificationCounts...');
|
|
111
|
-
try {
|
|
112
|
-
this.debouncedLoadNotificationCounts();
|
|
113
|
-
console.log('✅ NotificationService: debouncedLoadNotificationCounts called successfully');
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error('❌ NotificationService: Error calling debouncedLoadNotificationCounts:', error);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Handler for message updates that could affect notification counts
|
|
120
|
-
SocketHelper.addHandler("message", "NotificationService-MessageUpdate", (data: any) => {
|
|
121
|
-
// Only update counts if the message update involves the current person
|
|
122
|
-
if (data?.message?.personId === this.currentPersonId ||
|
|
123
|
-
data?.notifyPersonId === this.currentPersonId) {
|
|
124
|
-
console.log('🔔 NotificationService: Message update affecting current user, updating counts');
|
|
125
|
-
console.log('📨 Message update data:', data);
|
|
126
|
-
console.log('🔄 NotificationService: About to call debouncedLoadNotificationCounts...');
|
|
127
|
-
try {
|
|
128
|
-
this.debouncedLoadNotificationCounts();
|
|
129
|
-
console.log('✅ NotificationService: debouncedLoadNotificationCounts called successfully');
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error('❌ NotificationService: Error calling debouncedLoadNotificationCounts:', error);
|
|
132
|
-
}
|
|
133
|
-
} else {
|
|
134
|
-
console.log('🔕 NotificationService: Message update not for current user, ignoring');
|
|
135
|
-
console.log('📨 Message personId:', data?.message?.personId, 'Current personId:', this.currentPersonId);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// Handler for reconnect events
|
|
140
|
-
SocketHelper.addHandler("reconnect", "NotificationService-Reconnect", (data: any) => {
|
|
141
|
-
console.log('🔔 NotificationService: WebSocket reconnected, refreshing counts');
|
|
142
|
-
this.loadNotificationCounts(); // Don't debounce reconnect - need immediate update
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Load notification counts from the API with debouncing
|
|
148
|
-
*/
|
|
149
|
-
/**
|
|
150
|
-
* Load notification counts from the API with debouncing
|
|
151
|
-
*/
|
|
152
|
-
private debouncedLoadNotificationCounts(): void {
|
|
153
|
-
console.log('⏰ NotificationService: Debounced load triggered');
|
|
154
|
-
|
|
155
|
-
if (this.loadTimeout) {
|
|
156
|
-
console.log('⏰ NotificationService: Clearing existing timeout');
|
|
157
|
-
clearTimeout(this.loadTimeout);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
this.loadTimeout = setTimeout(() => {
|
|
161
|
-
console.log('⏰ NotificationService: Timeout expired, loading counts...');
|
|
162
|
-
this.loadNotificationCounts();
|
|
163
|
-
}, 300); // 300ms debounce
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Load notification counts from the API
|
|
168
|
-
*/
|
|
169
|
-
/**
|
|
170
|
-
* Load notification counts from the API
|
|
171
|
-
*/
|
|
172
|
-
async loadNotificationCounts(): Promise<void> {
|
|
173
|
-
console.log('📊 NotificationService: Loading notification counts from API...');
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
// Use the unreadCount endpoint which returns both notification and PM counts
|
|
177
|
-
console.log('🌐 NotificationService: Making API call to /notifications/unreadCount');
|
|
178
|
-
const counts = await ApiHelper.get("/notifications/unreadCount", "MessagingApi");
|
|
179
|
-
console.log('📊 NotificationService: API response:', counts);
|
|
180
|
-
|
|
181
|
-
const newCounts = {
|
|
182
|
-
notificationCount: counts?.notificationCount || 0,
|
|
183
|
-
pmCount: counts?.pmCount || 0
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
console.log('🔄 NotificationService: Updating counts:', newCounts);
|
|
187
|
-
|
|
188
|
-
// Update counts and notify listeners
|
|
189
|
-
this.updateCounts(newCounts);
|
|
190
|
-
|
|
191
|
-
} catch (error) {
|
|
192
|
-
console.error("❌ Failed to load notification counts:", error);
|
|
193
|
-
console.error("❌ Error details:", {
|
|
194
|
-
message: error.message,
|
|
195
|
-
status: error.status,
|
|
196
|
-
response: error.response
|
|
197
|
-
});
|
|
198
|
-
// Don't throw - just log the error and keep existing counts
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Update counts and notify all listeners
|
|
204
|
-
*/
|
|
205
|
-
/**
|
|
206
|
-
* Update counts and notify all listeners
|
|
207
|
-
*/
|
|
208
|
-
private updateCounts(newCounts: NotificationCounts): void {
|
|
209
|
-
console.log('🔔 NotificationService: updateCounts called with:', newCounts);
|
|
210
|
-
console.log('🔔 NotificationService: Current counts:', this.counts);
|
|
211
|
-
console.log('🔔 NotificationService: Number of listeners:', this.listeners.length);
|
|
212
|
-
|
|
213
|
-
const countsChanged =
|
|
214
|
-
this.counts.notificationCount !== newCounts.notificationCount ||
|
|
215
|
-
this.counts.pmCount !== newCounts.pmCount;
|
|
216
|
-
|
|
217
|
-
console.log('🔄 NotificationService: Counts changed?', countsChanged);
|
|
218
|
-
|
|
219
|
-
if (countsChanged) {
|
|
220
|
-
this.counts = { ...newCounts };
|
|
221
|
-
console.log('✅ NotificationService: Counts updated, notifying listeners...');
|
|
222
|
-
|
|
223
|
-
// Notify all listeners
|
|
224
|
-
this.listeners.forEach((listener, index) => {
|
|
225
|
-
try {
|
|
226
|
-
console.log(`📢 NotificationService: Calling listener ${index + 1}/${this.listeners.length}`);
|
|
227
|
-
listener(this.counts);
|
|
228
|
-
} catch (error) {
|
|
229
|
-
console.error(`❌ Error in notification listener ${index}:`, error);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
} else {
|
|
233
|
-
console.log('⚪ NotificationService: Counts unchanged, not notifying listeners');
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Subscribe to notification count changes
|
|
239
|
-
*/
|
|
240
|
-
subscribe(listener: (counts: NotificationCounts) => void): () => void {
|
|
241
|
-
this.listeners.push(listener);
|
|
242
|
-
|
|
243
|
-
// Immediately call with current counts
|
|
244
|
-
listener(this.counts);
|
|
245
|
-
|
|
246
|
-
// Return unsubscribe function
|
|
247
|
-
return () => {
|
|
248
|
-
this.listeners = this.listeners.filter(l => l !== listener);
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Get current notification counts
|
|
254
|
-
*/
|
|
255
|
-
getCounts(): NotificationCounts {
|
|
256
|
-
return { ...this.counts };
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Manually refresh notification counts
|
|
261
|
-
*/
|
|
262
|
-
async refresh(): Promise<void> {
|
|
263
|
-
await this.loadNotificationCounts();
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Cleanup the service
|
|
268
|
-
*/
|
|
269
|
-
cleanup(): void {
|
|
270
|
-
// Clear any pending timeout
|
|
271
|
-
if (this.loadTimeout) {
|
|
272
|
-
clearTimeout(this.loadTimeout);
|
|
273
|
-
this.loadTimeout = null;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Remove websocket handlers
|
|
277
|
-
SocketHelper.removeHandler("NotificationService-PM");
|
|
278
|
-
SocketHelper.removeHandler("NotificationService-Notification");
|
|
279
|
-
SocketHelper.removeHandler("NotificationService-MessageUpdate");
|
|
280
|
-
SocketHelper.removeHandler("NotificationService-Reconnect");
|
|
281
|
-
|
|
282
|
-
// Clear listeners
|
|
283
|
-
this.listeners = [];
|
|
284
|
-
|
|
285
|
-
// Reset state
|
|
286
|
-
this.counts = { notificationCount: 0, pmCount: 0 };
|
|
287
|
-
this.currentPersonId = null;
|
|
288
|
-
this.isInitialized = false;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Check if service is initialized
|
|
293
|
-
*/
|
|
294
|
-
isReady(): boolean {
|
|
295
|
-
return this.isInitialized && SocketHelper.isConnected();
|
|
296
|
-
}
|
|
1
|
+
import { SocketHelper } from "./SocketHelper";
|
|
2
|
+
import { ApiHelper, UserContextInterface } from "@churchapps/helpers";
|
|
3
|
+
|
|
4
|
+
export interface NotificationCounts {
|
|
5
|
+
notificationCount: number;
|
|
6
|
+
pmCount: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class NotificationService {
|
|
10
|
+
private static instance: NotificationService;
|
|
11
|
+
private counts: NotificationCounts = { notificationCount: 0, pmCount: 0 };
|
|
12
|
+
private listeners: Array<(counts: NotificationCounts) => void> = [];
|
|
13
|
+
private isInitialized: boolean = false;
|
|
14
|
+
private currentPersonId: string | null = null;
|
|
15
|
+
private loadTimeout: any | null = null;
|
|
16
|
+
|
|
17
|
+
private constructor() {}
|
|
18
|
+
|
|
19
|
+
static getInstance(): NotificationService {
|
|
20
|
+
if (!NotificationService.instance) {
|
|
21
|
+
NotificationService.instance = new NotificationService();
|
|
22
|
+
}
|
|
23
|
+
return NotificationService.instance;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Initialize the notification service with user context
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Initialize the notification service with user context
|
|
31
|
+
*/
|
|
32
|
+
async initialize(context: UserContextInterface): Promise<void> {
|
|
33
|
+
if (this.isInitialized) {
|
|
34
|
+
console.log('🔔 NotificationService: Already initialized, skipping');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log('🔔 NotificationService: Starting initialization with context:', {
|
|
39
|
+
hasUser: !!context?.user,
|
|
40
|
+
hasPerson: !!context?.person,
|
|
41
|
+
hasUserChurch: !!context?.userChurch,
|
|
42
|
+
personId: context?.person?.id,
|
|
43
|
+
churchId: context?.userChurch?.church?.id
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
// Store current person ID for conversation counting
|
|
48
|
+
this.currentPersonId = context?.person?.id || null;
|
|
49
|
+
console.log('👤 NotificationService: Set current person ID:', this.currentPersonId);
|
|
50
|
+
|
|
51
|
+
// Initialize WebSocket connection
|
|
52
|
+
console.log('🔌 NotificationService: Initializing SocketHelper...');
|
|
53
|
+
await SocketHelper.init();
|
|
54
|
+
|
|
55
|
+
// Set person/church context for websocket
|
|
56
|
+
if (context?.person?.id && context?.userChurch?.church?.id) {
|
|
57
|
+
console.log('🔗 NotificationService: Setting person/church context in SocketHelper');
|
|
58
|
+
SocketHelper.setPersonChurch({
|
|
59
|
+
personId: context.person.id,
|
|
60
|
+
churchId: context.userChurch.church.id
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
console.warn('⚠️ NotificationService: Missing person/church IDs, cannot set socket context');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Register handlers for notification updates
|
|
67
|
+
console.log('📋 NotificationService: Registering WebSocket handlers');
|
|
68
|
+
this.registerWebSocketHandlers();
|
|
69
|
+
|
|
70
|
+
// Load initial notification counts
|
|
71
|
+
console.log('📊 NotificationService: Loading initial notification counts');
|
|
72
|
+
await this.loadNotificationCounts();
|
|
73
|
+
|
|
74
|
+
this.isInitialized = true;
|
|
75
|
+
console.log('✅ NotificationService: Initialization complete');
|
|
76
|
+
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error("❌ Failed to initialize NotificationService:", error);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Register websocket handlers for real-time notification updates
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* Register websocket handlers for real-time notification updates
|
|
88
|
+
*/
|
|
89
|
+
/**
|
|
90
|
+
* Register websocket handlers for real-time notification updates
|
|
91
|
+
*/
|
|
92
|
+
private registerWebSocketHandlers(): void {
|
|
93
|
+
// Handler for new private messages
|
|
94
|
+
SocketHelper.addHandler("privateMessage", "NotificationService-PM", (data: any) => {
|
|
95
|
+
console.log('🔔 NotificationService: New private message received, updating counts');
|
|
96
|
+
console.log('📨 Private message data:', data);
|
|
97
|
+
console.log('🔄 NotificationService: About to call debouncedLoadNotificationCounts...');
|
|
98
|
+
try {
|
|
99
|
+
this.debouncedLoadNotificationCounts();
|
|
100
|
+
console.log('✅ NotificationService: debouncedLoadNotificationCounts called successfully');
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('❌ NotificationService: Error calling debouncedLoadNotificationCounts:', error);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Handler for general notifications
|
|
107
|
+
SocketHelper.addHandler("notification", "NotificationService-Notification", (data: any) => {
|
|
108
|
+
console.log('🔔 NotificationService: New notification received, updating counts');
|
|
109
|
+
console.log('📨 Notification data:', data);
|
|
110
|
+
console.log('🔄 NotificationService: About to call debouncedLoadNotificationCounts...');
|
|
111
|
+
try {
|
|
112
|
+
this.debouncedLoadNotificationCounts();
|
|
113
|
+
console.log('✅ NotificationService: debouncedLoadNotificationCounts called successfully');
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('❌ NotificationService: Error calling debouncedLoadNotificationCounts:', error);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Handler for message updates that could affect notification counts
|
|
120
|
+
SocketHelper.addHandler("message", "NotificationService-MessageUpdate", (data: any) => {
|
|
121
|
+
// Only update counts if the message update involves the current person
|
|
122
|
+
if (data?.message?.personId === this.currentPersonId ||
|
|
123
|
+
data?.notifyPersonId === this.currentPersonId) {
|
|
124
|
+
console.log('🔔 NotificationService: Message update affecting current user, updating counts');
|
|
125
|
+
console.log('📨 Message update data:', data);
|
|
126
|
+
console.log('🔄 NotificationService: About to call debouncedLoadNotificationCounts...');
|
|
127
|
+
try {
|
|
128
|
+
this.debouncedLoadNotificationCounts();
|
|
129
|
+
console.log('✅ NotificationService: debouncedLoadNotificationCounts called successfully');
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('❌ NotificationService: Error calling debouncedLoadNotificationCounts:', error);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
console.log('🔕 NotificationService: Message update not for current user, ignoring');
|
|
135
|
+
console.log('📨 Message personId:', data?.message?.personId, 'Current personId:', this.currentPersonId);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Handler for reconnect events
|
|
140
|
+
SocketHelper.addHandler("reconnect", "NotificationService-Reconnect", (data: any) => {
|
|
141
|
+
console.log('🔔 NotificationService: WebSocket reconnected, refreshing counts');
|
|
142
|
+
this.loadNotificationCounts(); // Don't debounce reconnect - need immediate update
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Load notification counts from the API with debouncing
|
|
148
|
+
*/
|
|
149
|
+
/**
|
|
150
|
+
* Load notification counts from the API with debouncing
|
|
151
|
+
*/
|
|
152
|
+
private debouncedLoadNotificationCounts(): void {
|
|
153
|
+
console.log('⏰ NotificationService: Debounced load triggered');
|
|
154
|
+
|
|
155
|
+
if (this.loadTimeout) {
|
|
156
|
+
console.log('⏰ NotificationService: Clearing existing timeout');
|
|
157
|
+
clearTimeout(this.loadTimeout);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.loadTimeout = setTimeout(() => {
|
|
161
|
+
console.log('⏰ NotificationService: Timeout expired, loading counts...');
|
|
162
|
+
this.loadNotificationCounts();
|
|
163
|
+
}, 300); // 300ms debounce
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Load notification counts from the API
|
|
168
|
+
*/
|
|
169
|
+
/**
|
|
170
|
+
* Load notification counts from the API
|
|
171
|
+
*/
|
|
172
|
+
async loadNotificationCounts(): Promise<void> {
|
|
173
|
+
console.log('📊 NotificationService: Loading notification counts from API...');
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
// Use the unreadCount endpoint which returns both notification and PM counts
|
|
177
|
+
console.log('🌐 NotificationService: Making API call to /notifications/unreadCount');
|
|
178
|
+
const counts = await ApiHelper.get("/notifications/unreadCount", "MessagingApi");
|
|
179
|
+
console.log('📊 NotificationService: API response:', counts);
|
|
180
|
+
|
|
181
|
+
const newCounts = {
|
|
182
|
+
notificationCount: counts?.notificationCount || 0,
|
|
183
|
+
pmCount: counts?.pmCount || 0
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
console.log('🔄 NotificationService: Updating counts:', newCounts);
|
|
187
|
+
|
|
188
|
+
// Update counts and notify listeners
|
|
189
|
+
this.updateCounts(newCounts);
|
|
190
|
+
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error("❌ Failed to load notification counts:", error);
|
|
193
|
+
console.error("❌ Error details:", {
|
|
194
|
+
message: error.message,
|
|
195
|
+
status: error.status,
|
|
196
|
+
response: error.response
|
|
197
|
+
});
|
|
198
|
+
// Don't throw - just log the error and keep existing counts
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Update counts and notify all listeners
|
|
204
|
+
*/
|
|
205
|
+
/**
|
|
206
|
+
* Update counts and notify all listeners
|
|
207
|
+
*/
|
|
208
|
+
private updateCounts(newCounts: NotificationCounts): void {
|
|
209
|
+
console.log('🔔 NotificationService: updateCounts called with:', newCounts);
|
|
210
|
+
console.log('🔔 NotificationService: Current counts:', this.counts);
|
|
211
|
+
console.log('🔔 NotificationService: Number of listeners:', this.listeners.length);
|
|
212
|
+
|
|
213
|
+
const countsChanged =
|
|
214
|
+
this.counts.notificationCount !== newCounts.notificationCount ||
|
|
215
|
+
this.counts.pmCount !== newCounts.pmCount;
|
|
216
|
+
|
|
217
|
+
console.log('🔄 NotificationService: Counts changed?', countsChanged);
|
|
218
|
+
|
|
219
|
+
if (countsChanged) {
|
|
220
|
+
this.counts = { ...newCounts };
|
|
221
|
+
console.log('✅ NotificationService: Counts updated, notifying listeners...');
|
|
222
|
+
|
|
223
|
+
// Notify all listeners
|
|
224
|
+
this.listeners.forEach((listener, index) => {
|
|
225
|
+
try {
|
|
226
|
+
console.log(`📢 NotificationService: Calling listener ${index + 1}/${this.listeners.length}`);
|
|
227
|
+
listener(this.counts);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error(`❌ Error in notification listener ${index}:`, error);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
} else {
|
|
233
|
+
console.log('⚪ NotificationService: Counts unchanged, not notifying listeners');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Subscribe to notification count changes
|
|
239
|
+
*/
|
|
240
|
+
subscribe(listener: (counts: NotificationCounts) => void): () => void {
|
|
241
|
+
this.listeners.push(listener);
|
|
242
|
+
|
|
243
|
+
// Immediately call with current counts
|
|
244
|
+
listener(this.counts);
|
|
245
|
+
|
|
246
|
+
// Return unsubscribe function
|
|
247
|
+
return () => {
|
|
248
|
+
this.listeners = this.listeners.filter(l => l !== listener);
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get current notification counts
|
|
254
|
+
*/
|
|
255
|
+
getCounts(): NotificationCounts {
|
|
256
|
+
return { ...this.counts };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Manually refresh notification counts
|
|
261
|
+
*/
|
|
262
|
+
async refresh(): Promise<void> {
|
|
263
|
+
await this.loadNotificationCounts();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Cleanup the service
|
|
268
|
+
*/
|
|
269
|
+
cleanup(): void {
|
|
270
|
+
// Clear any pending timeout
|
|
271
|
+
if (this.loadTimeout) {
|
|
272
|
+
clearTimeout(this.loadTimeout);
|
|
273
|
+
this.loadTimeout = null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Remove websocket handlers
|
|
277
|
+
SocketHelper.removeHandler("NotificationService-PM");
|
|
278
|
+
SocketHelper.removeHandler("NotificationService-Notification");
|
|
279
|
+
SocketHelper.removeHandler("NotificationService-MessageUpdate");
|
|
280
|
+
SocketHelper.removeHandler("NotificationService-Reconnect");
|
|
281
|
+
|
|
282
|
+
// Clear listeners
|
|
283
|
+
this.listeners = [];
|
|
284
|
+
|
|
285
|
+
// Reset state
|
|
286
|
+
this.counts = { notificationCount: 0, pmCount: 0 };
|
|
287
|
+
this.currentPersonId = null;
|
|
288
|
+
this.isInitialized = false;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Check if service is initialized
|
|
293
|
+
*/
|
|
294
|
+
isReady(): boolean {
|
|
295
|
+
return this.isInitialized && SocketHelper.isConnected();
|
|
296
|
+
}
|
|
297
297
|
}
|