@ozdao/martyrs 0.2.468 → 0.2.470

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.
Files changed (135) hide show
  1. package/dist/{Media-DwVcRIAX.mjs → Media-C4Ges_Sd.mjs} +1 -1
  2. package/dist/{Media-DCGbUujy.js → Media-CR0V1zvB.js} +1 -1
  3. package/dist/chats.server.js +14 -13
  4. package/dist/chats.server.mjs +14 -13
  5. package/dist/globals.server.js +20 -12
  6. package/dist/globals.server.mjs +20 -12
  7. package/dist/{main-DEHjtgLs.mjs → main-CTcal9qN.mjs} +900 -884
  8. package/dist/{main-UVdexuMN.js → main-CsZAG5Wz.js} +5 -5
  9. package/dist/martyrs/src/components/Block/Block.vue.cjs +1 -1
  10. package/dist/martyrs/src/components/Block/Block.vue.js +1 -1
  11. package/dist/martyrs/src/components/SelectMulti/{SelectMulti.vue2.cjs → SelectMulti.vue.cjs} +2 -2
  12. package/dist/martyrs/src/components/SelectMulti/{SelectMulti.vue2.js.map → SelectMulti.vue.cjs.map} +1 -1
  13. package/dist/martyrs/src/components/SelectMulti/{SelectMulti.vue2.js → SelectMulti.vue.js} +2 -2
  14. package/dist/martyrs/src/components/SelectMulti/SelectMulti.vue.js.map +1 -0
  15. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue.cjs → Tooltip.vue2.cjs} +2 -2
  16. package/dist/martyrs/src/components/Tooltip/Tooltip.vue2.cjs.map +1 -0
  17. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue.js → Tooltip.vue2.js} +2 -2
  18. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue.cjs.map → Tooltip.vue2.js.map} +1 -1
  19. package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.cjs +1 -1
  20. package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.js +1 -1
  21. package/dist/martyrs/src/modules/chats/store/chat.store.cjs +47 -16
  22. package/dist/martyrs/src/modules/chats/store/chat.store.cjs.map +1 -1
  23. package/dist/martyrs/src/modules/chats/store/chat.store.js +47 -16
  24. package/dist/martyrs/src/modules/chats/store/chat.store.js.map +1 -1
  25. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.cjs +1 -1
  26. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.cjs.map +1 -1
  27. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.js +1 -1
  28. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.js.map +1 -1
  29. package/dist/martyrs/src/modules/community/components/pages/Blog.vue.cjs +1 -1
  30. package/dist/martyrs/src/modules/community/components/pages/Blog.vue.cjs.map +1 -1
  31. package/dist/martyrs/src/modules/community/components/pages/Blog.vue.js +1 -1
  32. package/dist/martyrs/src/modules/community/components/pages/Blog.vue.js.map +1 -1
  33. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.cjs +4 -1
  34. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.cjs.map +1 -1
  35. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js +4 -1
  36. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js.map +1 -1
  37. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.cjs +3 -3
  38. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.cjs.map +1 -1
  39. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +3 -3
  40. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js.map +1 -1
  41. package/dist/martyrs/src/modules/constructor/components/elements/VideoPlayer.vue.cjs +1 -1
  42. package/dist/martyrs/src/modules/constructor/components/elements/VideoPlayer.vue.cjs.map +1 -1
  43. package/dist/martyrs/src/modules/constructor/components/elements/VideoPlayer.vue.js +1 -1
  44. package/dist/martyrs/src/modules/constructor/components/elements/VideoPlayer.vue.js.map +1 -1
  45. package/dist/martyrs/src/modules/constructor/components/sections/Constructor.vue.cjs +9 -9
  46. package/dist/martyrs/src/modules/constructor/components/sections/Constructor.vue.cjs.map +1 -1
  47. package/dist/martyrs/src/modules/constructor/components/sections/Constructor.vue.js +9 -9
  48. package/dist/martyrs/src/modules/constructor/components/sections/Constructor.vue.js.map +1 -1
  49. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.cjs +2 -2
  50. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.cjs.map +1 -1
  51. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +2 -2
  52. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js.map +1 -1
  53. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.cjs +1 -1
  54. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +1 -1
  55. package/dist/martyrs/src/modules/globals/globals.client.cjs +0 -9
  56. package/dist/martyrs/src/modules/globals/globals.client.cjs.map +1 -1
  57. package/dist/martyrs/src/modules/globals/globals.client.js +0 -9
  58. package/dist/martyrs/src/modules/globals/globals.client.js.map +1 -1
  59. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.cjs +40 -97
  60. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.cjs.map +1 -1
  61. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.js +40 -97
  62. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.js.map +1 -1
  63. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.cjs +1 -1
  64. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.js +1 -1
  65. package/dist/martyrs/src/modules/icons/skeletons/SkeletonBlogpost.vue.cjs +1 -1
  66. package/dist/martyrs/src/modules/icons/skeletons/SkeletonBlogpost.vue.cjs.map +1 -1
  67. package/dist/martyrs/src/modules/icons/skeletons/SkeletonBlogpost.vue.js +1 -1
  68. package/dist/martyrs/src/modules/icons/skeletons/SkeletonBlogpost.vue.js.map +1 -1
  69. package/dist/martyrs/src/modules/notifications/notifications.client.cjs +35 -9
  70. package/dist/martyrs/src/modules/notifications/notifications.client.cjs.map +1 -1
  71. package/dist/martyrs/src/modules/notifications/notifications.client.js +35 -9
  72. package/dist/martyrs/src/modules/notifications/notifications.client.js.map +1 -1
  73. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.cjs +1 -1
  74. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js +1 -1
  75. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs +1 -1
  76. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +1 -1
  77. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs +7 -7
  78. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs.map +1 -1
  79. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +8 -8
  80. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js.map +1 -1
  81. package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.cjs +1 -1
  82. package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.js +1 -1
  83. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs +1 -1
  84. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +1 -1
  85. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.cjs +1 -1
  86. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
  87. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.cjs +1 -1
  88. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +1 -1
  89. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.cjs +1 -1
  90. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
  91. package/dist/martyrs/src/modules/products/components/blocks/CardPosition.vue.cjs +1 -1
  92. package/dist/martyrs/src/modules/products/components/blocks/CardPosition.vue.js +1 -1
  93. package/dist/martyrs/src/modules/products/components/pages/EditLeftover.vue.cjs +1 -1
  94. package/dist/martyrs/src/modules/products/components/pages/EditLeftover.vue.js +1 -1
  95. package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs +6 -5
  96. package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs.map +1 -1
  97. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +6 -5
  98. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js.map +1 -1
  99. package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.cjs +1 -1
  100. package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js +1 -1
  101. package/dist/martyrs.cjs.js +1 -1
  102. package/dist/martyrs.css +1 -1
  103. package/dist/martyrs.es.js +1 -1
  104. package/dist/notifications.server.js +69 -13
  105. package/dist/notifications.server.mjs +69 -13
  106. package/dist/orders.server.js +1 -0
  107. package/dist/orders.server.mjs +1 -0
  108. package/package.json +1 -1
  109. package/src/components/Shader/Shader.vue +44 -25
  110. package/src/modules/chats/routes/chats.routes.js +21 -17
  111. package/src/modules/chats/store/chat.store.js +55 -28
  112. package/src/modules/community/components/blocks/CardBlogpost.vue +1 -1
  113. package/src/modules/community/components/pages/Blog.vue +1 -1
  114. package/src/modules/community/components/pages/BlogPost.vue +1 -0
  115. package/src/modules/community/components/pages/CreateBlogPost.vue +3 -3
  116. package/src/modules/constructor/components/elements/VideoPlayer.vue +1 -1
  117. package/src/modules/constructor/components/sections/Constructor.vue +9 -9
  118. package/src/modules/events/components/pages/EditEvent.vue +1 -1
  119. package/src/modules/globals/controllers/classes/globals.websocket.js +29 -21
  120. package/src/modules/globals/globals.client.js +0 -12
  121. package/src/modules/globals/views/classes/globals.websocket.js +46 -146
  122. package/src/modules/icons/skeletons/SkeletonBlogpost.vue +2 -2
  123. package/src/modules/notifications/controllers/notifications.controller.js +2 -2
  124. package/src/modules/notifications/notifications.client.js +57 -19
  125. package/src/modules/notifications/notifications.server.js +3 -1
  126. package/src/modules/notifications/routes/notifications.routes.js +2 -2
  127. package/src/modules/notifications/services/notification.service.js +34 -15
  128. package/src/modules/notifications/services/web-push.service.js +7 -6
  129. package/src/modules/orders/components/pages/OrderCreate.vue +3 -4
  130. package/src/modules/orders/controllers/orders.controller.js +2 -0
  131. package/src/modules/products/components/pages/Product.vue +7 -6
  132. package/dist/martyrs/src/components/SelectMulti/SelectMulti.vue2.cjs.map +0 -1
  133. package/dist/martyrs/src/components/Tooltip/Tooltip.vue.js.map +0 -1
  134. package/src/modules/notifications/notifications2.client.js +0 -256
  135. package/src/modules/notifications/services/websocket.service.js +0 -100
