@novu/react 3.0.0 → 3.0.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.
@@ -1,805 +0,0 @@
1
- // src/components/Bell.tsx
2
- import React2 from "react";
3
-
4
- // src/components/Mounter.tsx
5
- import { useEffect, useRef } from "react";
6
- import { jsx } from "react/jsx-runtime";
7
- function Mounter({ mount }) {
8
- const ref = useRef(null);
9
- useEffect(() => {
10
- let unmount;
11
- const element = ref.current;
12
- if (element && mount) {
13
- const possibleUnmount = mount(element);
14
- if (possibleUnmount) {
15
- unmount = possibleUnmount;
16
- }
17
- }
18
- return () => {
19
- if (element && unmount) {
20
- unmount(element);
21
- }
22
- };
23
- }, [ref, mount]);
24
- return /* @__PURE__ */ jsx("div", { ref });
25
- }
26
-
27
- // src/components/Renderer.tsx
28
- import { useCallback, useState } from "react";
29
- import { createPortal } from "react-dom";
30
-
31
- // src/utils/createContextAndHook.ts
32
- import React from "react";
33
- function assertContextExists(contextVal, msgOrCtx) {
34
- if (!contextVal) {
35
- throw typeof msgOrCtx === "string" ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);
36
- }
37
- }
38
- var createContextAndHook = (displayName, options) => {
39
- const { assertCtxFn = assertContextExists } = options || {};
40
- const Ctx = React.createContext(void 0);
41
- Ctx.displayName = displayName;
42
- const useCtx = () => {
43
- const ctx = React.useContext(Ctx);
44
- assertCtxFn(ctx, `Component must be wrapped with ${Ctx.displayName}`);
45
- return ctx.value;
46
- };
47
- const useCtxWithoutGuarantee = () => {
48
- const ctx = React.useContext(Ctx);
49
- return ctx ? ctx.value : {};
50
- };
51
- return [Ctx, useCtx, useCtxWithoutGuarantee];
52
- };
53
-
54
- // src/context/RendererContext.tsx
55
- import { jsx as jsx2 } from "react/jsx-runtime";
56
- var [RendererContext, useRendererContext, useUnsafeRendererContext] = createContextAndHook("RendererContext");
57
- var RendererProvider = (props) => {
58
- return /* @__PURE__ */ jsx2(RendererContext.Provider, { value: { value: props.value }, children: props.children });
59
- };
60
-
61
- // src/components/Renderer.tsx
62
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
63
- var Renderer = (props) => {
64
- const { children } = props;
65
- const [mountedElements, setMountedElements] = useState(/* @__PURE__ */ new Map());
66
- const mountElement = useCallback(
67
- (el, mountedElement) => {
68
- setMountedElements((prev) => {
69
- const newMountedElements = new Map(prev);
70
- newMountedElements.set(el, mountedElement);
71
- return newMountedElements;
72
- });
73
- return () => {
74
- setMountedElements((prev) => {
75
- const newMountedElements = new Map(prev);
76
- newMountedElements.delete(el);
77
- return newMountedElements;
78
- });
79
- };
80
- },
81
- [setMountedElements]
82
- );
83
- return /* @__PURE__ */ jsxs(RendererProvider, { value: { mountElement }, children: [
84
- [...mountedElements].map(([element, mountedElement]) => {
85
- return createPortal(mountedElement, element);
86
- }),
87
- children
88
- ] });
89
- };
90
- var withRenderer = (WrappedComponent) => {
91
- const HOC = (props) => {
92
- return /* @__PURE__ */ jsx3(Renderer, { children: /* @__PURE__ */ jsx3(WrappedComponent, { ...props }) });
93
- };
94
- HOC.displayName = `WithRenderer(${WrappedComponent.displayName || WrappedComponent.name || "Component"})`;
95
- return HOC;
96
- };
97
-
98
- // src/context/NovuUIContext.tsx
99
- import { jsx as jsx4 } from "react/jsx-runtime";
100
- var [NovuUIContext, useNovuUIContext, useUnsafeNovuUIContext] = createContextAndHook("NovuUIContext");
101
- var NovuUIProvider = (props) => {
102
- return /* @__PURE__ */ jsx4(NovuUIContext.Provider, { value: { value: props.value }, children: props.children });
103
- };
104
-
105
- // src/components/Bell.tsx
106
- import { jsx as jsx5 } from "react/jsx-runtime";
107
- var _Bell = React2.memo((props) => {
108
- const { renderBell } = props;
109
- const { novuUI } = useNovuUIContext();
110
- const { mountElement } = useRendererContext();
111
- const mount = React2.useCallback(
112
- (element) => {
113
- return novuUI.mountComponent({
114
- name: "Bell",
115
- element,
116
- props: renderBell ? { renderBell: (el, unreadCount) => mountElement(el, renderBell(unreadCount)) } : void 0
117
- });
118
- },
119
- [renderBell]
120
- );
121
- return /* @__PURE__ */ jsx5(Mounter, { mount });
122
- });
123
- var Bell = withRenderer(_Bell);
124
-
125
- // src/components/Inbox.tsx
126
- import React4, { useMemo as useMemo2 } from "react";
127
-
128
- // src/hooks/NovuProvider.tsx
129
- import { Novu } from "@novu/js";
130
- import { createContext, useContext, useMemo } from "react";
131
- import { jsx as jsx6 } from "react/jsx-runtime";
132
- var version = "2.6.6";
133
- var name = "@novu/react";
134
- var baseUserAgent = `${name}@${version}`;
135
- var NovuContext = createContext(void 0);
136
- var NovuProvider = ({
137
- children,
138
- applicationIdentifier,
139
- subscriberId,
140
- subscriberHash,
141
- backendUrl,
142
- socketUrl,
143
- useCache
144
- }) => {
145
- return /* @__PURE__ */ jsx6(
146
- InternalNovuProvider,
147
- {
148
- applicationIdentifier,
149
- subscriberId,
150
- subscriberHash,
151
- backendUrl,
152
- socketUrl,
153
- useCache,
154
- userAgentType: "hooks",
155
- children
156
- }
157
- );
158
- };
159
- var InternalNovuProvider = ({
160
- children,
161
- applicationIdentifier,
162
- subscriberId,
163
- subscriberHash,
164
- backendUrl,
165
- socketUrl,
166
- useCache,
167
- userAgentType
168
- }) => {
169
- const novu = useMemo(
170
- () => new Novu({
171
- applicationIdentifier,
172
- subscriberId,
173
- subscriberHash,
174
- backendUrl,
175
- socketUrl,
176
- useCache,
177
- __userAgent: `${baseUserAgent} ${userAgentType}`
178
- }),
179
- [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache, userAgentType]
180
- );
181
- return /* @__PURE__ */ jsx6(NovuContext.Provider, { value: novu, children });
182
- };
183
- var useNovu = () => {
184
- const context = useContext(NovuContext);
185
- if (!context) {
186
- throw new Error("useNovu must be used within a <NovuProvider />");
187
- }
188
- return context;
189
- };
190
- var useUnsafeNovu = () => {
191
- const context = useContext(NovuContext);
192
- return context;
193
- };
194
-
195
- // src/components/NovuUI.tsx
196
- import { NovuUI as NovuUIClass } from "@novu/js/ui";
197
- import { useEffect as useEffect2, useState as useState2 } from "react";
198
-
199
- // src/hooks/internal/useDataRef.ts
200
- import { useRef as useRef2 } from "react";
201
- var useDataRef = (data) => {
202
- const ref = useRef2(data);
203
- ref.current = data;
204
- return ref;
205
- };
206
-
207
- // src/components/NovuUI.tsx
208
- import { jsx as jsx7 } from "react/jsx-runtime";
209
- var NovuUI = ({ options, novu, children }) => {
210
- const optionsRef = useDataRef({ ...options, novu });
211
- const [novuUI, setNovuUI] = useState2();
212
- useEffect2(() => {
213
- const novu2 = new NovuUIClass(optionsRef.current);
214
- setNovuUI(novu2);
215
- return () => {
216
- novu2.unmount();
217
- };
218
- }, []);
219
- useEffect2(() => {
220
- if (!novuUI) {
221
- return;
222
- }
223
- novuUI.updateAppearance(options.appearance);
224
- novuUI.updateLocalization(options.localization);
225
- novuUI.updateTabs(options.tabs);
226
- novuUI.updateOptions(options.options);
227
- novuUI.updateRouterPush(options.routerPush);
228
- }, [options]);
229
- if (!novuUI) {
230
- return null;
231
- }
232
- return /* @__PURE__ */ jsx7(NovuUIProvider, { value: { novuUI }, children });
233
- };
234
-
235
- // src/components/Inbox.tsx
236
- import { jsx as jsx8 } from "react/jsx-runtime";
237
- var _DefaultInbox = (props) => {
238
- const {
239
- open,
240
- renderNotification,
241
- renderSubject,
242
- renderBody,
243
- renderBell,
244
- onNotificationClick,
245
- onPrimaryActionClick,
246
- onSecondaryActionClick,
247
- placement,
248
- placementOffset
249
- } = props;
250
- const { novuUI } = useNovuUIContext();
251
- const { mountElement } = useRendererContext();
252
- const mount = React4.useCallback(
253
- (element) => {
254
- if (renderNotification) {
255
- return novuUI.mountComponent({
256
- name: "Inbox",
257
- props: {
258
- open,
259
- renderNotification: renderNotification ? (el, notification) => mountElement(el, renderNotification(notification)) : void 0,
260
- renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : void 0,
261
- onNotificationClick,
262
- onPrimaryActionClick,
263
- onSecondaryActionClick,
264
- placementOffset,
265
- placement
266
- },
267
- element
268
- });
269
- }
270
- return novuUI.mountComponent({
271
- name: "Inbox",
272
- props: {
273
- open,
274
- renderSubject: renderSubject ? (el, notification) => mountElement(el, renderSubject(notification)) : void 0,
275
- renderBody: renderBody ? (el, notification) => mountElement(el, renderBody(notification)) : void 0,
276
- renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : void 0,
277
- onNotificationClick,
278
- onPrimaryActionClick,
279
- onSecondaryActionClick,
280
- placementOffset,
281
- placement
282
- },
283
- element
284
- });
285
- },
286
- [
287
- open,
288
- renderNotification,
289
- renderSubject,
290
- renderBody,
291
- renderBell,
292
- onNotificationClick,
293
- onPrimaryActionClick,
294
- onSecondaryActionClick
295
- ]
296
- );
297
- return /* @__PURE__ */ jsx8(Mounter, { mount });
298
- };
299
- var DefaultInbox = withRenderer(_DefaultInbox);
300
- var Inbox = React4.memo((props) => {
301
- const { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl } = props;
302
- const novu = useUnsafeNovu();
303
- if (novu) {
304
- return /* @__PURE__ */ jsx8(InboxChild, { ...props });
305
- }
306
- return /* @__PURE__ */ jsx8(
307
- InternalNovuProvider,
308
- {
309
- applicationIdentifier,
310
- subscriberId,
311
- subscriberHash,
312
- backendUrl,
313
- socketUrl,
314
- userAgentType: "components",
315
- children: /* @__PURE__ */ jsx8(InboxChild, { ...props })
316
- }
317
- );
318
- });
319
- var InboxChild = React4.memo((props) => {
320
- const {
321
- localization,
322
- appearance,
323
- tabs,
324
- preferencesFilter,
325
- routerPush,
326
- applicationIdentifier,
327
- subscriberId,
328
- subscriberHash,
329
- backendUrl,
330
- socketUrl
331
- } = props;
332
- const novu = useNovu();
333
- const options = useMemo2(() => {
334
- return {
335
- localization,
336
- appearance,
337
- tabs,
338
- preferencesFilter,
339
- routerPush,
340
- options: { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl }
341
- };
342
- }, [
343
- localization,
344
- appearance,
345
- tabs,
346
- preferencesFilter,
347
- applicationIdentifier,
348
- subscriberId,
349
- subscriberHash,
350
- backendUrl,
351
- socketUrl
352
- ]);
353
- if (isWithChildrenProps(props)) {
354
- return /* @__PURE__ */ jsx8(NovuUI, { options, novu, children: props.children });
355
- }
356
- const {
357
- open,
358
- renderNotification,
359
- renderSubject,
360
- renderBody,
361
- renderBell,
362
- onNotificationClick,
363
- onPrimaryActionClick,
364
- onSecondaryActionClick,
365
- placementOffset,
366
- placement
367
- } = props;
368
- return /* @__PURE__ */ jsx8(NovuUI, { options, novu, children: /* @__PURE__ */ jsx8(
369
- DefaultInbox,
370
- {
371
- open,
372
- renderNotification,
373
- renderSubject,
374
- renderBody,
375
- renderBell,
376
- onNotificationClick,
377
- onPrimaryActionClick,
378
- onSecondaryActionClick,
379
- placement,
380
- placementOffset
381
- }
382
- ) });
383
- });
384
- function isWithChildrenProps(props) {
385
- return "children" in props;
386
- }
387
-
388
- // src/components/Preferences.tsx
389
- import React5 from "react";
390
- import { jsx as jsx9 } from "react/jsx-runtime";
391
- var Preferences = () => {
392
- const { novuUI } = useNovuUIContext();
393
- const mount = React5.useCallback((element) => {
394
- return novuUI.mountComponent({
395
- name: "Preferences",
396
- element
397
- });
398
- }, []);
399
- return /* @__PURE__ */ jsx9(Mounter, { mount });
400
- };
401
-
402
- // src/components/Notifications.tsx
403
- import React6 from "react";
404
- import { jsx as jsx10 } from "react/jsx-runtime";
405
- var _Notifications = React6.memo((props) => {
406
- const {
407
- renderNotification,
408
- renderSubject,
409
- renderBody,
410
- onNotificationClick,
411
- onPrimaryActionClick,
412
- onSecondaryActionClick
413
- } = props;
414
- const { novuUI } = useNovuUIContext();
415
- const { mountElement } = useRendererContext();
416
- const mount = React6.useCallback(
417
- (element) => {
418
- if (renderNotification) {
419
- return novuUI.mountComponent({
420
- name: "Notifications",
421
- element,
422
- props: {
423
- renderNotification: renderNotification ? (el, notification) => mountElement(el, renderNotification(notification)) : void 0,
424
- onNotificationClick,
425
- onPrimaryActionClick,
426
- onSecondaryActionClick
427
- }
428
- });
429
- }
430
- return novuUI.mountComponent({
431
- name: "Notifications",
432
- element,
433
- props: {
434
- renderSubject: renderSubject ? (el, notification) => mountElement(el, renderSubject(notification)) : void 0,
435
- renderBody: renderBody ? (el, notification) => mountElement(el, renderBody(notification)) : void 0,
436
- onNotificationClick,
437
- onPrimaryActionClick,
438
- onSecondaryActionClick
439
- }
440
- });
441
- },
442
- [renderNotification, renderSubject, renderBody, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]
443
- );
444
- return /* @__PURE__ */ jsx10(Mounter, { mount });
445
- });
446
- var Notifications = withRenderer(_Notifications);
447
-
448
- // src/components/InboxContent.tsx
449
- import React7 from "react";
450
- import { jsx as jsx11 } from "react/jsx-runtime";
451
- var _InboxContent = React7.memo((props) => {
452
- const {
453
- onNotificationClick,
454
- onPrimaryActionClick,
455
- renderNotification,
456
- renderSubject,
457
- renderBody,
458
- onSecondaryActionClick,
459
- initialPage,
460
- hideNav
461
- } = props;
462
- const { novuUI } = useNovuUIContext();
463
- const { mountElement } = useRendererContext();
464
- const mount = React7.useCallback(
465
- (element) => {
466
- if (renderNotification) {
467
- return novuUI.mountComponent({
468
- name: "InboxContent",
469
- element,
470
- props: {
471
- renderNotification: renderNotification ? (el, notification) => mountElement(el, renderNotification(notification)) : void 0,
472
- onNotificationClick,
473
- onPrimaryActionClick,
474
- onSecondaryActionClick,
475
- initialPage,
476
- hideNav
477
- }
478
- });
479
- }
480
- return novuUI.mountComponent({
481
- name: "InboxContent",
482
- element,
483
- props: {
484
- renderSubject: renderSubject ? (el, notification) => mountElement(el, renderSubject(notification)) : void 0,
485
- renderBody: renderBody ? (el, notification) => mountElement(el, renderBody(notification)) : void 0,
486
- onNotificationClick,
487
- onPrimaryActionClick,
488
- onSecondaryActionClick,
489
- initialPage,
490
- hideNav
491
- }
492
- });
493
- },
494
- [renderNotification, renderSubject, renderBody, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]
495
- );
496
- return /* @__PURE__ */ jsx11(Mounter, { mount });
497
- });
498
- var InboxContent = withRenderer(_InboxContent);
499
-
500
- // src/hooks/useNotifications.ts
501
- import { useState as useState3, useEffect as useEffect3, useRef as useRef3 } from "react";
502
- import { isSameFilter } from "@novu/js";
503
- var useNotifications = (props) => {
504
- const { tags, read, archived = false, limit, onSuccess, onError } = props || {};
505
- const filterRef = useRef3(void 0);
506
- const { notifications, on } = useNovu();
507
- const [data, setData] = useState3();
508
- const [error, setError] = useState3();
509
- const [isLoading, setIsLoading] = useState3(true);
510
- const [isFetching, setIsFetching] = useState3(false);
511
- const [hasMore, setHasMore] = useState3(false);
512
- const length = data?.length;
513
- const after = length ? data[length - 1].id : void 0;
514
- const sync = (event) => {
515
- if (!event.data || filterRef.current && !isSameFilter(filterRef.current, event.data.filter)) {
516
- return;
517
- }
518
- setData(event.data.notifications);
519
- setHasMore(event.data.hasMore);
520
- };
521
- useEffect3(() => {
522
- const cleanup = on("notifications.list.updated", sync);
523
- return () => {
524
- cleanup();
525
- };
526
- }, []);
527
- useEffect3(() => {
528
- const newFilter = { tags, read, archived };
529
- if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {
530
- return;
531
- }
532
- notifications.clearCache({ filter: filterRef.current });
533
- filterRef.current = newFilter;
534
- fetchNotifications({ refetch: true });
535
- }, [tags, read, archived]);
536
- const fetchNotifications = async (options) => {
537
- if (options?.refetch) {
538
- setError(void 0);
539
- setIsLoading(true);
540
- setIsFetching(false);
541
- }
542
- setIsFetching(true);
543
- const response = await notifications.list({
544
- tags,
545
- read,
546
- archived,
547
- limit,
548
- after: options?.refetch ? void 0 : after
549
- });
550
- if (response.error) {
551
- setError(response.error);
552
- onError?.(response.error);
553
- } else {
554
- onSuccess?.(response.data.notifications);
555
- setData(response.data.notifications);
556
- setHasMore(response.data.hasMore);
557
- }
558
- setIsLoading(false);
559
- setIsFetching(false);
560
- };
561
- const refetch = () => {
562
- notifications.clearCache({ filter: { tags, read, archived } });
563
- return fetchNotifications({ refetch: true });
564
- };
565
- const fetchMore = async () => {
566
- if (!hasMore || isFetching) return;
567
- return fetchNotifications();
568
- };
569
- const readAll = async () => {
570
- return await notifications.readAll({ tags });
571
- };
572
- const archiveAll = async () => {
573
- return await notifications.archiveAll({ tags });
574
- };
575
- const archiveAllRead = async () => {
576
- return await notifications.archiveAllRead({ tags });
577
- };
578
- return {
579
- readAll,
580
- archiveAll,
581
- archiveAllRead,
582
- notifications: data,
583
- error,
584
- isLoading,
585
- isFetching,
586
- refetch,
587
- fetchMore,
588
- hasMore
589
- };
590
- };
591
-
592
- // src/hooks/usePreferences.ts
593
- import { useEffect as useEffect4, useState as useState4 } from "react";
594
- var usePreferences = (props) => {
595
- const { onSuccess, onError } = props || {};
596
- const [data, setData] = useState4();
597
- const { preferences, on } = useNovu();
598
- const [error, setError] = useState4();
599
- const [isLoading, setIsLoading] = useState4(true);
600
- const [isFetching, setIsFetching] = useState4(false);
601
- const sync = (event) => {
602
- if (!event.data) {
603
- return;
604
- }
605
- setData(event.data);
606
- };
607
- useEffect4(() => {
608
- fetchPreferences();
609
- const listUpdatedCleanup = on("preferences.list.updated", sync);
610
- const listPendingCleanup = on("preferences.list.pending", sync);
611
- const listResolvedCleanup = on("preferences.list.resolved", sync);
612
- return () => {
613
- listUpdatedCleanup();
614
- listPendingCleanup();
615
- listResolvedCleanup();
616
- };
617
- }, []);
618
- const fetchPreferences = async () => {
619
- setIsFetching(true);
620
- const response = await preferences.list(props?.filter);
621
- if (response.error) {
622
- setError(response.error);
623
- onError?.(response.error);
624
- } else {
625
- onSuccess?.(response.data);
626
- }
627
- setIsLoading(false);
628
- setIsFetching(false);
629
- };
630
- const refetch = () => {
631
- preferences.cache.clearAll();
632
- return fetchPreferences();
633
- };
634
- return {
635
- preferences: data,
636
- error,
637
- isLoading,
638
- isFetching,
639
- refetch
640
- };
641
- };
642
-
643
- // src/hooks/useCounts.ts
644
- import { useEffect as useEffect7, useState as useState6 } from "react";
645
- import { areTagsEqual } from "@novu/js";
646
-
647
- // src/hooks/internal/useWebsocketEvent.ts
648
- import { useEffect as useEffect6 } from "react";
649
-
650
- // src/utils/requestLock.ts
651
- function requestLock(id, cb) {
652
- if (!("locks" in navigator)) {
653
- cb(id);
654
- return () => {
655
- };
656
- }
657
- let isFulfilled = false;
658
- let promiseResolve;
659
- const promise = new Promise((resolve) => {
660
- promiseResolve = resolve;
661
- });
662
- navigator.locks.request(id, () => {
663
- if (!isFulfilled) {
664
- cb(id);
665
- }
666
- return promise;
667
- });
668
- return () => {
669
- isFulfilled = true;
670
- promiseResolve();
671
- };
672
- }
673
-
674
- // src/hooks/internal/useBrowserTabsChannel.ts
675
- import { useEffect as useEffect5, useState as useState5 } from "react";
676
- var useBrowserTabsChannel = ({
677
- channelName,
678
- onMessage
679
- }) => {
680
- const [tabsChannel] = useState5(
681
- typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelName) : void 0
682
- );
683
- const postMessage = (data) => {
684
- tabsChannel?.postMessage(data);
685
- };
686
- useEffect5(() => {
687
- const listener = (event) => {
688
- onMessage(event.data);
689
- };
690
- tabsChannel?.addEventListener("message", listener);
691
- return () => {
692
- tabsChannel?.removeEventListener("message", listener);
693
- };
694
- }, []);
695
- return { postMessage };
696
- };
697
-
698
- // src/hooks/internal/useWebsocketEvent.ts
699
- var useWebSocketEvent = ({
700
- event: webSocketEvent,
701
- eventHandler: onMessage
702
- }) => {
703
- const novu = useNovu();
704
- const { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });
705
- const updateReadCount = (data) => {
706
- onMessage(data);
707
- postMessage(data);
708
- };
709
- useEffect6(() => {
710
- let cleanup;
711
- const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {
712
- cleanup = novu.on(webSocketEvent, updateReadCount);
713
- });
714
- return () => {
715
- if (cleanup) {
716
- cleanup();
717
- }
718
- resolveLock();
719
- };
720
- }, []);
721
- };
722
-
723
- // src/hooks/useCounts.ts
724
- var useCounts = (props) => {
725
- const { filters, onSuccess, onError } = props;
726
- const { notifications } = useNovu();
727
- const [error, setError] = useState6();
728
- const [counts, setCounts] = useState6();
729
- const [isLoading, setIsLoading] = useState6(true);
730
- const [isFetching, setIsFetching] = useState6(false);
731
- const sync = async (notification) => {
732
- const existingCounts = counts ?? new Array(filters.length).fill(void 0);
733
- let countFiltersToFetch = [];
734
- if (notification) {
735
- for (let i = 0; i < existingCounts.length; i++) {
736
- const filter = filters[i];
737
- if (areTagsEqual(filter.tags, notification.tags)) {
738
- countFiltersToFetch.push(filter);
739
- }
740
- }
741
- } else {
742
- countFiltersToFetch = filters;
743
- }
744
- if (countFiltersToFetch.length === 0) {
745
- return;
746
- }
747
- setIsFetching(true);
748
- const countsRes = await notifications.count({ filters: countFiltersToFetch });
749
- setIsFetching(false);
750
- setIsLoading(false);
751
- if (countsRes.error) {
752
- setError(countsRes.error);
753
- onError?.(countsRes.error);
754
- return;
755
- }
756
- const data = countsRes.data;
757
- onSuccess?.(data.counts);
758
- setCounts((oldCounts) => {
759
- const newCounts = [];
760
- const countsReceived = data.counts;
761
- for (let i = 0; i < existingCounts.length; i++) {
762
- const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));
763
- newCounts.push(countReceived || oldCounts[i]);
764
- }
765
- return newCounts;
766
- });
767
- };
768
- useWebSocketEvent({
769
- event: "notifications.notification_received",
770
- eventHandler: (data) => {
771
- sync(data.result);
772
- }
773
- });
774
- useWebSocketEvent({
775
- event: "notifications.unread_count_changed",
776
- eventHandler: () => {
777
- sync();
778
- }
779
- });
780
- useEffect7(() => {
781
- setError(void 0);
782
- setIsLoading(true);
783
- setIsFetching(false);
784
- sync();
785
- }, [JSON.stringify(filters)]);
786
- const refetch = async () => {
787
- await sync();
788
- };
789
- return { counts, error, refetch, isLoading, isFetching };
790
- };
791
- export {
792
- Bell,
793
- Inbox,
794
- InboxContent,
795
- InternalNovuProvider,
796
- Notifications,
797
- NovuProvider,
798
- Preferences,
799
- useCounts,
800
- useNotifications,
801
- useNovu,
802
- usePreferences,
803
- useUnsafeNovu
804
- };
805
- //# sourceMappingURL=index.mjs.map