@novu/react 3.15.0 → 3.16.0
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/cjs/components/NovuUI.cjs.map +1 -1
- package/dist/cjs/components/NovuUI.d.cts +2 -2
- package/dist/cjs/components/connect-chat/ConnectChat.cjs +63 -0
- package/dist/cjs/components/connect-chat/ConnectChat.cjs.map +1 -0
- package/dist/cjs/components/connect-chat/ConnectChat.d.cts +12 -0
- package/dist/cjs/components/connect-chat/DefaultConnectChat.cjs +83 -0
- package/dist/cjs/components/connect-chat/DefaultConnectChat.cjs.map +1 -0
- package/dist/cjs/components/connect-chat/DefaultConnectChat.d.cts +7 -0
- package/dist/cjs/components/index.cjs +4 -0
- package/dist/cjs/components/index.cjs.map +1 -1
- package/dist/cjs/components/index.d.cts +5 -1
- package/dist/cjs/components/slack-connect-button/DefaultSlackConnectButton.cjs +89 -0
- package/dist/cjs/components/slack-connect-button/DefaultSlackConnectButton.cjs.map +1 -0
- package/dist/cjs/components/slack-connect-button/DefaultSlackConnectButton.d.cts +7 -0
- package/dist/cjs/components/slack-connect-button/SlackConnectButton.cjs +63 -0
- package/dist/cjs/components/slack-connect-button/SlackConnectButton.cjs.map +1 -0
- package/dist/cjs/components/slack-connect-button/SlackConnectButton.d.cts +12 -0
- package/dist/cjs/components/slack-link-user/DefaultSlackLinkUser.cjs +80 -0
- package/dist/cjs/components/slack-link-user/DefaultSlackLinkUser.cjs.map +1 -0
- package/dist/cjs/components/slack-link-user/DefaultSlackLinkUser.d.cts +7 -0
- package/dist/cjs/components/slack-link-user/SlackLinkUser.cjs +63 -0
- package/dist/cjs/components/slack-link-user/SlackLinkUser.cjs.map +1 -0
- package/dist/cjs/components/slack-link-user/SlackLinkUser.d.cts +12 -0
- package/dist/cjs/hooks/NovuProvider.cjs +34 -22
- package/dist/cjs/hooks/NovuProvider.cjs.map +1 -1
- package/dist/cjs/hooks/NovuProvider.d.cts +13 -2
- package/dist/cjs/hooks/index.cjs +10 -0
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/index.d.cts +5 -0
- package/dist/cjs/hooks/internal/useBrowserTabsChannel.cjs +5 -2
- package/dist/cjs/hooks/internal/useBrowserTabsChannel.cjs.map +1 -1
- package/dist/cjs/hooks/internal/useBrowserTabsChannel.d.cts +2 -1
- package/dist/cjs/hooks/internal/useWebsocketEvent.cjs +6 -3
- package/dist/cjs/hooks/internal/useWebsocketEvent.cjs.map +1 -1
- package/dist/cjs/hooks/internal/useWebsocketEvent.d.cts +2 -1
- package/dist/cjs/hooks/useChannelConnection.cjs +107 -0
- package/dist/cjs/hooks/useChannelConnection.cjs.map +1 -0
- package/dist/cjs/hooks/useChannelConnection.d.cts +20 -0
- package/dist/cjs/hooks/useChannelConnections.cjs +85 -0
- package/dist/cjs/hooks/useChannelConnections.cjs.map +1 -0
- package/dist/cjs/hooks/useChannelConnections.d.cts +24 -0
- package/dist/cjs/hooks/useChannelEndpoint.cjs +110 -0
- package/dist/cjs/hooks/useChannelEndpoint.cjs.map +1 -0
- package/dist/cjs/hooks/useChannelEndpoint.d.cts +20 -0
- package/dist/cjs/hooks/useCounts.cjs +5 -1
- package/dist/cjs/hooks/useCounts.cjs.map +1 -1
- package/dist/cjs/hooks/useCounts.d.cts +18 -0
- package/dist/cjs/hooks/useCreateChannelEndpoint.cjs +61 -0
- package/dist/cjs/hooks/useCreateChannelEndpoint.cjs.map +1 -0
- package/dist/cjs/hooks/useCreateChannelEndpoint.d.cts +17 -0
- package/dist/cjs/hooks/useDeleteChannelEndpoint.cjs +69 -0
- package/dist/cjs/hooks/useDeleteChannelEndpoint.cjs.map +1 -0
- package/dist/cjs/hooks/useDeleteChannelEndpoint.d.cts +17 -0
- package/dist/cjs/hooks/useNotifications.cjs +4 -0
- package/dist/cjs/hooks/useNotifications.cjs.map +1 -1
- package/dist/cjs/hooks/useNotifications.d.cts +18 -0
- package/dist/cjs/index.cjs +14 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +11 -2
- package/dist/cjs/internal/index.d.cts +1 -0
- package/dist/cjs/themes/index.d.cts +0 -1
- package/dist/cjs/utils/appearance.cjs.map +1 -1
- package/dist/cjs/utils/appearance.d.cts +2 -2
- package/dist/cjs/utils/types.d.cts +1 -1
- package/dist/esm/components/NovuUI.d.ts +2 -2
- package/dist/esm/components/NovuUI.js.map +1 -1
- package/dist/esm/components/connect-chat/ConnectChat.d.ts +12 -0
- package/dist/esm/components/connect-chat/ConnectChat.js +28 -0
- package/dist/esm/components/connect-chat/ConnectChat.js.map +1 -0
- package/dist/esm/components/connect-chat/DefaultConnectChat.d.ts +7 -0
- package/dist/esm/components/connect-chat/DefaultConnectChat.js +58 -0
- package/dist/esm/components/connect-chat/DefaultConnectChat.js.map +1 -0
- package/dist/esm/components/index.d.ts +5 -1
- package/dist/esm/components/index.js +2 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/components/slack-connect-button/DefaultSlackConnectButton.d.ts +7 -0
- package/dist/esm/components/slack-connect-button/DefaultSlackConnectButton.js +64 -0
- package/dist/esm/components/slack-connect-button/DefaultSlackConnectButton.js.map +1 -0
- package/dist/esm/components/slack-connect-button/SlackConnectButton.d.ts +12 -0
- package/dist/esm/components/slack-connect-button/SlackConnectButton.js +28 -0
- package/dist/esm/components/slack-connect-button/SlackConnectButton.js.map +1 -0
- package/dist/esm/components/slack-link-user/DefaultSlackLinkUser.d.ts +7 -0
- package/dist/esm/components/slack-link-user/DefaultSlackLinkUser.js +55 -0
- package/dist/esm/components/slack-link-user/DefaultSlackLinkUser.js.map +1 -0
- package/dist/esm/components/slack-link-user/SlackLinkUser.d.ts +12 -0
- package/dist/esm/components/slack-link-user/SlackLinkUser.js +28 -0
- package/dist/esm/components/slack-link-user/SlackLinkUser.js.map +1 -0
- package/dist/esm/hooks/NovuProvider.d.ts +13 -2
- package/dist/esm/hooks/NovuProvider.js +33 -22
- package/dist/esm/hooks/NovuProvider.js.map +1 -1
- package/dist/esm/hooks/index.d.ts +5 -0
- package/dist/esm/hooks/index.js +5 -0
- package/dist/esm/hooks/index.js.map +1 -1
- package/dist/esm/hooks/internal/useBrowserTabsChannel.d.ts +2 -1
- package/dist/esm/hooks/internal/useBrowserTabsChannel.js +5 -2
- package/dist/esm/hooks/internal/useBrowserTabsChannel.js.map +1 -1
- package/dist/esm/hooks/internal/useWebsocketEvent.d.ts +2 -1
- package/dist/esm/hooks/internal/useWebsocketEvent.js +6 -3
- package/dist/esm/hooks/internal/useWebsocketEvent.js.map +1 -1
- package/dist/esm/hooks/useChannelConnection.d.ts +20 -0
- package/dist/esm/hooks/useChannelConnection.js +81 -0
- package/dist/esm/hooks/useChannelConnection.js.map +1 -0
- package/dist/esm/hooks/useChannelConnections.d.ts +24 -0
- package/dist/esm/hooks/useChannelConnections.js +60 -0
- package/dist/esm/hooks/useChannelConnections.js.map +1 -0
- package/dist/esm/hooks/useChannelEndpoint.d.ts +20 -0
- package/dist/esm/hooks/useChannelEndpoint.js +83 -0
- package/dist/esm/hooks/useChannelEndpoint.js.map +1 -0
- package/dist/esm/hooks/useCounts.d.ts +18 -0
- package/dist/esm/hooks/useCounts.js +6 -2
- package/dist/esm/hooks/useCounts.js.map +1 -1
- package/dist/esm/hooks/useCreateChannelEndpoint.d.ts +17 -0
- package/dist/esm/hooks/useCreateChannelEndpoint.js +36 -0
- package/dist/esm/hooks/useCreateChannelEndpoint.js.map +1 -0
- package/dist/esm/hooks/useDeleteChannelEndpoint.d.ts +17 -0
- package/dist/esm/hooks/useDeleteChannelEndpoint.js +43 -0
- package/dist/esm/hooks/useDeleteChannelEndpoint.js.map +1 -0
- package/dist/esm/hooks/useNotifications.d.ts +18 -0
- package/dist/esm/hooks/useNotifications.js +5 -1
- package/dist/esm/hooks/useNotifications.js.map +1 -1
- package/dist/esm/index.d.ts +11 -2
- package/dist/esm/index.js +14 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/appearance.d.ts +2 -2
- package/dist/esm/utils/appearance.js.map +1 -1
- package/dist/esm/utils/types.d.ts +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/NovuProvider.tsx"],"sourcesContent":["import { Novu, NovuOptions } from '@novu/js';\nimport { buildSubscriber } from '@novu/js/internal';\nimport { createContext, ReactNode, useContext, useMemo } from 'react';\n\nexport type NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/NovuProvider.tsx"],"sourcesContent":["import { Novu, NovuOptions } from '@novu/js';\nimport { buildSubscriber } from '@novu/js/internal';\nimport { createContext, ReactNode, useContext, useMemo } from 'react';\n\nexport type NovuProviderProps = NovuOptions & {\n /**\n * When `false`, disables the WebSocket subscription that auto-injects\n * newly received notifications into the list and subscription that auto-resync\n * notification counts. Built-in mutations like\n * `readAll`, `seenAll`, `archiveAll`, and `archiveAllRead` continue to\n * update local state. Use this when you want to drive new-notification updates yourself (e.g.\n * via your own `novu.on('notifications.notification_received', ...)`\n * handler combined with `refetch()`). Defaults to `true`.\n */\n realtime?: boolean;\n children: ReactNode;\n};\n\nconst NovuContext = createContext<{ novu: Novu; realtime: boolean }>({ novu: undefined as any, realtime: true });\n\nexport const NovuProvider = (props: NovuProviderProps) => {\n const { subscriberId, realtime = true, ...propsWithoutSubscriberId } = props;\n const subscriberObj = useMemo(\n () => buildSubscriber({ subscriberId, subscriber: props.subscriber }),\n [subscriberId, props.subscriber]\n );\n const applicationIdentifier = propsWithoutSubscriberId.applicationIdentifier\n ? propsWithoutSubscriberId.applicationIdentifier\n : '';\n\n const providerProps: NovuProviderProps = {\n ...propsWithoutSubscriberId,\n applicationIdentifier,\n subscriber: subscriberObj,\n realtime,\n };\n\n return (\n <InternalNovuProvider {...providerProps} applicationIdentifier={applicationIdentifier}>\n {props.children}\n </InternalNovuProvider>\n );\n};\n\n/**\n * @internal Should be used internally not to be exposed outside of the library\n */\nexport const InternalNovuProvider = (props: NovuProviderProps) => {\n const applicationIdentifier = props.applicationIdentifier || '';\n const subscriberObj = useMemo(\n () => buildSubscriber({ subscriberId: props.subscriberId, subscriber: props.subscriber }),\n [props.subscriberId, props.subscriber]\n );\n\n const {\n children,\n subscriberHash,\n contextHash,\n backendUrl,\n apiUrl,\n socketUrl,\n socketOptions,\n useCache,\n defaultSchedule,\n context,\n realtime = true,\n } = props;\n\n const value = useMemo(\n () => ({\n novu: new Novu({\n applicationIdentifier,\n subscriberHash,\n contextHash,\n backendUrl,\n apiUrl,\n socketUrl,\n socketOptions,\n useCache,\n subscriber: subscriberObj,\n defaultSchedule,\n context,\n }),\n realtime,\n }),\n [\n applicationIdentifier,\n subscriberHash,\n subscriberObj,\n context,\n contextHash,\n backendUrl,\n apiUrl,\n socketUrl,\n socketOptions,\n useCache,\n realtime,\n ]\n );\n\n return <NovuContext.Provider value={value}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context.novu) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context.novu;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context.novu;\n};\n\nexport const useRealtime = () => {\n const context = useContext(NovuContext);\n\n return context.realtime;\n};\n"],"mappings":";AAAA,SAAS,YAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,eAA0B,YAAY,eAAe;AAoC1D;AApBJ,IAAM,cAAc,cAAiD,EAAE,MAAM,QAAkB,UAAU,KAAK,CAAC;AAExG,IAAM,eAAe,CAAC,UAA6B;AACxD,QAAM,EAAE,cAAc,WAAW,MAAM,GAAG,yBAAyB,IAAI;AACvE,QAAM,gBAAgB;AAAA,IACpB,MAAM,gBAAgB,EAAE,cAAc,YAAY,MAAM,WAAW,CAAC;AAAA,IACpE,CAAC,cAAc,MAAM,UAAU;AAAA,EACjC;AACA,QAAM,wBAAwB,yBAAyB,wBACnD,yBAAyB,wBACzB;AAEJ,QAAM,gBAAmC;AAAA,IACvC,GAAG;AAAA,IACH;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,EACF;AAEA,SACE,oBAAC,wBAAsB,GAAG,eAAe,uBACtC,gBAAM,UACT;AAEJ;AAKO,IAAM,uBAAuB,CAAC,UAA6B;AAChE,QAAM,wBAAwB,MAAM,yBAAyB;AAC7D,QAAM,gBAAgB;AAAA,IACpB,MAAM,gBAAgB,EAAE,cAAc,MAAM,cAAc,YAAY,MAAM,WAAW,CAAC;AAAA,IACxF,CAAC,MAAM,cAAc,MAAM,UAAU;AAAA,EACvC;AAEA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,IAAI;AAEJ,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL,MAAM,IAAI,KAAK;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;AAEO,IAAM,UAAU,MAAM;AAC3B,QAAM,UAAU,WAAW,WAAW;AACtC,MAAI,CAAC,QAAQ,MAAM;AACjB,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAEA,SAAO,QAAQ;AACjB;AAEO,IAAM,gBAAgB,MAAM;AACjC,QAAM,UAAU,WAAW,WAAW;AAEtC,SAAO,QAAQ;AACjB;AAEO,IAAM,cAAc,MAAM;AAC/B,QAAM,UAAU,WAAW,WAAW;AAEtC,SAAO,QAAQ;AACjB;","names":[]}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
export * from '@novu/js';
|
|
2
2
|
export { PreferenceLevel, SeverityLevelEnum, WorkflowCriticalityEnum } from '@novu/js';
|
|
3
3
|
export { NovuProvider, useNovu } from './NovuProvider.js';
|
|
4
|
+
export { UseChannelConnectionProps, UseChannelConnectionResult, useChannelConnection } from './useChannelConnection.js';
|
|
5
|
+
export { UseChannelConnectionsProps, UseChannelConnectionsResult, useChannelConnections } from './useChannelConnections.js';
|
|
6
|
+
export { UseChannelEndpointProps, UseChannelEndpointResult, useChannelEndpoint } from './useChannelEndpoint.js';
|
|
4
7
|
export { UseCountsProps, UseCountsResult, useCounts } from './useCounts.js';
|
|
8
|
+
export { UseCreateChannelEndpointProps, UseCreateChannelEndpointResult, useCreateChannelEndpoint } from './useCreateChannelEndpoint.js';
|
|
5
9
|
export { UseCreateSubscriptionProps, UseCreateSubscriptionResult, useCreateSubscription } from './useCreateSubscription.js';
|
|
10
|
+
export { UseDeleteChannelEndpointProps, UseDeleteChannelEndpointResult, useDeleteChannelEndpoint } from './useDeleteChannelEndpoint.js';
|
|
6
11
|
export { UseNotificationsProps, UseNotificationsResult, useNotifications } from './useNotifications.js';
|
|
7
12
|
export { UsePreferencesProps, UsePreferencesResult, usePreferences } from './usePreferences.js';
|
|
8
13
|
export { UseRemoveSubscriptionProps, UseRemoveSubscriptionResult, useRemoveSubscription } from './useRemoveSubscription.js';
|
package/dist/esm/hooks/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
// src/hooks/index.ts
|
|
2
2
|
import { PreferenceLevel, SeverityLevelEnum, WorkflowCriticalityEnum } from "@novu/js";
|
|
3
3
|
import { NovuProvider, useNovu } from "./NovuProvider.js";
|
|
4
|
+
export * from "./useChannelConnection.js";
|
|
5
|
+
export * from "./useChannelConnections.js";
|
|
6
|
+
export * from "./useChannelEndpoint.js";
|
|
4
7
|
export * from "./useCounts.js";
|
|
8
|
+
export * from "./useCreateChannelEndpoint.js";
|
|
5
9
|
export * from "./useCreateSubscription.js";
|
|
10
|
+
export * from "./useDeleteChannelEndpoint.js";
|
|
6
11
|
export * from "./useNotifications.js";
|
|
7
12
|
export * from "./usePreferences.js";
|
|
8
13
|
export * from "./useRemoveSubscription.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/index.ts"],"sourcesContent":["export type * from '@novu/js';\nexport { PreferenceLevel, SeverityLevelEnum, WorkflowCriticalityEnum } from '@novu/js';\nexport { NovuProvider, useNovu } from './NovuProvider';\nexport * from './useCounts';\nexport * from './useCreateSubscription';\nexport * from './useNotifications';\nexport * from './usePreferences';\nexport * from './useRemoveSubscription';\nexport * from './useSchedule';\nexport * from './useSubscription';\nexport * from './useSubscriptions';\nexport * from './useUpdateSubscription';\n"],"mappings":";AACA,SAAS,iBAAiB,mBAAmB,+BAA+B;AAC5E,SAAS,cAAc,eAAe;AACtC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/index.ts"],"sourcesContent":["export type * from '@novu/js';\nexport { PreferenceLevel, SeverityLevelEnum, WorkflowCriticalityEnum } from '@novu/js';\nexport { NovuProvider, useNovu } from './NovuProvider';\nexport * from './useChannelConnection';\nexport * from './useChannelConnections';\nexport * from './useChannelEndpoint';\nexport * from './useCounts';\nexport * from './useCreateChannelEndpoint';\nexport * from './useCreateSubscription';\nexport * from './useDeleteChannelEndpoint';\nexport * from './useNotifications';\nexport * from './usePreferences';\nexport * from './useRemoveSubscription';\nexport * from './useSchedule';\nexport * from './useSubscription';\nexport * from './useSubscriptions';\nexport * from './useUpdateSubscription';\n"],"mappings":";AACA,SAAS,iBAAiB,mBAAmB,+BAA+B;AAC5E,SAAS,cAAc,eAAe;AACtC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
declare const useBrowserTabsChannel: <T = unknown>({ channelName, onMessage, }: {
|
|
1
|
+
declare const useBrowserTabsChannel: <T = unknown>({ channelName, onMessage, enabled, }: {
|
|
2
2
|
channelName: string;
|
|
3
3
|
onMessage: (args: T) => void;
|
|
4
|
+
enabled?: boolean;
|
|
4
5
|
}) => {
|
|
5
6
|
postMessage: (data: T) => void;
|
|
6
7
|
};
|
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
var useBrowserTabsChannel = ({
|
|
4
4
|
channelName,
|
|
5
|
-
onMessage
|
|
5
|
+
onMessage,
|
|
6
|
+
enabled = true
|
|
6
7
|
}) => {
|
|
7
8
|
const [tabsChannel] = useState(
|
|
8
9
|
typeof BroadcastChannel !== "undefined" ? new BroadcastChannel(channelName) : void 0
|
|
9
10
|
);
|
|
10
11
|
const postMessage = (data) => {
|
|
12
|
+
if (!enabled) return;
|
|
11
13
|
tabsChannel?.postMessage(data);
|
|
12
14
|
};
|
|
13
15
|
useEffect(() => {
|
|
16
|
+
if (!enabled) return;
|
|
14
17
|
const listener = (event) => {
|
|
15
18
|
onMessage(event.data);
|
|
16
19
|
};
|
|
@@ -18,7 +21,7 @@ var useBrowserTabsChannel = ({
|
|
|
18
21
|
return () => {
|
|
19
22
|
tabsChannel?.removeEventListener("message", listener);
|
|
20
23
|
};
|
|
21
|
-
}, []);
|
|
24
|
+
}, [enabled]);
|
|
22
25
|
return { postMessage };
|
|
23
26
|
};
|
|
24
27
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nexport const useBrowserTabsChannel = <T = unknown>({\n channelName,\n onMessage,\n}: {\n channelName: string;\n onMessage: (args: T) => void;\n}) => {\n const [tabsChannel] = useState(\n typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(channelName) : undefined\n );\n\n const postMessage = (data: T) => {\n tabsChannel?.postMessage(data);\n };\n\n useEffect(() => {\n const listener = (event: MessageEvent<T>) => {\n onMessage(event.data);\n };\n\n tabsChannel?.addEventListener('message', listener);\n\n return () => {\n tabsChannel?.removeEventListener('message', listener);\n };\n }, []);\n\n return { postMessage };\n};\n"],"mappings":";AAAA,SAAS,WAAW,gBAAgB;AAE7B,IAAM,wBAAwB,CAAc;AAAA,EACjD;AAAA,EACA;
|
|
1
|
+
{"version":3,"sources":["../../../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nexport const useBrowserTabsChannel = <T = unknown>({\n channelName,\n onMessage,\n enabled = true,\n}: {\n channelName: string;\n onMessage: (args: T) => void;\n enabled?: boolean;\n}) => {\n const [tabsChannel] = useState(\n typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(channelName) : undefined\n );\n\n const postMessage = (data: T) => {\n if (!enabled) return;\n tabsChannel?.postMessage(data);\n };\n\n useEffect(() => {\n if (!enabled) return;\n\n const listener = (event: MessageEvent<T>) => {\n onMessage(event.data);\n };\n\n tabsChannel?.addEventListener('message', listener);\n\n return () => {\n tabsChannel?.removeEventListener('message', listener);\n };\n }, [enabled]);\n\n return { postMessage };\n};\n"],"mappings":";AAAA,SAAS,WAAW,gBAAgB;AAE7B,IAAM,wBAAwB,CAAc;AAAA,EACjD;AAAA,EACA;AAAA,EACA,UAAU;AACZ,MAIM;AACJ,QAAM,CAAC,WAAW,IAAI;AAAA,IACpB,OAAO,qBAAqB,cAAc,IAAI,iBAAiB,WAAW,IAAI;AAAA,EAChF;AAEA,QAAM,cAAc,CAAC,SAAY;AAC/B,QAAI,CAAC,QAAS;AACd,iBAAa,YAAY,IAAI;AAAA,EAC/B;AAEA,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,CAAC,UAA2B;AAC3C,gBAAU,MAAM,IAAI;AAAA,IACtB;AAEA,iBAAa,iBAAiB,WAAW,QAAQ;AAEjD,WAAO,MAAM;AACX,mBAAa,oBAAoB,WAAW,QAAQ;AAAA,IACtD;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO,EAAE,YAAY;AACvB;","names":[]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { SocketEventNames, Events } from '@novu/js';
|
|
2
2
|
|
|
3
|
-
declare const useWebSocketEvent: <E extends SocketEventNames>({ event: webSocketEvent, eventHandler: onMessage, }: {
|
|
3
|
+
declare const useWebSocketEvent: <E extends SocketEventNames>({ event: webSocketEvent, eventHandler: onMessage, enabled, }: {
|
|
4
4
|
event: E;
|
|
5
5
|
eventHandler: (args: Events[E]) => void;
|
|
6
|
+
enabled?: boolean;
|
|
6
7
|
}) => void;
|
|
7
8
|
|
|
8
9
|
export { useWebSocketEvent };
|
|
@@ -5,19 +5,22 @@ import { useNovu } from "../NovuProvider.js";
|
|
|
5
5
|
import { useBrowserTabsChannel } from "./useBrowserTabsChannel.js";
|
|
6
6
|
var useWebSocketEvent = ({
|
|
7
7
|
event: webSocketEvent,
|
|
8
|
-
eventHandler: onMessage
|
|
8
|
+
eventHandler: onMessage,
|
|
9
|
+
enabled = true
|
|
9
10
|
}) => {
|
|
10
11
|
const novu = useNovu();
|
|
11
12
|
const channelName = `nv_ws_connection:a=${novu.applicationIdentifier}:s=${novu.subscriberId}:c=${novu.contextKey}:e=${webSocketEvent}`;
|
|
12
13
|
const { postMessage } = useBrowserTabsChannel({
|
|
13
14
|
channelName,
|
|
14
|
-
onMessage
|
|
15
|
+
onMessage,
|
|
16
|
+
enabled
|
|
15
17
|
});
|
|
16
18
|
const updateReadCount = (data) => {
|
|
17
19
|
onMessage(data);
|
|
18
20
|
postMessage(data);
|
|
19
21
|
};
|
|
20
22
|
useEffect(() => {
|
|
23
|
+
if (!enabled) return;
|
|
21
24
|
let cleanup;
|
|
22
25
|
const resolveLock = requestLock(channelName, () => {
|
|
23
26
|
cleanup = novu.on(webSocketEvent, updateReadCount);
|
|
@@ -28,7 +31,7 @@ var useWebSocketEvent = ({
|
|
|
28
31
|
}
|
|
29
32
|
resolveLock();
|
|
30
33
|
};
|
|
31
|
-
}, []);
|
|
34
|
+
}, [enabled]);
|
|
32
35
|
};
|
|
33
36
|
export {
|
|
34
37
|
useWebSocketEvent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/hooks/internal/useWebsocketEvent.ts"],"sourcesContent":["import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { requestLock } from '../../utils/requestLock';\nimport { useNovu } from '../NovuProvider';\nimport { useBrowserTabsChannel } from './useBrowserTabsChannel';\n\nexport const useWebSocketEvent = <E extends SocketEventNames>({\n event: webSocketEvent,\n eventHandler: onMessage,\n}: {\n event: E;\n eventHandler: (args: Events[E]) => void;\n}) => {\n const novu = useNovu();\n const channelName = `nv_ws_connection:a=${novu.applicationIdentifier}:s=${novu.subscriberId}:c=${novu.contextKey}:e=${webSocketEvent}`;\n\n const { postMessage } = useBrowserTabsChannel({\n channelName,\n onMessage,\n });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n let cleanup: () => void;\n const resolveLock = requestLock(channelName, () => {\n cleanup = novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n if (cleanup) {\n cleanup();\n }\n\n resolveLock();\n };\n }, []);\n};\n"],"mappings":";AACA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AACxB,SAAS,6BAA6B;AAE/B,IAAM,oBAAoB,CAA6B;AAAA,EAC5D,OAAO;AAAA,EACP,cAAc;
|
|
1
|
+
{"version":3,"sources":["../../../../src/hooks/internal/useWebsocketEvent.ts"],"sourcesContent":["import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { requestLock } from '../../utils/requestLock';\nimport { useNovu } from '../NovuProvider';\nimport { useBrowserTabsChannel } from './useBrowserTabsChannel';\n\nexport const useWebSocketEvent = <E extends SocketEventNames>({\n event: webSocketEvent,\n eventHandler: onMessage,\n enabled = true,\n}: {\n event: E;\n eventHandler: (args: Events[E]) => void;\n enabled?: boolean;\n}) => {\n const novu = useNovu();\n const channelName = `nv_ws_connection:a=${novu.applicationIdentifier}:s=${novu.subscriberId}:c=${novu.contextKey}:e=${webSocketEvent}`;\n\n const { postMessage } = useBrowserTabsChannel({\n channelName,\n onMessage,\n enabled,\n });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n if (!enabled) return;\n\n let cleanup: () => void;\n const resolveLock = requestLock(channelName, () => {\n cleanup = novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n if (cleanup) {\n cleanup();\n }\n\n resolveLock();\n };\n }, [enabled]);\n};\n"],"mappings":";AACA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AACxB,SAAS,6BAA6B;AAE/B,IAAM,oBAAoB,CAA6B;AAAA,EAC5D,OAAO;AAAA,EACP,cAAc;AAAA,EACd,UAAU;AACZ,MAIM;AACJ,QAAM,OAAO,QAAQ;AACrB,QAAM,cAAc,sBAAsB,KAAK,qBAAqB,MAAM,KAAK,YAAY,MAAM,KAAK,UAAU,MAAM,cAAc;AAEpI,QAAM,EAAE,YAAY,IAAI,sBAAsB;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,kBAA2C,CAAC,SAAS;AACzD,cAAU,IAAI;AACd,gBAAY,IAAI;AAAA,EAClB;AAEA,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,QAAI;AACJ,UAAM,cAAc,YAAY,aAAa,MAAM;AACjD,gBAAU,KAAK,GAAG,gBAAgB,eAAe;AAAA,IACnD,CAAC;AAED,WAAO,MAAM;AACX,UAAI,SAAS;AACX,gBAAQ;AAAA,MACV;AAEA,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AACd;","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ChannelConnectionResponse, NovuError } from '@novu/js';
|
|
2
|
+
|
|
3
|
+
type UseChannelConnectionProps = {
|
|
4
|
+
identifier: string;
|
|
5
|
+
onSuccess?: (data: ChannelConnectionResponse | null) => void;
|
|
6
|
+
onError?: (error: NovuError) => void;
|
|
7
|
+
};
|
|
8
|
+
type UseChannelConnectionResult = {
|
|
9
|
+
connection?: ChannelConnectionResponse | null;
|
|
10
|
+
error?: NovuError;
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
isFetching: boolean;
|
|
13
|
+
refetch: () => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Get a channel connection by identifier.
|
|
17
|
+
*/
|
|
18
|
+
declare const useChannelConnection: (props: UseChannelConnectionProps) => UseChannelConnectionResult;
|
|
19
|
+
|
|
20
|
+
export { type UseChannelConnectionProps, type UseChannelConnectionResult, useChannelConnection };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/hooks/useChannelConnection.ts
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useNovu } from "./NovuProvider.js";
|
|
4
|
+
var useChannelConnection = (props) => {
|
|
5
|
+
const novu = useNovu();
|
|
6
|
+
const propsRef = useRef(props);
|
|
7
|
+
propsRef.current = props;
|
|
8
|
+
const [connection, setConnection] = useState();
|
|
9
|
+
const [error, setError] = useState();
|
|
10
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
11
|
+
const [isFetching, setIsFetching] = useState(false);
|
|
12
|
+
const fetchConnection = useCallback(
|
|
13
|
+
async (options) => {
|
|
14
|
+
const { identifier, onSuccess, onError } = propsRef.current;
|
|
15
|
+
if (options?.refetch) {
|
|
16
|
+
setError(void 0);
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
}
|
|
19
|
+
setIsFetching(true);
|
|
20
|
+
const response = await novu.channelConnections.get({ identifier });
|
|
21
|
+
if (response.error) {
|
|
22
|
+
setError(response.error);
|
|
23
|
+
onError?.(response.error);
|
|
24
|
+
} else if (response.data !== void 0) {
|
|
25
|
+
onSuccess?.(response.data);
|
|
26
|
+
setConnection(response.data);
|
|
27
|
+
}
|
|
28
|
+
setIsLoading(false);
|
|
29
|
+
setIsFetching(false);
|
|
30
|
+
},
|
|
31
|
+
[novu]
|
|
32
|
+
);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const cleanupGetPending = novu.on("channel-connection.get.pending", ({ args }) => {
|
|
35
|
+
if (!args || args.identifier !== propsRef.current.identifier) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
setIsFetching(true);
|
|
39
|
+
});
|
|
40
|
+
const cleanupGetResolved = novu.on("channel-connection.get.resolved", ({ args, data, error: resolvedError }) => {
|
|
41
|
+
if (!args || args.identifier !== propsRef.current.identifier) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const { onSuccess, onError } = propsRef.current;
|
|
45
|
+
if (resolvedError) {
|
|
46
|
+
setError(resolvedError);
|
|
47
|
+
onError?.(resolvedError);
|
|
48
|
+
} else {
|
|
49
|
+
setConnection(data ?? null);
|
|
50
|
+
onSuccess?.(data ?? null);
|
|
51
|
+
}
|
|
52
|
+
setIsFetching(false);
|
|
53
|
+
});
|
|
54
|
+
const cleanupDeleteResolved = novu.on("channel-connection.delete.resolved", ({ args }) => {
|
|
55
|
+
if (!args || args.identifier !== propsRef.current.identifier) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
setConnection(null);
|
|
59
|
+
propsRef.current.onSuccess?.(null);
|
|
60
|
+
setIsFetching(false);
|
|
61
|
+
});
|
|
62
|
+
void fetchConnection({ refetch: true });
|
|
63
|
+
return () => {
|
|
64
|
+
cleanupGetPending();
|
|
65
|
+
cleanupGetResolved();
|
|
66
|
+
cleanupDeleteResolved();
|
|
67
|
+
};
|
|
68
|
+
}, [novu, fetchConnection, props.identifier]);
|
|
69
|
+
const refetch = useCallback(() => fetchConnection({ refetch: true }), [fetchConnection]);
|
|
70
|
+
return {
|
|
71
|
+
connection,
|
|
72
|
+
error,
|
|
73
|
+
isLoading,
|
|
74
|
+
isFetching,
|
|
75
|
+
refetch
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
export {
|
|
79
|
+
useChannelConnection
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=useChannelConnection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/useChannelConnection.ts"],"sourcesContent":["import type { ChannelConnectionResponse, NovuError } from '@novu/js';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\nexport type UseChannelConnectionProps = {\n identifier: string;\n onSuccess?: (data: ChannelConnectionResponse | null) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport type UseChannelConnectionResult = {\n connection?: ChannelConnectionResponse | null;\n error?: NovuError;\n isLoading: boolean;\n isFetching: boolean;\n refetch: () => Promise<void>;\n};\n\n/**\n * Get a channel connection by identifier.\n */\nexport const useChannelConnection = (props: UseChannelConnectionProps): UseChannelConnectionResult => {\n const novu = useNovu();\n const propsRef = useRef<UseChannelConnectionProps>(props);\n propsRef.current = props;\n\n const [connection, setConnection] = useState<ChannelConnectionResponse | null>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const fetchConnection = useCallback(\n async (options?: { refetch: boolean }) => {\n const { identifier, onSuccess, onError } = propsRef.current;\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n }\n\n setIsFetching(true);\n\n const response = await novu.channelConnections.get({ identifier });\n\n if (response.error) {\n setError(response.error as NovuError);\n onError?.(response.error as NovuError);\n } else if (response.data !== undefined) {\n onSuccess?.(response.data);\n setConnection(response.data);\n }\n setIsLoading(false);\n setIsFetching(false);\n },\n [novu]\n );\n\n // props.identifier triggers a re-fetch and re-registration whenever the\n // caller switches to a different identifier; fetchConnection reads it from\n // propsRef at call-time so it doesn't appear in the callback body directly.\n // biome-ignore lint/correctness/useExhaustiveDependencies: props.identifier is an intentional trigger dependency\n useEffect(() => {\n const cleanupGetPending = novu.on('channel-connection.get.pending', ({ args }) => {\n if (!args || args.identifier !== propsRef.current.identifier) {\n return;\n }\n setIsFetching(true);\n });\n\n const cleanupGetResolved = novu.on('channel-connection.get.resolved', ({ args, data, error: resolvedError }) => {\n if (!args || args.identifier !== propsRef.current.identifier) {\n return;\n }\n const { onSuccess, onError } = propsRef.current;\n if (resolvedError) {\n setError(resolvedError as NovuError);\n onError?.(resolvedError as NovuError);\n } else {\n setConnection((data as ChannelConnectionResponse) ?? null);\n onSuccess?.((data as ChannelConnectionResponse) ?? null);\n }\n setIsFetching(false);\n });\n\n const cleanupDeleteResolved = novu.on('channel-connection.delete.resolved', ({ args }) => {\n if (!args || args.identifier !== propsRef.current.identifier) {\n return;\n }\n setConnection(null);\n propsRef.current.onSuccess?.(null);\n setIsFetching(false);\n });\n\n void fetchConnection({ refetch: true });\n\n return () => {\n cleanupGetPending();\n cleanupGetResolved();\n cleanupDeleteResolved();\n };\n }, [novu, fetchConnection, props.identifier]);\n\n const refetch = useCallback(() => fetchConnection({ refetch: true }), [fetchConnection]);\n\n return {\n connection,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n"],"mappings":";AACA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AACzD,SAAS,eAAe;AAmBjB,IAAM,uBAAuB,CAAC,UAAiE;AACpG,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,OAAkC,KAAK;AACxD,WAAS,UAAU;AAEnB,QAAM,CAAC,YAAY,aAAa,IAAI,SAA2C;AAC/E,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoB;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAElD,QAAM,kBAAkB;AAAA,IACtB,OAAO,YAAmC;AACxC,YAAM,EAAE,YAAY,WAAW,QAAQ,IAAI,SAAS;AACpD,UAAI,SAAS,SAAS;AACpB,iBAAS,MAAS;AAClB,qBAAa,IAAI;AAAA,MACnB;AAEA,oBAAc,IAAI;AAElB,YAAM,WAAW,MAAM,KAAK,mBAAmB,IAAI,EAAE,WAAW,CAAC;AAEjE,UAAI,SAAS,OAAO;AAClB,iBAAS,SAAS,KAAkB;AACpC,kBAAU,SAAS,KAAkB;AAAA,MACvC,WAAW,SAAS,SAAS,QAAW;AACtC,oBAAY,SAAS,IAAI;AACzB,sBAAc,SAAS,IAAI;AAAA,MAC7B;AACA,mBAAa,KAAK;AAClB,oBAAc,KAAK;AAAA,IACrB;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAMA,YAAU,MAAM;AACd,UAAM,oBAAoB,KAAK,GAAG,kCAAkC,CAAC,EAAE,KAAK,MAAM;AAChF,UAAI,CAAC,QAAQ,KAAK,eAAe,SAAS,QAAQ,YAAY;AAC5D;AAAA,MACF;AACA,oBAAc,IAAI;AAAA,IACpB,CAAC;AAED,UAAM,qBAAqB,KAAK,GAAG,mCAAmC,CAAC,EAAE,MAAM,MAAM,OAAO,cAAc,MAAM;AAC9G,UAAI,CAAC,QAAQ,KAAK,eAAe,SAAS,QAAQ,YAAY;AAC5D;AAAA,MACF;AACA,YAAM,EAAE,WAAW,QAAQ,IAAI,SAAS;AACxC,UAAI,eAAe;AACjB,iBAAS,aAA0B;AACnC,kBAAU,aAA0B;AAAA,MACtC,OAAO;AACL,sBAAe,QAAsC,IAAI;AACzD,oBAAa,QAAsC,IAAI;AAAA,MACzD;AACA,oBAAc,KAAK;AAAA,IACrB,CAAC;AAED,UAAM,wBAAwB,KAAK,GAAG,sCAAsC,CAAC,EAAE,KAAK,MAAM;AACxF,UAAI,CAAC,QAAQ,KAAK,eAAe,SAAS,QAAQ,YAAY;AAC5D;AAAA,MACF;AACA,oBAAc,IAAI;AAClB,eAAS,QAAQ,YAAY,IAAI;AACjC,oBAAc,KAAK;AAAA,IACrB,CAAC;AAED,SAAK,gBAAgB,EAAE,SAAS,KAAK,CAAC;AAEtC,WAAO,MAAM;AACX,wBAAkB;AAClB,yBAAmB;AACnB,4BAAsB;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,MAAM,iBAAiB,MAAM,UAAU,CAAC;AAE5C,QAAM,UAAU,YAAY,MAAM,gBAAgB,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC;AAEvF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ListChannelConnectionsArgs, ChannelConnectionResponse, NovuError } from '@novu/js';
|
|
2
|
+
|
|
3
|
+
type UseChannelConnectionsProps = ListChannelConnectionsArgs & {
|
|
4
|
+
onSuccess?: (data: ChannelConnectionResponse[]) => void;
|
|
5
|
+
onError?: (error: NovuError) => void;
|
|
6
|
+
};
|
|
7
|
+
type UseChannelConnectionsResult = {
|
|
8
|
+
connections: ChannelConnectionResponse[];
|
|
9
|
+
error?: NovuError;
|
|
10
|
+
isLoading: boolean;
|
|
11
|
+
isFetching: boolean;
|
|
12
|
+
refetch: () => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* List channel connections for the current subscriber. Use this to discover an active
|
|
16
|
+
* connection identifier after a chat OAuth flow so it can be passed to `LinkUser`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const { connections } = useChannelConnections({ integrationIdentifier: 'my-chat-integration' });
|
|
20
|
+
* const connectionIdentifier = connections[0]?.identifier;
|
|
21
|
+
*/
|
|
22
|
+
declare const useChannelConnections: (props?: UseChannelConnectionsProps) => UseChannelConnectionsResult;
|
|
23
|
+
|
|
24
|
+
export { type UseChannelConnectionsProps, type UseChannelConnectionsResult, useChannelConnections };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/hooks/useChannelConnections.ts
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useNovu } from "./NovuProvider.js";
|
|
4
|
+
var useChannelConnections = (props = {}) => {
|
|
5
|
+
const novu = useNovu();
|
|
6
|
+
const propsRef = useRef(props);
|
|
7
|
+
propsRef.current = props;
|
|
8
|
+
const [connections, setConnections] = useState([]);
|
|
9
|
+
const [error, setError] = useState();
|
|
10
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
11
|
+
const [isFetching, setIsFetching] = useState(false);
|
|
12
|
+
const fetchConnections = useCallback(
|
|
13
|
+
async (options) => {
|
|
14
|
+
const { onSuccess, onError, ...listArgs } = propsRef.current;
|
|
15
|
+
if (options?.refetch) {
|
|
16
|
+
setError(void 0);
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
}
|
|
19
|
+
setIsFetching(true);
|
|
20
|
+
try {
|
|
21
|
+
const response = await novu.channelConnections.list(listArgs);
|
|
22
|
+
if (response.error) {
|
|
23
|
+
setError(response.error);
|
|
24
|
+
onError?.(response.error);
|
|
25
|
+
} else if (response.data !== void 0) {
|
|
26
|
+
setConnections(response.data);
|
|
27
|
+
onSuccess?.(response.data);
|
|
28
|
+
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
setError(err);
|
|
31
|
+
onError?.(err);
|
|
32
|
+
} finally {
|
|
33
|
+
setIsLoading(false);
|
|
34
|
+
setIsFetching(false);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
[novu]
|
|
38
|
+
);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const cleanupDeleteResolved = novu.on("channel-connection.delete.resolved", () => {
|
|
41
|
+
void fetchConnections({ refetch: true });
|
|
42
|
+
});
|
|
43
|
+
void fetchConnections({ refetch: true });
|
|
44
|
+
return () => {
|
|
45
|
+
cleanupDeleteResolved();
|
|
46
|
+
};
|
|
47
|
+
}, [novu, fetchConnections]);
|
|
48
|
+
const refetch = useCallback(() => fetchConnections({ refetch: true }), [fetchConnections]);
|
|
49
|
+
return {
|
|
50
|
+
connections,
|
|
51
|
+
error,
|
|
52
|
+
isLoading,
|
|
53
|
+
isFetching,
|
|
54
|
+
refetch
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
export {
|
|
58
|
+
useChannelConnections
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=useChannelConnections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/useChannelConnections.ts"],"sourcesContent":["import type { ChannelConnectionResponse, ListChannelConnectionsArgs, NovuError } from '@novu/js';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\nexport type UseChannelConnectionsProps = ListChannelConnectionsArgs & {\n onSuccess?: (data: ChannelConnectionResponse[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport type UseChannelConnectionsResult = {\n connections: ChannelConnectionResponse[];\n error?: NovuError;\n isLoading: boolean;\n isFetching: boolean;\n refetch: () => Promise<void>;\n};\n\n/**\n * List channel connections for the current subscriber. Use this to discover an active\n * connection identifier after a chat OAuth flow so it can be passed to `LinkUser`.\n *\n * @example\n * const { connections } = useChannelConnections({ integrationIdentifier: 'my-chat-integration' });\n * const connectionIdentifier = connections[0]?.identifier;\n */\nexport const useChannelConnections = (props: UseChannelConnectionsProps = {}): UseChannelConnectionsResult => {\n const novu = useNovu();\n const propsRef = useRef<UseChannelConnectionsProps>(props);\n propsRef.current = props;\n\n const [connections, setConnections] = useState<ChannelConnectionResponse[]>([]);\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const fetchConnections = useCallback(\n async (options?: { refetch: boolean }) => {\n const { onSuccess, onError, ...listArgs } = propsRef.current;\n\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n }\n\n setIsFetching(true);\n\n try {\n const response = await novu.channelConnections.list(listArgs);\n\n if (response.error) {\n setError(response.error as NovuError);\n onError?.(response.error as NovuError);\n } else if (response.data !== undefined) {\n setConnections(response.data);\n onSuccess?.(response.data);\n }\n } catch (err) {\n setError(err as NovuError);\n onError?.(err as NovuError);\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n },\n [novu]\n );\n\n useEffect(() => {\n const cleanupDeleteResolved = novu.on('channel-connection.delete.resolved', () => {\n void fetchConnections({ refetch: true });\n });\n\n void fetchConnections({ refetch: true });\n\n return () => {\n cleanupDeleteResolved();\n };\n }, [novu, fetchConnections]);\n\n const refetch = useCallback(() => fetchConnections({ refetch: true }), [fetchConnections]);\n\n return {\n connections,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n"],"mappings":";AACA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AACzD,SAAS,eAAe;AAuBjB,IAAM,wBAAwB,CAAC,QAAoC,CAAC,MAAmC;AAC5G,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,OAAmC,KAAK;AACzD,WAAS,UAAU;AAEnB,QAAM,CAAC,aAAa,cAAc,IAAI,SAAsC,CAAC,CAAC;AAC9E,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoB;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAElD,QAAM,mBAAmB;AAAA,IACvB,OAAO,YAAmC;AACxC,YAAM,EAAE,WAAW,SAAS,GAAG,SAAS,IAAI,SAAS;AAErD,UAAI,SAAS,SAAS;AACpB,iBAAS,MAAS;AAClB,qBAAa,IAAI;AAAA,MACnB;AAEA,oBAAc,IAAI;AAElB,UAAI;AACF,cAAM,WAAW,MAAM,KAAK,mBAAmB,KAAK,QAAQ;AAE5D,YAAI,SAAS,OAAO;AAClB,mBAAS,SAAS,KAAkB;AACpC,oBAAU,SAAS,KAAkB;AAAA,QACvC,WAAW,SAAS,SAAS,QAAW;AACtC,yBAAe,SAAS,IAAI;AAC5B,sBAAY,SAAS,IAAI;AAAA,QAC3B;AAAA,MACF,SAAS,KAAK;AACZ,iBAAS,GAAgB;AACzB,kBAAU,GAAgB;AAAA,MAC5B,UAAE;AACA,qBAAa,KAAK;AAClB,sBAAc,KAAK;AAAA,MACrB;AAAA,IACF;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAEA,YAAU,MAAM;AACd,UAAM,wBAAwB,KAAK,GAAG,sCAAsC,MAAM;AAChF,WAAK,iBAAiB,EAAE,SAAS,KAAK,CAAC;AAAA,IACzC,CAAC;AAED,SAAK,iBAAiB,EAAE,SAAS,KAAK,CAAC;AAEvC,WAAO,MAAM;AACX,4BAAsB;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,MAAM,gBAAgB,CAAC;AAE3B,QAAM,UAAU,YAAY,MAAM,iBAAiB,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAEzF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ChannelEndpointResponse, NovuError } from '@novu/js';
|
|
2
|
+
|
|
3
|
+
type UseChannelEndpointProps = {
|
|
4
|
+
identifier: string;
|
|
5
|
+
onSuccess?: (data: ChannelEndpointResponse | null) => void;
|
|
6
|
+
onError?: (error: NovuError) => void;
|
|
7
|
+
};
|
|
8
|
+
type UseChannelEndpointResult = {
|
|
9
|
+
endpoint?: ChannelEndpointResponse | null;
|
|
10
|
+
error?: NovuError;
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
isFetching: boolean;
|
|
13
|
+
refetch: () => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Get a channel endpoint by identifier.
|
|
17
|
+
*/
|
|
18
|
+
declare const useChannelEndpoint: (props: UseChannelEndpointProps) => UseChannelEndpointResult;
|
|
19
|
+
|
|
20
|
+
export { type UseChannelEndpointProps, type UseChannelEndpointResult, useChannelEndpoint };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// src/hooks/useChannelEndpoint.ts
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useNovu } from "./NovuProvider.js";
|
|
4
|
+
var useChannelEndpoint = (props) => {
|
|
5
|
+
const novu = useNovu();
|
|
6
|
+
const propsRef = useRef(props);
|
|
7
|
+
propsRef.current = props;
|
|
8
|
+
const [endpoint, setEndpoint] = useState();
|
|
9
|
+
const [error, setError] = useState();
|
|
10
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
11
|
+
const [isFetching, setIsFetching] = useState(false);
|
|
12
|
+
const fetchEndpoint = useCallback(
|
|
13
|
+
async (options) => {
|
|
14
|
+
const { identifier, onSuccess, onError } = propsRef.current;
|
|
15
|
+
if (options?.refetch) {
|
|
16
|
+
setError(void 0);
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
}
|
|
19
|
+
setIsFetching(true);
|
|
20
|
+
const response = await novu.channelEndpoints.get({ identifier });
|
|
21
|
+
if (response.error) {
|
|
22
|
+
setError(response.error);
|
|
23
|
+
onError?.(response.error);
|
|
24
|
+
} else if (response.data !== void 0) {
|
|
25
|
+
onSuccess?.(response.data);
|
|
26
|
+
setEndpoint(response.data);
|
|
27
|
+
}
|
|
28
|
+
setIsLoading(false);
|
|
29
|
+
setIsFetching(false);
|
|
30
|
+
},
|
|
31
|
+
[novu]
|
|
32
|
+
);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const cleanupGetPending = novu.on("channel-endpoint.get.pending", () => {
|
|
35
|
+
setIsFetching(true);
|
|
36
|
+
});
|
|
37
|
+
const cleanupGetResolved = novu.on("channel-endpoint.get.resolved", ({ data, error: resolvedError }) => {
|
|
38
|
+
const { onSuccess, onError } = propsRef.current;
|
|
39
|
+
if (resolvedError) {
|
|
40
|
+
setError(resolvedError);
|
|
41
|
+
onError?.(resolvedError);
|
|
42
|
+
} else {
|
|
43
|
+
setEndpoint(data ?? null);
|
|
44
|
+
onSuccess?.(data ?? null);
|
|
45
|
+
}
|
|
46
|
+
setIsFetching(false);
|
|
47
|
+
});
|
|
48
|
+
const cleanupCreateResolved = novu.on("channel-endpoint.create.resolved", ({ data }) => {
|
|
49
|
+
if (data) {
|
|
50
|
+
setEndpoint(data);
|
|
51
|
+
propsRef.current.onSuccess?.(data);
|
|
52
|
+
}
|
|
53
|
+
setIsFetching(false);
|
|
54
|
+
});
|
|
55
|
+
const cleanupDeleteResolved = novu.on("channel-endpoint.delete.resolved", ({ args }) => {
|
|
56
|
+
if (!args || args.identifier !== propsRef.current.identifier) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
setEndpoint(null);
|
|
60
|
+
propsRef.current.onSuccess?.(null);
|
|
61
|
+
setIsFetching(false);
|
|
62
|
+
});
|
|
63
|
+
void fetchEndpoint({ refetch: true });
|
|
64
|
+
return () => {
|
|
65
|
+
cleanupGetPending();
|
|
66
|
+
cleanupGetResolved();
|
|
67
|
+
cleanupCreateResolved();
|
|
68
|
+
cleanupDeleteResolved();
|
|
69
|
+
};
|
|
70
|
+
}, [novu, fetchEndpoint, props.identifier]);
|
|
71
|
+
const refetch = useCallback(() => fetchEndpoint({ refetch: true }), [fetchEndpoint]);
|
|
72
|
+
return {
|
|
73
|
+
endpoint,
|
|
74
|
+
error,
|
|
75
|
+
isLoading,
|
|
76
|
+
isFetching,
|
|
77
|
+
refetch
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
export {
|
|
81
|
+
useChannelEndpoint
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=useChannelEndpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/useChannelEndpoint.ts"],"sourcesContent":["import type { ChannelEndpointResponse, NovuError } from '@novu/js';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\nexport type UseChannelEndpointProps = {\n identifier: string;\n onSuccess?: (data: ChannelEndpointResponse | null) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport type UseChannelEndpointResult = {\n endpoint?: ChannelEndpointResponse | null;\n error?: NovuError;\n isLoading: boolean;\n isFetching: boolean;\n refetch: () => Promise<void>;\n};\n\n/**\n * Get a channel endpoint by identifier.\n */\nexport const useChannelEndpoint = (props: UseChannelEndpointProps): UseChannelEndpointResult => {\n const novu = useNovu();\n const propsRef = useRef<UseChannelEndpointProps>(props);\n propsRef.current = props;\n\n const [endpoint, setEndpoint] = useState<ChannelEndpointResponse | null>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const fetchEndpoint = useCallback(\n async (options?: { refetch: boolean }) => {\n const { identifier, onSuccess, onError } = propsRef.current;\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n }\n\n setIsFetching(true);\n\n const response = await novu.channelEndpoints.get({ identifier });\n\n if (response.error) {\n setError(response.error as NovuError);\n onError?.(response.error as NovuError);\n } else if (response.data !== undefined) {\n onSuccess?.(response.data);\n setEndpoint(response.data);\n }\n setIsLoading(false);\n setIsFetching(false);\n },\n [novu]\n );\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: props.identifier is needed to re-run the effect and initial fetch when the identifier changes\n useEffect(() => {\n const cleanupGetPending = novu.on('channel-endpoint.get.pending', () => {\n setIsFetching(true);\n });\n\n const cleanupGetResolved = novu.on('channel-endpoint.get.resolved', ({ data, error: resolvedError }) => {\n const { onSuccess, onError } = propsRef.current;\n if (resolvedError) {\n setError(resolvedError as NovuError);\n onError?.(resolvedError as NovuError);\n } else {\n setEndpoint((data as ChannelEndpointResponse) ?? null);\n onSuccess?.((data as ChannelEndpointResponse) ?? null);\n }\n setIsFetching(false);\n });\n\n const cleanupCreateResolved = novu.on('channel-endpoint.create.resolved', ({ data }) => {\n if (data) {\n setEndpoint(data as ChannelEndpointResponse);\n propsRef.current.onSuccess?.(data as ChannelEndpointResponse);\n }\n setIsFetching(false);\n });\n\n const cleanupDeleteResolved = novu.on('channel-endpoint.delete.resolved', ({ args }) => {\n if (!args || args.identifier !== propsRef.current.identifier) {\n return;\n }\n setEndpoint(null);\n propsRef.current.onSuccess?.(null);\n setIsFetching(false);\n });\n\n void fetchEndpoint({ refetch: true });\n\n return () => {\n cleanupGetPending();\n cleanupGetResolved();\n cleanupCreateResolved();\n cleanupDeleteResolved();\n };\n }, [novu, fetchEndpoint, props.identifier]);\n\n const refetch = useCallback(() => fetchEndpoint({ refetch: true }), [fetchEndpoint]);\n\n return {\n endpoint,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n"],"mappings":";AACA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AACzD,SAAS,eAAe;AAmBjB,IAAM,qBAAqB,CAAC,UAA6D;AAC9F,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,OAAgC,KAAK;AACtD,WAAS,UAAU;AAEnB,QAAM,CAAC,UAAU,WAAW,IAAI,SAAyC;AACzE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoB;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAElD,QAAM,gBAAgB;AAAA,IACpB,OAAO,YAAmC;AACxC,YAAM,EAAE,YAAY,WAAW,QAAQ,IAAI,SAAS;AACpD,UAAI,SAAS,SAAS;AACpB,iBAAS,MAAS;AAClB,qBAAa,IAAI;AAAA,MACnB;AAEA,oBAAc,IAAI;AAElB,YAAM,WAAW,MAAM,KAAK,iBAAiB,IAAI,EAAE,WAAW,CAAC;AAE/D,UAAI,SAAS,OAAO;AAClB,iBAAS,SAAS,KAAkB;AACpC,kBAAU,SAAS,KAAkB;AAAA,MACvC,WAAW,SAAS,SAAS,QAAW;AACtC,oBAAY,SAAS,IAAI;AACzB,oBAAY,SAAS,IAAI;AAAA,MAC3B;AACA,mBAAa,KAAK;AAClB,oBAAc,KAAK;AAAA,IACrB;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAGA,YAAU,MAAM;AACd,UAAM,oBAAoB,KAAK,GAAG,gCAAgC,MAAM;AACtE,oBAAc,IAAI;AAAA,IACpB,CAAC;AAED,UAAM,qBAAqB,KAAK,GAAG,iCAAiC,CAAC,EAAE,MAAM,OAAO,cAAc,MAAM;AACtG,YAAM,EAAE,WAAW,QAAQ,IAAI,SAAS;AACxC,UAAI,eAAe;AACjB,iBAAS,aAA0B;AACnC,kBAAU,aAA0B;AAAA,MACtC,OAAO;AACL,oBAAa,QAAoC,IAAI;AACrD,oBAAa,QAAoC,IAAI;AAAA,MACvD;AACA,oBAAc,KAAK;AAAA,IACrB,CAAC;AAED,UAAM,wBAAwB,KAAK,GAAG,oCAAoC,CAAC,EAAE,KAAK,MAAM;AACtF,UAAI,MAAM;AACR,oBAAY,IAA+B;AAC3C,iBAAS,QAAQ,YAAY,IAA+B;AAAA,MAC9D;AACA,oBAAc,KAAK;AAAA,IACrB,CAAC;AAED,UAAM,wBAAwB,KAAK,GAAG,oCAAoC,CAAC,EAAE,KAAK,MAAM;AACtF,UAAI,CAAC,QAAQ,KAAK,eAAe,SAAS,QAAQ,YAAY;AAC5D;AAAA,MACF;AACA,kBAAY,IAAI;AAChB,eAAS,QAAQ,YAAY,IAAI;AACjC,oBAAc,KAAK;AAAA,IACrB,CAAC;AAED,SAAK,cAAc,EAAE,SAAS,KAAK,CAAC;AAEpC,WAAO,MAAM;AACX,wBAAkB;AAClB,yBAAmB;AACnB,4BAAsB;AACtB,4BAAsB;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,MAAM,eAAe,MAAM,UAAU,CAAC;AAE1C,QAAM,UAAU,YAAY,MAAM,cAAc,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;AAEnF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -23,10 +23,28 @@ type Count = {
|
|
|
23
23
|
* const { counts } = useCounts({
|
|
24
24
|
* filters: [{ seen: true, read: false }]
|
|
25
25
|
* });
|
|
26
|
+
*
|
|
27
|
+
* // Opt out of the built-in realtime count updates and drive them yourself
|
|
28
|
+
* const { counts, refetch } = useCounts({
|
|
29
|
+
* filters: [{ read: false }],
|
|
30
|
+
* realtime: false,
|
|
31
|
+
* });
|
|
26
32
|
* ```
|
|
27
33
|
*/
|
|
28
34
|
type UseCountsProps = {
|
|
29
35
|
filters: NotificationFilter[];
|
|
36
|
+
/**
|
|
37
|
+
* When `false`, disables the WebSocket subscriptions that auto-resync
|
|
38
|
+
* counts on `notifications.notification_received` and
|
|
39
|
+
* `notifications.unread_count_changed`. The filter-driven fetch and
|
|
40
|
+
* `refetch()` keep working. Use alongside
|
|
41
|
+
* `useNotifications({ realtime: false })` when you drive live updates
|
|
42
|
+
* yourself.
|
|
43
|
+
*
|
|
44
|
+
* When set, this prop takes precedence over the `realtime` config on
|
|
45
|
+
* `<NovuProvider />`. When omitted, the provider value (default `true`) is used.
|
|
46
|
+
*/
|
|
47
|
+
realtime?: boolean;
|
|
30
48
|
onSuccess?: (data: Count[]) => void;
|
|
31
49
|
onError?: (error: NovuError) => void;
|
|
32
50
|
};
|
|
@@ -3,10 +3,12 @@ import { areTagsEqual, isSameFilter } from "@novu/js";
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { useDataRef } from "./internal/useDataRef.js";
|
|
5
5
|
import { useWebSocketEvent } from "./internal/useWebsocketEvent.js";
|
|
6
|
-
import { useNovu } from "./NovuProvider.js";
|
|
6
|
+
import { useNovu, useRealtime } from "./NovuProvider.js";
|
|
7
7
|
var useCounts = (props) => {
|
|
8
|
-
const { filters, onSuccess, onError } = props;
|
|
8
|
+
const { filters, realtime: propsRealtime, onSuccess, onError } = props;
|
|
9
9
|
const { notifications } = useNovu();
|
|
10
|
+
const providerRealtime = useRealtime();
|
|
11
|
+
const realtime = propsRealtime ?? providerRealtime;
|
|
10
12
|
const filtersRef = useDataRef(filters);
|
|
11
13
|
const [error, setError] = useState();
|
|
12
14
|
const [counts, setCounts] = useState();
|
|
@@ -57,12 +59,14 @@ var useCounts = (props) => {
|
|
|
57
59
|
};
|
|
58
60
|
useWebSocketEvent({
|
|
59
61
|
event: "notifications.notification_received",
|
|
62
|
+
enabled: realtime,
|
|
60
63
|
eventHandler: (data) => {
|
|
61
64
|
sync(data.result);
|
|
62
65
|
}
|
|
63
66
|
});
|
|
64
67
|
useWebSocketEvent({
|
|
65
68
|
event: "notifications.unread_count_changed",
|
|
69
|
+
enabled: realtime,
|
|
66
70
|
eventHandler: () => {
|
|
67
71
|
sync();
|
|
68
72
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/useCounts.ts"],"sourcesContent":["import { areTagsEqual, isSameFilter, Notification, NotificationFilter, NovuError } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useDataRef } from './internal/useDataRef';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\nimport { useNovu } from './NovuProvider';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\n/**\n * Props for the useCounts hook.\n *\n * @example\n * ```tsx\n * // Count unread notifications\n * const { counts } = useCounts({\n * filters: [{ read: false }]\n * });\n *\n * // Count unseen notifications with specific tags\n * const { counts } = useCounts({\n * filters: [{ seen: false, tags: ['important'] }]\n * });\n *\n * // Count seen but unread notifications\n * const { counts } = useCounts({\n * filters: [{ seen: true, read: false }]\n * });\n * ```\n */\nexport type UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport type UseCountsResult = {\n counts?: Count[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const useCounts = (props: UseCountsProps): UseCountsResult => {\n const { filters, onSuccess, onError } = props;\n const { notifications } = useNovu();\n const filtersRef = useDataRef<NotificationFilter[]>(filters);\n const [error, setError] = useState<NovuError>();\n const [counts, setCounts] = useState<Count[]>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = async (notification?: Notification, overrideFilters?: NotificationFilter[]) => {\n const currentFilters = overrideFilters || filtersRef.current;\n const existingCounts = currentFilters.map((filter) => ({ count: 0, filter }));\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = currentFilters[i];\n const isSeverityMatches =\n !filter.severity ||\n (Array.isArray(filter.severity) && filter.severity.length === 0) ||\n (Array.isArray(filter.severity) && filter.severity.includes(notification.severity)) ||\n (!Array.isArray(filter.severity) && filter.severity === notification.severity);\n\n if (areTagsEqual(filter.tags, notification.tags) && isSeverityMatches) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = currentFilters;\n }\n\n if (countFiltersToFetch.length === 0) {\n return;\n }\n\n setIsFetching(true);\n const countsRes = await notifications.count({ filters: countFiltersToFetch });\n setIsFetching(false);\n setIsLoading(false);\n if (countsRes.error) {\n setError(countsRes.error);\n onError?.(countsRes.error);\n\n return;\n }\n const data = countsRes.data!;\n onSuccess?.(data.counts);\n\n setCounts((oldCounts) => {\n const newCounts: Count[] = [];\n const countsReceived = data.counts;\n\n for (let i = 0; i < existingCounts.length; i++) {\n const existingFilter = existingCounts[i].filter;\n const countReceived = countsReceived.find((c) => isSameFilter(c.filter, existingFilter));\n const count = countReceived || oldCounts?.[i];\n if (count) {\n newCounts.push(count);\n }\n }\n\n return newCounts;\n });\n };\n\n useWebSocketEvent({\n event: 'notifications.notification_received',\n eventHandler: (data) => {\n sync(data.result);\n },\n });\n\n useWebSocketEvent({\n event: 'notifications.unread_count_changed',\n eventHandler: () => {\n sync();\n },\n });\n\n useEffect(() => {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n sync(undefined, filters);\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n"],"mappings":";AAAA,SAAS,cAAc,oBAAiE;AACxF,SAAS,WAAW,gBAAgB;AACpC,SAAS,kBAAkB;AAC3B,SAAS,yBAAyB;AAClC,SAAS,
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/useCounts.ts"],"sourcesContent":["import { areTagsEqual, isSameFilter, Notification, NotificationFilter, NovuError } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useDataRef } from './internal/useDataRef';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\nimport { useNovu, useRealtime } from './NovuProvider';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\n/**\n * Props for the useCounts hook.\n *\n * @example\n * ```tsx\n * // Count unread notifications\n * const { counts } = useCounts({\n * filters: [{ read: false }]\n * });\n *\n * // Count unseen notifications with specific tags\n * const { counts } = useCounts({\n * filters: [{ seen: false, tags: ['important'] }]\n * });\n *\n * // Count seen but unread notifications\n * const { counts } = useCounts({\n * filters: [{ seen: true, read: false }]\n * });\n *\n * // Opt out of the built-in realtime count updates and drive them yourself\n * const { counts, refetch } = useCounts({\n * filters: [{ read: false }],\n * realtime: false,\n * });\n * ```\n */\nexport type UseCountsProps = {\n filters: NotificationFilter[];\n /**\n * When `false`, disables the WebSocket subscriptions that auto-resync\n * counts on `notifications.notification_received` and\n * `notifications.unread_count_changed`. The filter-driven fetch and\n * `refetch()` keep working. Use alongside\n * `useNotifications({ realtime: false })` when you drive live updates\n * yourself.\n *\n * When set, this prop takes precedence over the `realtime` config on\n * `<NovuProvider />`. When omitted, the provider value (default `true`) is used.\n */\n realtime?: boolean;\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport type UseCountsResult = {\n counts?: Count[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const useCounts = (props: UseCountsProps): UseCountsResult => {\n const { filters, realtime: propsRealtime, onSuccess, onError } = props;\n const { notifications } = useNovu();\n const providerRealtime = useRealtime();\n const realtime = propsRealtime ?? providerRealtime;\n const filtersRef = useDataRef<NotificationFilter[]>(filters);\n const [error, setError] = useState<NovuError>();\n const [counts, setCounts] = useState<Count[]>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = async (notification?: Notification, overrideFilters?: NotificationFilter[]) => {\n const currentFilters = overrideFilters || filtersRef.current;\n const existingCounts = currentFilters.map((filter) => ({ count: 0, filter }));\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = currentFilters[i];\n const isSeverityMatches =\n !filter.severity ||\n (Array.isArray(filter.severity) && filter.severity.length === 0) ||\n (Array.isArray(filter.severity) && filter.severity.includes(notification.severity)) ||\n (!Array.isArray(filter.severity) && filter.severity === notification.severity);\n\n if (areTagsEqual(filter.tags, notification.tags) && isSeverityMatches) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = currentFilters;\n }\n\n if (countFiltersToFetch.length === 0) {\n return;\n }\n\n setIsFetching(true);\n const countsRes = await notifications.count({ filters: countFiltersToFetch });\n setIsFetching(false);\n setIsLoading(false);\n if (countsRes.error) {\n setError(countsRes.error);\n onError?.(countsRes.error);\n\n return;\n }\n const data = countsRes.data!;\n onSuccess?.(data.counts);\n\n setCounts((oldCounts) => {\n const newCounts: Count[] = [];\n const countsReceived = data.counts;\n\n for (let i = 0; i < existingCounts.length; i++) {\n const existingFilter = existingCounts[i].filter;\n const countReceived = countsReceived.find((c) => isSameFilter(c.filter, existingFilter));\n const count = countReceived || oldCounts?.[i];\n if (count) {\n newCounts.push(count);\n }\n }\n\n return newCounts;\n });\n };\n\n useWebSocketEvent({\n event: 'notifications.notification_received',\n enabled: realtime,\n eventHandler: (data) => {\n sync(data.result);\n },\n });\n\n useWebSocketEvent({\n event: 'notifications.unread_count_changed',\n enabled: realtime,\n eventHandler: () => {\n sync();\n },\n });\n\n useEffect(() => {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n sync(undefined, filters);\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n"],"mappings":";AAAA,SAAS,cAAc,oBAAiE;AACxF,SAAS,WAAW,gBAAgB;AACpC,SAAS,kBAAkB;AAC3B,SAAS,yBAAyB;AAClC,SAAS,SAAS,mBAAmB;AA4D9B,IAAM,YAAY,CAAC,UAA2C;AACnE,QAAM,EAAE,SAAS,UAAU,eAAe,WAAW,QAAQ,IAAI;AACjE,QAAM,EAAE,cAAc,IAAI,QAAQ;AAClC,QAAM,mBAAmB,YAAY;AACrC,QAAM,WAAW,iBAAiB;AAClC,QAAM,aAAa,WAAiC,OAAO;AAC3D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoB;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAkB;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAElD,QAAM,OAAO,OAAO,cAA6B,oBAA2C;AAC1F,UAAM,iBAAiB,mBAAmB,WAAW;AACrD,UAAM,iBAAiB,eAAe,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,EAAE;AAC5E,QAAI,sBAA4C,CAAC;AACjD,QAAI,cAAc;AAChB,eAAS,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK;AAC9C,cAAM,SAAS,eAAe,CAAC;AAC/B,cAAM,oBACJ,CAAC,OAAO,YACP,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,WAAW,KAC7D,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,aAAa,QAAQ,KAChF,CAAC,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,aAAa,aAAa;AAEvE,YAAI,aAAa,OAAO,MAAM,aAAa,IAAI,KAAK,mBAAmB;AACrE,8BAAoB,KAAK,MAAM;AAAA,QACjC;AAAA,MACF;AAAA,IACF,OAAO;AACL,4BAAsB;AAAA,IACxB;AAEA,QAAI,oBAAoB,WAAW,GAAG;AACpC;AAAA,IACF;AAEA,kBAAc,IAAI;AAClB,UAAM,YAAY,MAAM,cAAc,MAAM,EAAE,SAAS,oBAAoB,CAAC;AAC5E,kBAAc,KAAK;AACnB,iBAAa,KAAK;AAClB,QAAI,UAAU,OAAO;AACnB,eAAS,UAAU,KAAK;AACxB,gBAAU,UAAU,KAAK;AAEzB;AAAA,IACF;AACA,UAAM,OAAO,UAAU;AACvB,gBAAY,KAAK,MAAM;AAEvB,cAAU,CAAC,cAAc;AACvB,YAAM,YAAqB,CAAC;AAC5B,YAAM,iBAAiB,KAAK;AAE5B,eAAS,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK;AAC9C,cAAM,iBAAiB,eAAe,CAAC,EAAE;AACzC,cAAM,gBAAgB,eAAe,KAAK,CAAC,MAAM,aAAa,EAAE,QAAQ,cAAc,CAAC;AACvF,cAAM,QAAQ,iBAAiB,YAAY,CAAC;AAC5C,YAAI,OAAO;AACT,oBAAU,KAAK,KAAK;AAAA,QACtB;AAAA,MACF;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,oBAAkB;AAAA,IAChB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,cAAc,CAAC,SAAS;AACtB,WAAK,KAAK,MAAM;AAAA,IAClB;AAAA,EACF,CAAC;AAED,oBAAkB;AAAA,IAChB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,cAAc,MAAM;AAClB,WAAK;AAAA,IACP;AAAA,EACF,CAAC;AAED,YAAU,MAAM;AACd,aAAS,MAAS;AAClB,iBAAa,IAAI;AACjB,kBAAc,KAAK;AACnB,SAAK,QAAW,OAAO;AAAA,EACzB,GAAG,CAAC,KAAK,UAAU,OAAO,CAAC,CAAC;AAE5B,QAAM,UAAU,YAAY;AAC1B,UAAM,KAAK;AAAA,EACb;AAEA,SAAO,EAAE,QAAQ,OAAO,SAAS,WAAW,WAAW;AACzD;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChannelEndpointResponse, NovuError, CreateChannelEndpointArgs } from '@novu/js';
|
|
2
|
+
|
|
3
|
+
type UseCreateChannelEndpointProps = {
|
|
4
|
+
onSuccess?: (data: ChannelEndpointResponse) => void;
|
|
5
|
+
onError?: (error: NovuError) => void;
|
|
6
|
+
};
|
|
7
|
+
type UseCreateChannelEndpointResult = {
|
|
8
|
+
isCreating: boolean;
|
|
9
|
+
error?: NovuError;
|
|
10
|
+
create: (args: CreateChannelEndpointArgs) => Promise<{
|
|
11
|
+
data?: ChannelEndpointResponse | undefined;
|
|
12
|
+
error?: NovuError | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
declare const useCreateChannelEndpoint: (props?: UseCreateChannelEndpointProps) => UseCreateChannelEndpointResult;
|
|
16
|
+
|
|
17
|
+
export { type UseCreateChannelEndpointProps, type UseCreateChannelEndpointResult, useCreateChannelEndpoint };
|