@@ -1,7 +1,3 @@
1
- /**
2
- * Global WebSocket handler for centralized WebSocket connections
3
- * @martyrs/src/modules/globals/views/classes/globals.websocket.js
4
- */
5
1
  class GlobalWebSocket {
6
2
  constructor() {
7
3
  this.socket = null;
@@ -11,16 +7,13 @@ class GlobalWebSocket {
11
7
  this.reconnectDelay = 3000;
12
8
  this.baseUrl = null;
13
9
  this.pingInterval = null;
14
- this.pingIntervalTime = 30000; // 30 seconds
10
+ this.pingIntervalTime = 30000;
15
11
  this.listeners = {};
16
12
  this.userId = null;
17
13
  this.connectPromise = null;
14
+ this.subscribedModules = new Set(); // <--- ключевое изменение
18
15
  }
19
16
 
20
- /**
21
- * Initialize WebSocket with configuration options
22
- * @param {Object} options - Configuration options
23
- */
24
17
  initialize(options = {}) {
25
18
  this.maxReconnectAttempts = options.maxReconnectAttempts || this.maxReconnectAttempts;
26
19
  this.reconnectDelay = options.reconnectDelay || this.reconnectDelay;
@@ -28,67 +21,39 @@ class GlobalWebSocket {
28
21
  this.pingIntervalTime = options.pingInterval || this.pingIntervalTime;
29
22
  }
30
23
 
31
- /**
32
- * Get default WebSocket URL based on current HTTP URL
33
- * @returns {String} WebSocket URL
34
- */
35
24
  _getDefaultWsUrl() {
36
- // Check if window exists (for SSR compatibility)
37
- if (typeof window === 'undefined') {
38
- return '/api/ws'; // Default fallback for SSR
39
- }
40
-
25
+ if (typeof window === 'undefined') return '/api/ws';
41
26
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
42
27
  const host = window.location.host;
43
28
  return `${protocol}//${host}/api/ws`;
44
29
  }
45
30
 
46
- /**
47
- * Connect to WebSocket server
48
- * @param {String} userId - User ID for authentication
49
- * @returns {Promise} Promise that resolves when connection is established
50
- */
51
31
  connect(userId) {
52
- // Skip if running in SSR
53
- if (typeof window === 'undefined') {
54
- return Promise.resolve(false);
55
- }
56
-
57
- // Always update userId before any connection logic
32
+ if (typeof window === 'undefined') return Promise.resolve(false);
58
33
  this.userId = userId;
59
34
 
60
- // If already connected with the same user and socket is valid, return the existing connection
61
- if (this.isConnected && this.socket && this.socket.readyState === WebSocket.OPEN) {
35
+ if (this.isConnected && this.socket?.readyState === WebSocket.OPEN) {
62
36
  return Promise.resolve(this.socket);
63
37
  }
64
38
 
65
- // Clear any existing connection promise to avoid conflicts
66
- this.connectPromise = null;
67
-
68
- // Create new connection promise
69
39
  this.connectPromise = new Promise((resolve, reject) => {
70
- // Close existing connection if any
71
40
  this.disconnect();
72
41
 
73
- // Create new WebSocket connection with user ID
74
42
  const wsUrl = userId ? `${this.baseUrl}?userId=${encodeURIComponent(userId)}` : this.baseUrl;
75
43
  this.socket = new WebSocket(wsUrl);
76
44
 
77
- // Setup event handlers
78
45
  this.socket.onopen = () => {
79
46
  this._handleOpen();
80
47
  resolve(this.socket);
81
48
  };
82
-
49
+
83
50
  this.socket.onmessage = this._handleMessage.bind(this);
84
- this.socket.onerror = (error) => {
85
- this._handleError(error);
86
- reject(error);
51
+ this.socket.onerror = (err) => {
52
+ this._handleError(err);
53
+ reject(err);
87
54
  };
88
-
89
55
  this.socket.onclose = this._handleClose.bind(this);
90
56
 
91
- // Timeout for connection
92
57
  setTimeout(() => {
93
58
  if (!this.isConnected) {
94
59
  reject(new Error('WebSocket connection timeout'));
@@ -101,32 +66,20 @@ class GlobalWebSocket {
101
66
  return this.connectPromise;
102
67
  }
103
68
 
104
- /**
105
- * Disconnect from WebSocket server
106
- */
107
69
  disconnect() {
108
- // Skip if running in SSR
109
- if (typeof window === 'undefined') {
110
- return;
111
- }
70
+ if (typeof window === 'undefined') return;
112
71
 
113
72
  if (this.socket) {
114
- // Remove event listeners
115
73
  this.socket.onopen = null;
116
74
  this.socket.onmessage = null;
117
75
  this.socket.onerror = null;
118
76
  this.socket.onclose = null;
119
-
120
- // Close connection
121
- if (this.socket.readyState === WebSocket.OPEN ||
122
- this.socket.readyState === WebSocket.CONNECTING) {
77
+ if (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING) {
123
78
  this.socket.close();
124
79
  }
125
-
126
80
  this.socket = null;
127
81
  }
128
82
 
129
- // Clear ping interval
130
83
  if (this.pingInterval) {
131
84
  clearInterval(this.pingInterval);
132
85
  this.pingInterval = null;
@@ -136,11 +89,6 @@ class GlobalWebSocket {
136
89
  this.userId = null;
137
90
  }
138
91
 
139
- /**
140
- * Send data through WebSocket
141
- * @param {Object|String} data - Data to send
142
- * @returns {Boolean} Success status
143
- */
144
92
  async send(data) {
145
93
  if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
146
94
  console.error('Cannot send message: WebSocket is not connected');
@@ -148,51 +96,29 @@ class GlobalWebSocket {
148
96
  }
149
97
 
150
98
  try {
151
- const message = typeof data === 'string' ? data : JSON.stringify(data);
152
- await this.socket.send(message);
99
+ const msg = typeof data === 'string' ? data : JSON.stringify(data);
100
+ this.socket.send(msg);
153
101
  return true;
154
- } catch (error) {
155
- console.error('Error sending WebSocket message:', error);
102
+ } catch (err) {
103
+ console.error('Error sending message:', err);
156
104
  return false;
157
105
  }
158
106
  }
159
107
 
160
- /**
161
- * Register an event listener
162
- * @param {String} eventType - Event type to listen for
163
- * @param {Function} callback - Callback function
164
- * @param {Object} options - Additional options like module name for namespacing
165
- * @returns {String} Listener ID for unregistering
166
- */
167
108
  addEventListener(eventType, callback, options = {}) {
168
109
  const listenerId = `${options.module || 'global'}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
169
-
170
- if (!this.listeners[eventType]) {
171
- this.listeners[eventType] = {};
172
- }
173
-
110
+ if (!this.listeners[eventType]) this.listeners[eventType] = {};
174
111
  this.listeners[eventType][listenerId] = callback;
175
112
  return listenerId;
176
113
  }
177
114
 
178
- /**
179
- * Remove an event listener
180
- * @param {String} eventType - Event type
181
- * @param {String} listenerId - Listener ID returned from addEventListener
182
- */
183
115
  removeEventListener(eventType, listenerId) {
184
- if (this.listeners[eventType] && this.listeners[eventType][listenerId]) {
116
+ if (this.listeners[eventType]?.[listenerId]) {
185
117
  delete this.listeners[eventType][listenerId];
186
118
  }
187
119
  }
188
120
 
189
- /**
190
- * Remove all listeners for a module
191
- * @param {String} moduleName - Module name to remove listeners for
192
- */
193
121
  removeModuleListeners(moduleName) {
194
- if (!moduleName) return;
195
-
196
122
  Object.keys(this.listeners).forEach(eventType => {
197
123
  Object.keys(this.listeners[eventType]).forEach(listenerId => {
198
124
  if (listenerId.startsWith(`${moduleName}_`)) {
@@ -202,111 +128,85 @@ class GlobalWebSocket {
202
128
  });
203
129
  }
204
130
 
205
- /**
206
- * Handle WebSocket open event
207
- */
131
+ async subscribeModule(moduleName) {
132
+ if (!moduleName || this.subscribedModules.has(moduleName)) return;
133
+ const success = await this.send({ type: 'subscribe', module: moduleName });
134
+ if (success) {
135
+ this.subscribedModules.add(moduleName);
136
+ }
137
+ }
138
+
139
+ _resubscribeAllModules() {
140
+ for (const moduleName of this.subscribedModules) {
141
+ this.send({ type: 'subscribe', module: moduleName });
142
+ }
143
+ }
144
+
208
145
  _handleOpen() {
209
146
  this.isConnected = true;
210
147
  this.reconnectAttempts = 0;
211
-
212
- // Setup ping interval to keep connection alive
148
+
213
149
  this.pingInterval = setInterval(() => {
214
- if (this.socket && this.socket.readyState === WebSocket.OPEN) {
150
+ if (this.socket?.readyState === WebSocket.OPEN) {
215
151
  this.socket.send(JSON.stringify({ type: 'ping' }));
216
152
  }
217
153
  }, this.pingIntervalTime);
218
154
 
219
- // Notify listeners
155
+ this._resubscribeAllModules(); // <--- ВАЖНО
220
156
  this._notifyListeners('open', { isConnected: true });
221
157
  }
222
158
 
223
- /**
224
- * Handle WebSocket message event
225
- * @param {Event} event - WebSocket message event
226
- */
227
159
  _handleMessage(event) {
228
160
  try {
229
161
  const data = JSON.parse(event.data);
230
-
231
- // Generic event notifications
232
162
  this._notifyListeners('message', data);
233
-
234
- // Specific event type notifications
235
163
  if (data.type) {
236
164
  this._notifyListeners(data.type, data);
237
165
  }
238
-
239
- } catch (error) {
240
- console.error('Error processing WebSocket message:', error);
166
+ } catch (err) {
167
+ console.error('WebSocket message error:', err);
241
168
  }
242
169
  }
243
170
 
244
- /**
245
- * Handle WebSocket error
246
- * @param {Error} error - WebSocket error
247
- */
248
171
  _handleError(error) {
249
172
  console.error('WebSocket error:', error);
250
173
  this._notifyListeners('error', { error });
251
174
  }
252
175
 
253
- /**
254
- * Handle WebSocket close event
255
- * @param {Event} event - WebSocket close event
256
- */
257
176
  _handleClose(event) {
258
177
  this.isConnected = false;
259
-
260
- // Clear ping interval
261
178
  if (this.pingInterval) {
262
179
  clearInterval(this.pingInterval);
263
180
  this.pingInterval = null;
264
181
  }
265
-
182
+
266
183
  this._notifyListeners('close', { code: event.code, reason: event.reason });
267
-
268
- // Attempt to reconnect if not a normal closure and we have a userId
184
+
269
185
  if (event.code !== 1000 && this.userId && this.reconnectAttempts < this.maxReconnectAttempts) {
270
186
  this.reconnectAttempts++;
271
187
  const delay = this.reconnectDelay * this.reconnectAttempts;
272
-
273
188
  setTimeout(() => {
274
- if (this.userId) {
275
- this.connect(this.userId).catch(error => {
276
- console.error('Reconnection failed:', error);
277
- });
278
- }
189
+ this.connect(this.userId).catch(err => {
190
+ console.error('Reconnection failed:', err);
191
+ });
279
192
  }, delay);
280
193
  }
281
194
  }
282
195
 
283
- /**
284
- * Notify event listeners
285
- * @param {String} eventType - Event type
286
- * @param {Object} data - Event data
287
- */
288
196
  _notifyListeners(eventType, data) {
289
- if (!this.listeners[eventType]) return;
290
-
291
- Object.values(this.listeners[eventType]).forEach(callback => {
197
+ Object.values(this.listeners[eventType] || {}).forEach(fn => {
292
198
  try {
293
- callback(data);
294
- } catch (error) {
295
- console.error(`Error in WebSocket ${eventType} listener:`, error);
199
+ fn(data);
200
+ } catch (err) {
201
+ console.error(`Listener for ${eventType} failed:`, err);
296
202
  }
297
203
  });
298
204
  }
299
205
 
300
- /**
301
- * Get connection status
302
- * @returns {Boolean} Connection status
303
- */
304
206
  isSocketConnected() {
305
207
  return this.isConnected && this.socket?.readyState === WebSocket.OPEN;
306
208
  }
307
209
  }
308
210
 
309
- // Create singleton instance
310
211
  const globalWebSocket = new GlobalWebSocket();
311
-
312
- export default globalWebSocket;
212
+ export default globalWebSocket;
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <svg width="100%" height="20rem" xmlns="http://www.w3.org/2000/svg">
3
3
  <!-- Фоновый прямоугольник для всей карточки -->
4
- <rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" fill="rgb(var(--white))"/>
4
+ <rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" fill="rgb(var(--light))"/>
5
5
 
6
6
  <!-- Имитация шапки карточки -->
7
7
  <rect x="15" y="15" rx="4" ry="4" width="40%" height="20" fill="rgba(var(--black),0.05)"></rect>
@@ -14,7 +14,7 @@
14
14
  <rect x="15" y="130" rx="3" ry="3" width="70%" height="6" fill="rgba(var(--black),0.05)"></rect>
15
15
 
16
16
  <!-- Блик с анимацией движения -->
17
- <rect x="-25%" y="0" width="25%" height="100%" fill="rgb(var(--white))" mask="url(#myMask)" opacity="0.3">
17
+ <rect x="-25%" y="0" width="25%" height="100%" fill="rgb(var(--light))" mask="url(#myMask)" opacity="0.3">
18
18
  <animate attributeName="x" from="-25%" to="100%" dur="2s" repeatCount="indefinite"></animate>
19
19
  </rect>
20
20
  </svg>
@@ -1,12 +1,12 @@
1
1
  // controllers/notifications.controller.js
2
- const NotificationsController = (db) => {
2
+ const NotificationsController = (db, wss) => {
3
3
  // Create a new notification
4
4
  const create = async (req, res) => {
5
5
  try {
6
6
  const notification = await db.notification.create(req.body);
7
7
 
8
8
  // Trigger notification sending process
9
- const notificationService = require('../services/notification.service')(db);
9
+ const notificationService = require('../services/notification.service')(db, wss);
10
10
  notificationService.processNotification(notification);
11
11
 
12
12
  return res.status(201).json(notification);
@@ -178,6 +178,7 @@ class CapacitorPushHandler {
178
178
  /**
179
179
  * Notification Manager for coordinating WebSocket and Push notifications
180
180
  */
181
+
181
182
  class NotificationManager {
182
183
  constructor(store, options = {}) {
183
184
  this.store = store;
@@ -187,45 +188,82 @@ class NotificationManager {
187
188
  this.isServer = typeof window === 'undefined';
188
189
  }
189
190
 
190
- /**
191
- * Initialize notifications
192
- */
191
+ async registerWebPush(store) {
192
+ if (!('Notification' in window) || !('serviceWorker' in navigator) || !('PushManager' in window)) {
193
+ console.warn('Web Push не поддерживается в браузере');
194
+ return;
195
+ }
196
+
197
+ const permission = await Notification.requestPermission();
198
+ if (permission !== 'granted') {
199
+ console.warn('Разрешение на уведомления не получено');
200
+ return;
201
+ }
202
+
203
+ const registration = await navigator.serviceWorker.register('/sw.js');
204
+ const subscription = await registration.pushManager.subscribe({
205
+ userVisibleOnly: true,
206
+ applicationServerKey: 'BJtNnRrx05VQS0abnkHC-8gHJWpnmoqC_iQveENCmZOZIs-adWzqAiqFCdGVVd7CbiaLW-Q5iuIBDRgM9G-VnKg'
207
+ });
208
+
209
+ console.log('New subscription:', JSON.stringify(subscription));
210
+
211
+ // Отправь подписку на сервер
212
+ await store.notifications.actions.registerDevice({
213
+ deviceToken: JSON.stringify(subscription),
214
+ deviceType: 'web'
215
+ });
216
+ }
217
+
193
218
  async initialize() {
194
219
  if (this.initialized || this.isServer) return;
195
-
196
- // Get current user ID from auth store instead of localStorage
220
+
197
221
  const userId = this.store.auth.state.user?._id;
198
222
  if (!userId) {
199
223
  console.warn('Cannot initialize notifications: No user ID found in auth store');
200
224
  return;
201
225
  }
202
-
203
- // Initialize WebSocket for realtime notifications
226
+
227
+ console.log('Connecting to websockets via notifications')
204
228
  await globalWebSocket.connect(userId);
205
-
206
- // Initialize push notifications for mobile if enabled
229
+
230
+ globalWebSocket.removeModuleListeners('notification');
231
+
232
+ await globalWebSocket.subscribeModule('notification');
233
+
234
+ globalWebSocket.addEventListener(
235
+ 'notification',
236
+ (data) => {
237
+ this.store.notifications.actions.addLocalNotification(data.data);
238
+ },
239
+ { module: 'notification' }
240
+ );
241
+
242
+
243
+
244
+ // 🎯 Опционально включаем push
207
245
  if (this.options.enablePush !== false) {
208
246
  await this.pushHandler.requestPermissions();
247
+ await this.registerWebPush(this.store)
209
248
  }
210
-
249
+
211
250
  this.initialized = true;
212
-
213
- // Fetch existing notifications
251
+
252
+ // Загружаем список уведомлений из API
214
253
  await this.store.notifications.actions.getNotifications(userId);
215
254
  }
216
255
 
217
- /**
218
- * Disconnect and clean up
219
- */
220
256
  disconnect() {
221
257
  if (this.isServer) return;
222
-
223
- globalWebSocket.removeModuleListeners('notifications');
258
+
259
+ globalWebSocket.removeModuleListeners('notification');
224
260
  this.pushHandler.removeListeners();
225
261
  this.initialized = false;
226
262
  }
227
263
  }
228
264
 
265
+
266
+
229
267
  /**
230
268
  * Server-side utility for pre-fetching notification data
231
269
  */
@@ -283,7 +321,7 @@ function initializeNotifications(app, store, router, options = {}) {
283
321
 
284
322
  if (autoInit) {
285
323
  // Initialize after auth is confirmed
286
- const isAuthenticated = store.auth.state.isAuthenticated;
324
+ const isAuthenticated = store.auth.state.access.status;
287
325
  const userId = store.auth.state.user?._id;
288
326
 
289
327
  if (isAuthenticated && userId) {
@@ -291,7 +329,7 @@ function initializeNotifications(app, store, router, options = {}) {
291
329
  }
292
330
 
293
331
  // Watch for user login/logout using auth store
294
- watch(() => store.auth.state.isAuthenticated, (isAuthenticated) => {
332
+ watch(() => store.auth.state.access.status, (isAuthenticated) => {
295
333
  if (isAuthenticated) {
296
334
  notificationManager.initialize();
297
335
  } else {
@@ -20,6 +20,7 @@ const NotificationService = require('./services/notification.service.js');
20
20
  const { getInstance } = require('@martyrs/src/modules/globals/controllers/classes/globals.abac.js');
21
21
 
22
22
  function initializeNotifications(app, db, wss, origins, publicPath) {
23
+ console.log('wss init is', wss)
23
24
  // Set up models in the database object
24
25
  db.notification = NotificationModel(db);
25
26
  db.userDevice = UserDeviceModel(db);
@@ -31,11 +32,12 @@ function initializeNotifications(app, db, wss, origins, publicPath) {
31
32
 
32
33
  // Set up routes if app is provided
33
34
  if (app) {
34
- notificationsRoutes(app, db, origins, publicPath);
35
+ notificationsRoutes(app, db, wss, origins, publicPath);
35
36
  }
36
37
 
37
38
  // Initialize notification service and related background tasks
38
39
  const notificationService = NotificationService(db, wss);
40
+ console.log('[DEBUG] WSS in notification init:', wss);
39
41
 
40
42
  // Set up a scheduler to process pending notifications
41
43
  setInterval(() => {
@@ -1,6 +1,6 @@
1
1
  // routes/notifications.routes.js
2
- const notificationsRoutes = (app, db, origins, publicPath) => {
3
- const controller = require('../controllers/notifications.controller')(db);
2
+ const notificationsRoutes = (app, db, wss, origins, publicPath) => {
3
+ const controller = require('../controllers/notifications.controller')(db, wss);
4
4
 
5
5
  // Get notifications for a user
6
6
  app.get('/api/notifications/user/:userId', controller.getUserNotifications);
@@ -1,18 +1,33 @@
1
- // services/notification.service.js
2
- const NotificationService = (db, wss) => {
1
+ const ObjectId = require('mongoose').Types.ObjectId;
2
+
3
+ module.exports = function(db, wss) {
4
+ wss.registerModule('notification', async (ws, msg) => {
5
+ console.log('[WebSocket][notification] msg:', msg);
6
+ });
7
+
8
+
3
9
  // Process and route notification to appropriate channels
4
10
  const processNotification = async (notification) => {
5
11
  try {
6
- const userId = notification.userId;
12
+ const userId = notification.userId.toString();
7
13
 
8
14
  // Get user preferences
9
15
  const preferences = await db.notificationPreference.find({
10
- userId,
11
- notificationType: notification.type
16
+ userId: userId,
17
+ // notificationType: notification.type
12
18
  });
13
19
 
20
+ console.log('userId', userId)
21
+
22
+ console.log('preferences', preferences)
23
+
24
+ console.log('notificationType', notification.type)
25
+
26
+ console.log('notification', notification)
27
+
14
28
  // Get user data
15
- const user = await db.mongoose.model('User').findById(userId);
29
+ const user = await db.mongoose.model('User').findById(new ObjectId(userId));
30
+
16
31
  if (!user) {
17
32
  throw new Error(`User not found: ${userId}`);
18
33
  }
@@ -53,6 +68,9 @@ const NotificationService = (db, wss) => {
53
68
  .map(pref => pref.channelType);
54
69
  }
55
70
 
71
+
72
+ console.log('channels', channels)
73
+
56
74
  // Send to each enabled channel
57
75
  for (const channel of channels) {
58
76
  const sendFunc = channelRouters[channel];
@@ -107,20 +125,23 @@ const NotificationService = (db, wss) => {
107
125
  }
108
126
  };
109
127
 
110
- // Send web notification (for real-time notifications via WebSocket/SSE)
111
- // const webSocketService = require('./websocket.service')(wss);
112
-
128
+ // Send websocket notifications
113
129
  const sendWebNotification = async (notification, user) => {
114
- return wss.sendToUserInModule('notification', user._id, {
130
+ console.log(`[WebSocket][notification] sending to user ${user._id}`);
131
+ const result = await wss.sendToUserInModule('notification', user._id, {
115
132
  type: 'notification',
116
133
  data: notification
117
134
  });
135
+ if (!result) {
136
+ console.log(`Failed to send web notification to user ${user._id}`);
137
+ }
118
138
  };
119
139
 
120
140
  // Send push notification to mobile device
121
141
  const sendPushNotification = async (notification, user, device) => {
122
- // Implementation would depend on your push notification provider (Firebase, APN, etc.)
142
+
123
143
  const pushService = getPushServiceByDeviceType(device.deviceType);
144
+
124
145
  return pushService.send({
125
146
  token: device.deviceToken,
126
147
  title: notification.title,
@@ -136,7 +157,7 @@ const NotificationService = (db, wss) => {
136
157
  } else if (deviceType === 'android') {
137
158
  return require('./fcm.service');
138
159
  } else {
139
- // return require('./web-push.service');
160
+ return require('./web-push.service');
140
161
  }
141
162
  };
142
163
 
@@ -198,6 +219,4 @@ const NotificationService = (db, wss) => {
198
219
  processNotification,
199
220
  processPendingNotifications
200
221
  };
201
- };
202
-
203
- module.exports = NotificationService;
222
+ };
@@ -13,21 +13,22 @@ const WebPushService = {
13
13
  try {
14
14
  // Parse the subscription object from the token
15
15
  const subscription = JSON.parse(token);
16
-
16
+ console.log('title is', title)
17
+ console.log('body is', body)
18
+ console.log('data is', data)
17
19
  // Prepare the notification payload
18
20
  const payload = JSON.stringify({
19
- notification: {
20
21
  title: title,
21
22
  body: body,
22
23
  icon: process.env.NOTIFICATION_ICON_URL || '/favicon.ico',
23
- badge: process.env.NOTIFICATION_BADGE_URL,
24
+ badge: process.env.NOTIFICATION_BADGE_URL || '/favicon.ico',
24
25
  data: data
25
- }
26
26
  });
27
-
27
+ console.log('payload is', payload)
28
+
28
29
  // Send the notification
29
30
  const result = await webpush.sendNotification(subscription, payload);
30
-
31
+ console.log('web push is', result)
31
32
  return { success: true, statusCode: result.statusCode };
32
33
  } catch (error) {
33
34
  console.error('Web Push service error:', error);