@novu/react 2.1.2 → 2.2.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/client/index.d.mts +5 -1
- package/dist/client/index.d.ts +5 -1
- package/dist/client/index.js +15 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +15 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/hooks/index.d.mts +3 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/server/server.d.mts +5 -1
- package/dist/server/server.d.ts +5 -1
- package/dist/server/server.js +1 -1
- package/dist/server/server.js.map +1 -1
- package/dist/server/server.mjs +1 -1
- package/dist/server/server.mjs.map +1 -1
- package/package.json +5 -4
package/dist/client/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1, { ReactNode } from 'react';
|
|
3
|
-
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, RouterPush } from '@novu/js/ui';
|
|
3
|
+
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, PreferencesFilter, RouterPush } from '@novu/js/ui';
|
|
4
4
|
export { Notification } from '@novu/js/ui';
|
|
5
5
|
import { Novu, NovuOptions, Notification as Notification$1, NovuError, Preference, NotificationFilter } from '@novu/js';
|
|
6
6
|
|
|
@@ -23,6 +23,7 @@ type BaseProps = {
|
|
|
23
23
|
appearance?: Appearance;
|
|
24
24
|
localization?: Localization;
|
|
25
25
|
tabs?: Array<Tab>;
|
|
26
|
+
preferencesFilter?: PreferencesFilter;
|
|
26
27
|
routerPush?: RouterPush;
|
|
27
28
|
};
|
|
28
29
|
type DefaultProps = BaseProps & DefaultInboxProps & {
|
|
@@ -89,6 +90,9 @@ declare const useNotifications: (props?: UseNotificationsProps) => {
|
|
|
89
90
|
};
|
|
90
91
|
|
|
91
92
|
type UsePreferencesProps = {
|
|
93
|
+
filter?: {
|
|
94
|
+
tags?: string[];
|
|
95
|
+
};
|
|
92
96
|
onSuccess?: (data: Preference[]) => void;
|
|
93
97
|
onError?: (error: NovuError) => void;
|
|
94
98
|
};
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1, { ReactNode } from 'react';
|
|
3
|
-
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, RouterPush } from '@novu/js/ui';
|
|
3
|
+
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, PreferencesFilter, RouterPush } from '@novu/js/ui';
|
|
4
4
|
export { Notification } from '@novu/js/ui';
|
|
5
5
|
import { Novu, NovuOptions, Notification as Notification$1, NovuError, Preference, NotificationFilter } from '@novu/js';
|
|
6
6
|
|
|
@@ -23,6 +23,7 @@ type BaseProps = {
|
|
|
23
23
|
appearance?: Appearance;
|
|
24
24
|
localization?: Localization;
|
|
25
25
|
tabs?: Array<Tab>;
|
|
26
|
+
preferencesFilter?: PreferencesFilter;
|
|
26
27
|
routerPush?: RouterPush;
|
|
27
28
|
};
|
|
28
29
|
type DefaultProps = BaseProps & DefaultInboxProps & {
|
|
@@ -89,6 +90,9 @@ declare const useNotifications: (props?: UseNotificationsProps) => {
|
|
|
89
90
|
};
|
|
90
91
|
|
|
91
92
|
type UsePreferencesProps = {
|
|
93
|
+
filter?: {
|
|
94
|
+
tags?: string[];
|
|
95
|
+
};
|
|
92
96
|
onSuccess?: (data: Preference[]) => void;
|
|
93
97
|
onError?: (error: NovuError) => void;
|
|
94
98
|
};
|
package/dist/client/index.js
CHANGED
|
@@ -173,6 +173,7 @@ var Renderer = ({ options, novu, children }) => {
|
|
|
173
173
|
novuUI.updateTabs(options.tabs);
|
|
174
174
|
novuUI.updateOptions(options.options);
|
|
175
175
|
novuUI.updateRouterPush(options.routerPush);
|
|
176
|
+
novuUI.updatePreferencesFilter(options.preferencesFilter);
|
|
176
177
|
}, [options]);
|
|
177
178
|
if (!novuUI) {
|
|
178
179
|
return null;
|
|
@@ -232,6 +233,7 @@ var InboxChild = import_react6.default.memo((props) => {
|
|
|
232
233
|
localization,
|
|
233
234
|
appearance,
|
|
234
235
|
tabs,
|
|
236
|
+
preferencesFilter,
|
|
235
237
|
routerPush,
|
|
236
238
|
applicationIdentifier,
|
|
237
239
|
subscriberId,
|
|
@@ -245,10 +247,21 @@ var InboxChild = import_react6.default.memo((props) => {
|
|
|
245
247
|
localization,
|
|
246
248
|
appearance,
|
|
247
249
|
tabs,
|
|
250
|
+
preferencesFilter,
|
|
248
251
|
routerPush,
|
|
249
252
|
options: { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl }
|
|
250
253
|
};
|
|
251
|
-
}, [
|
|
254
|
+
}, [
|
|
255
|
+
localization,
|
|
256
|
+
appearance,
|
|
257
|
+
tabs,
|
|
258
|
+
preferencesFilter,
|
|
259
|
+
applicationIdentifier,
|
|
260
|
+
subscriberId,
|
|
261
|
+
subscriberHash,
|
|
262
|
+
backendUrl,
|
|
263
|
+
socketUrl
|
|
264
|
+
]);
|
|
252
265
|
if (isWithChildrenProps(props)) {
|
|
253
266
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Renderer, { options, novu, children: props.children });
|
|
254
267
|
}
|
|
@@ -459,7 +472,7 @@ var usePreferences = (props) => {
|
|
|
459
472
|
}, []);
|
|
460
473
|
const fetchPreferences = async () => {
|
|
461
474
|
setIsFetching(true);
|
|
462
|
-
const response = await preferences.list();
|
|
475
|
+
const response = await preferences.list(props?.filter);
|
|
463
476
|
if (response.error) {
|
|
464
477
|
setError(response.error);
|
|
465
478
|
onError?.(response.error);
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../src/components/Bell.tsx","../../src/utils/createContextAndHook.ts","../../src/context/RenderContext.tsx","../../src/components/Mounter.tsx","../../src/components/Inbox.tsx","../../src/components/Renderer.tsx","../../src/hooks/internal/useDataRef.ts","../../src/components/Preferences.tsx","../../src/components/Notifications.tsx","../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["export * from './components';\nexport * from './hooks';\nexport * from './utils/types';\n","import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { BellRenderer } from '../utils/types';\n\nexport type BellProps = {\n renderBell?: BellRenderer;\n};\n\nexport const Bell = React.memo((props: BellProps) => {\n const { renderBell } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Bell',\n element,\n props: renderBell ? { renderBell: (el, unreadCount) => mountElement(el, renderBell(unreadCount)) } : undefined,\n });\n },\n [renderBell]\n );\n\n return <Mounter mount={mount} />;\n});\n","import React from 'react';\n\nexport function assertContextExists(contextVal: unknown, msgOrCtx: string | React.Context<any>): asserts contextVal {\n if (!contextVal) {\n throw typeof msgOrCtx === 'string' ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);\n }\n}\n\ntype Options = { assertCtxFn?: (v: unknown, msg: string) => void };\ntype ContextOf<T> = React.Context<{ value: T } | undefined>;\ntype UseCtxFn<T> = () => T;\n\n/**\n * Creates and returns a Context and two hooks that return the context value.\n * The Context type is derived from the type passed in by the user.\n * The first hook returned guarantees that the context exists so the returned value is always CtxValue\n * The second hook makes no guarantees, so the returned value can be CtxValue | undefined\n */\nexport const createContextAndHook = <CtxVal>(\n displayName: string,\n options?: Options\n): [ContextOf<CtxVal>, UseCtxFn<CtxVal>, UseCtxFn<CtxVal | Partial<CtxVal>>] => {\n const { assertCtxFn = assertContextExists } = options || {};\n const Ctx = React.createContext<{ value: CtxVal } | undefined>(undefined);\n Ctx.displayName = displayName;\n\n const useCtx = () => {\n const ctx = React.useContext(Ctx);\n assertCtxFn(ctx, `Component must be wrapped with the <Inbox /> Component`);\n\n return (ctx as any).value as CtxVal;\n };\n\n const useCtxWithoutGuarantee = () => {\n const ctx = React.useContext(Ctx);\n\n return ctx ? ctx.value : {};\n };\n\n return [Ctx, useCtx, useCtxWithoutGuarantee];\n};\n","import React from 'react';\nimport type { NovuUI } from '@novu/js/ui';\nimport { createContextAndHook } from '../utils/createContextAndHook';\n\nexport type MountedElement = React.ReactNode;\nexport type MountedElements = Map<HTMLElement, MountedElement>;\n\ntype RendererContextValue = {\n mountElement: (el: HTMLElement, mountedElement: MountedElement) => () => void;\n novuUI: NovuUI;\n};\n\nconst [RendererContext, useRendererContext] = createContextAndHook<RendererContextValue>('RendererContext');\n\nconst RendererProvider = (props: React.PropsWithChildren<{ value: RendererContextValue }>) => {\n return <RendererContext.Provider value={{ value: props.value }}>{props.children}</RendererContext.Provider>;\n};\n\nexport { useRendererContext as useRenderer, RendererProvider };\n","import React from 'react';\n\ntype MounterProps = {\n mount: (node: HTMLElement) => ((node: HTMLElement) => void) | void;\n};\n\n/**\n * Mounter allows you to mount a component to a DOM node.\n */\nexport function Mounter({ mount }: MounterProps) {\n const ref = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n let unmount: (node: HTMLDivElement) => void | undefined;\n const element = ref.current;\n if (element && mount) {\n const possibleUnmount = mount(element);\n if (possibleUnmount) {\n unmount = possibleUnmount;\n }\n }\n\n return () => {\n if (element && unmount) {\n unmount(element);\n }\n };\n }, [ref, mount]);\n\n return <div ref={ref} />;\n}\n","import React, { useMemo } from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { DefaultProps, DefaultInboxProps, WithChildrenProps } from '../utils/types';\nimport { NovuProvider, useNovu, useUnsafeNovu } from './index';\nimport { Mounter } from './Mounter';\nimport { Renderer } from './Renderer';\n\nexport type InboxProps = DefaultProps | WithChildrenProps;\n\nconst DefaultInbox = (props: DefaultInboxProps) => {\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n element,\n });\n },\n [open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n};\n\nexport const Inbox = React.memo((props: InboxProps) => {\n const { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl } = props;\n const novu = useUnsafeNovu();\n\n if (novu) {\n return <InboxChild {...props} />;\n }\n\n return (\n <NovuProvider\n applicationIdentifier={applicationIdentifier}\n subscriberId={subscriberId}\n subscriberHash={subscriberHash}\n backendUrl={backendUrl}\n socketUrl={socketUrl}\n >\n <InboxChild {...props} />\n </NovuProvider>\n );\n});\n\nexport const InboxChild = React.memo((props: InboxProps) => {\n const {\n localization,\n appearance,\n tabs,\n routerPush,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n } = props;\n const novu = useNovu();\n\n const options = useMemo(() => {\n return {\n localization,\n appearance,\n tabs,\n routerPush,\n options: { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl },\n };\n }, [localization, appearance, tabs, applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl]);\n\n if (isWithChildrenProps(props)) {\n return (\n <Renderer options={options} novu={novu}>\n {props.children}\n </Renderer>\n );\n }\n\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n\n return (\n <Renderer options={options} novu={novu}>\n <DefaultInbox\n open={open}\n renderNotification={renderNotification}\n renderBell={renderBell}\n onNotificationClick={onNotificationClick}\n onPrimaryActionClick={onPrimaryActionClick}\n onSecondaryActionClick={onSecondaryActionClick}\n />\n </Renderer>\n );\n});\n\nfunction isWithChildrenProps(props: InboxProps): props is WithChildrenProps {\n return 'children' in props;\n}\n","import React, { useCallback, useEffect, useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport { NovuUI } from '@novu/js/ui';\nimport type { NovuUIOptions } from '@novu/js/ui';\nimport { Novu } from '@novu/js';\nimport { MountedElement, RendererProvider } from '../context/RenderContext';\nimport { useDataRef } from '../hooks/internal/useDataRef';\n\ntype RendererProps = React.PropsWithChildren<{\n options: NovuUIOptions;\n novu?: Novu;\n}>;\n\n/**\n *\n * Renderer component that provides the NovuUI instance and mounts the elements on DOM in a portal\n */\nexport const Renderer = ({ options, novu, children }: RendererProps) => {\n const optionsRef = useDataRef({ ...options, novu });\n const [novuUI, setNovuUI] = useState<NovuUI | undefined>();\n const [mountedElements, setMountedElements] = useState(new Map<HTMLElement, MountedElement>());\n\n const mountElement = useCallback(\n (el: HTMLElement, mountedElement: MountedElement) => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.set(el, mountedElement);\n\n return newMountedElements;\n });\n\n return () => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.delete(el);\n\n return newMountedElements;\n });\n };\n },\n [setMountedElements]\n );\n\n useEffect(() => {\n const novu = new NovuUI(optionsRef.current);\n setNovuUI(novu);\n\n return () => {\n novu.unmount();\n };\n }, []);\n\n useEffect(() => {\n if (!novuUI) {\n return;\n }\n\n novuUI.updateAppearance(options.appearance);\n novuUI.updateLocalization(options.localization);\n novuUI.updateTabs(options.tabs);\n novuUI.updateOptions(options.options);\n novuUI.updateRouterPush(options.routerPush);\n }, [options]);\n\n if (!novuUI) {\n return null;\n }\n\n return (\n <RendererProvider value={{ mountElement, novuUI }}>\n {[...mountedElements].map(([element, mountedElement]) => {\n return ReactDOM.createPortal(mountedElement, element);\n })}\n\n {children}\n </RendererProvider>\n );\n};\n","import { useRef } from 'react';\n\nexport const useDataRef = <T>(data: T) => {\n const ref = useRef(data);\n ref.current = data;\n\n return ref;\n};\n","import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\n\nexport const Preferences = () => {\n const { novuUI } = useRenderer();\n\n const mount = React.useCallback((element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Preferences',\n element,\n });\n }, []);\n\n return <Mounter mount={mount} />;\n};\n","import React from 'react';\nimport type { NotificationClickHandler, NotificationActionClickHandler } from '@novu/js/ui';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { NotificationsRenderer } from '../utils/types';\n\nexport type NotificationProps = {\n renderNotification?: NotificationsRenderer;\n onNotificationClick?: NotificationClickHandler;\n onPrimaryActionClick?: NotificationActionClickHandler;\n onSecondaryActionClick?: NotificationActionClickHandler;\n};\n\nexport const Notifications = React.memo((props: NotificationProps) => {\n const { onNotificationClick, onPrimaryActionClick, renderNotification, onSecondaryActionClick } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Notifications',\n element,\n props: {\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n });\n },\n [renderNotification, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n});\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list();\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["import_react","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_react","import_react","import_jsx_runtime","novu","ReactDOM","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","import_react","import_js","import_react","import_react","import_js","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts","../../src/components/Bell.tsx","../../src/utils/createContextAndHook.ts","../../src/context/RenderContext.tsx","../../src/components/Mounter.tsx","../../src/components/Inbox.tsx","../../src/components/Renderer.tsx","../../src/hooks/internal/useDataRef.ts","../../src/components/Preferences.tsx","../../src/components/Notifications.tsx","../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["export * from './components';\nexport * from './hooks';\nexport * from './utils/types';\n","import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { BellRenderer } from '../utils/types';\n\nexport type BellProps = {\n renderBell?: BellRenderer;\n};\n\nexport const Bell = React.memo((props: BellProps) => {\n const { renderBell } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Bell',\n element,\n props: renderBell ? { renderBell: (el, unreadCount) => mountElement(el, renderBell(unreadCount)) } : undefined,\n });\n },\n [renderBell]\n );\n\n return <Mounter mount={mount} />;\n});\n","import React from 'react';\n\nexport function assertContextExists(contextVal: unknown, msgOrCtx: string | React.Context<any>): asserts contextVal {\n if (!contextVal) {\n throw typeof msgOrCtx === 'string' ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);\n }\n}\n\ntype Options = { assertCtxFn?: (v: unknown, msg: string) => void };\ntype ContextOf<T> = React.Context<{ value: T } | undefined>;\ntype UseCtxFn<T> = () => T;\n\n/**\n * Creates and returns a Context and two hooks that return the context value.\n * The Context type is derived from the type passed in by the user.\n * The first hook returned guarantees that the context exists so the returned value is always CtxValue\n * The second hook makes no guarantees, so the returned value can be CtxValue | undefined\n */\nexport const createContextAndHook = <CtxVal>(\n displayName: string,\n options?: Options\n): [ContextOf<CtxVal>, UseCtxFn<CtxVal>, UseCtxFn<CtxVal | Partial<CtxVal>>] => {\n const { assertCtxFn = assertContextExists } = options || {};\n const Ctx = React.createContext<{ value: CtxVal } | undefined>(undefined);\n Ctx.displayName = displayName;\n\n const useCtx = () => {\n const ctx = React.useContext(Ctx);\n assertCtxFn(ctx, `Component must be wrapped with the <Inbox /> Component`);\n\n return (ctx as any).value as CtxVal;\n };\n\n const useCtxWithoutGuarantee = () => {\n const ctx = React.useContext(Ctx);\n\n return ctx ? ctx.value : {};\n };\n\n return [Ctx, useCtx, useCtxWithoutGuarantee];\n};\n","import React from 'react';\nimport type { NovuUI } from '@novu/js/ui';\nimport { createContextAndHook } from '../utils/createContextAndHook';\n\nexport type MountedElement = React.ReactNode;\nexport type MountedElements = Map<HTMLElement, MountedElement>;\n\ntype RendererContextValue = {\n mountElement: (el: HTMLElement, mountedElement: MountedElement) => () => void;\n novuUI: NovuUI;\n};\n\nconst [RendererContext, useRendererContext] = createContextAndHook<RendererContextValue>('RendererContext');\n\nconst RendererProvider = (props: React.PropsWithChildren<{ value: RendererContextValue }>) => {\n return <RendererContext.Provider value={{ value: props.value }}>{props.children}</RendererContext.Provider>;\n};\n\nexport { useRendererContext as useRenderer, RendererProvider };\n","import React from 'react';\n\ntype MounterProps = {\n mount: (node: HTMLElement) => ((node: HTMLElement) => void) | void;\n};\n\n/**\n * Mounter allows you to mount a component to a DOM node.\n */\nexport function Mounter({ mount }: MounterProps) {\n const ref = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n let unmount: (node: HTMLDivElement) => void | undefined;\n const element = ref.current;\n if (element && mount) {\n const possibleUnmount = mount(element);\n if (possibleUnmount) {\n unmount = possibleUnmount;\n }\n }\n\n return () => {\n if (element && unmount) {\n unmount(element);\n }\n };\n }, [ref, mount]);\n\n return <div ref={ref} />;\n}\n","import React, { useMemo } from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { DefaultProps, DefaultInboxProps, WithChildrenProps } from '../utils/types';\nimport { NovuProvider, useNovu, useUnsafeNovu } from './index';\nimport { Mounter } from './Mounter';\nimport { Renderer } from './Renderer';\n\nexport type InboxProps = DefaultProps | WithChildrenProps;\n\nconst DefaultInbox = (props: DefaultInboxProps) => {\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n element,\n });\n },\n [open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n};\n\nexport const Inbox = React.memo((props: InboxProps) => {\n const { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl } = props;\n const novu = useUnsafeNovu();\n\n if (novu) {\n return <InboxChild {...props} />;\n }\n\n return (\n <NovuProvider\n applicationIdentifier={applicationIdentifier}\n subscriberId={subscriberId}\n subscriberHash={subscriberHash}\n backendUrl={backendUrl}\n socketUrl={socketUrl}\n >\n <InboxChild {...props} />\n </NovuProvider>\n );\n});\n\nexport const InboxChild = React.memo((props: InboxProps) => {\n const {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n routerPush,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n } = props;\n const novu = useNovu();\n\n const options = useMemo(() => {\n return {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n routerPush,\n options: { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl },\n };\n }, [\n localization,\n appearance,\n tabs,\n preferencesFilter,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n ]);\n\n if (isWithChildrenProps(props)) {\n return (\n <Renderer options={options} novu={novu}>\n {props.children}\n </Renderer>\n );\n }\n\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n\n return (\n <Renderer options={options} novu={novu}>\n <DefaultInbox\n open={open}\n renderNotification={renderNotification}\n renderBell={renderBell}\n onNotificationClick={onNotificationClick}\n onPrimaryActionClick={onPrimaryActionClick}\n onSecondaryActionClick={onSecondaryActionClick}\n />\n </Renderer>\n );\n});\n\nfunction isWithChildrenProps(props: InboxProps): props is WithChildrenProps {\n return 'children' in props;\n}\n","import React, { useCallback, useEffect, useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport { NovuUI } from '@novu/js/ui';\nimport type { NovuUIOptions } from '@novu/js/ui';\nimport { Novu } from '@novu/js';\nimport { MountedElement, RendererProvider } from '../context/RenderContext';\nimport { useDataRef } from '../hooks/internal/useDataRef';\n\ntype RendererProps = React.PropsWithChildren<{\n options: NovuUIOptions;\n novu?: Novu;\n}>;\n\n/**\n *\n * Renderer component that provides the NovuUI instance and mounts the elements on DOM in a portal\n */\nexport const Renderer = ({ options, novu, children }: RendererProps) => {\n const optionsRef = useDataRef({ ...options, novu });\n const [novuUI, setNovuUI] = useState<NovuUI | undefined>();\n const [mountedElements, setMountedElements] = useState(new Map<HTMLElement, MountedElement>());\n\n const mountElement = useCallback(\n (el: HTMLElement, mountedElement: MountedElement) => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.set(el, mountedElement);\n\n return newMountedElements;\n });\n\n return () => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.delete(el);\n\n return newMountedElements;\n });\n };\n },\n [setMountedElements]\n );\n\n useEffect(() => {\n const novu = new NovuUI(optionsRef.current);\n setNovuUI(novu);\n\n return () => {\n novu.unmount();\n };\n }, []);\n\n useEffect(() => {\n if (!novuUI) {\n return;\n }\n\n novuUI.updateAppearance(options.appearance);\n novuUI.updateLocalization(options.localization);\n novuUI.updateTabs(options.tabs);\n novuUI.updateOptions(options.options);\n novuUI.updateRouterPush(options.routerPush);\n novuUI.updatePreferencesFilter(options.preferencesFilter);\n }, [options]);\n\n if (!novuUI) {\n return null;\n }\n\n return (\n <RendererProvider value={{ mountElement, novuUI }}>\n {[...mountedElements].map(([element, mountedElement]) => {\n return ReactDOM.createPortal(mountedElement, element);\n })}\n\n {children}\n </RendererProvider>\n );\n};\n","import { useRef } from 'react';\n\nexport const useDataRef = <T>(data: T) => {\n const ref = useRef(data);\n ref.current = data;\n\n return ref;\n};\n","import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\n\nexport const Preferences = () => {\n const { novuUI } = useRenderer();\n\n const mount = React.useCallback((element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Preferences',\n element,\n });\n }, []);\n\n return <Mounter mount={mount} />;\n};\n","import React from 'react';\nimport type { NotificationClickHandler, NotificationActionClickHandler } from '@novu/js/ui';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { NotificationsRenderer } from '../utils/types';\n\nexport type NotificationProps = {\n renderNotification?: NotificationsRenderer;\n onNotificationClick?: NotificationClickHandler;\n onPrimaryActionClick?: NotificationActionClickHandler;\n onSecondaryActionClick?: NotificationActionClickHandler;\n};\n\nexport const Notifications = React.memo((props: NotificationProps) => {\n const { onNotificationClick, onPrimaryActionClick, renderNotification, onSecondaryActionClick } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Notifications',\n element,\n props: {\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n });\n },\n [renderNotification, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n});\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n filter?: { tags?: string[] };\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list(props?.filter);\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["import_react","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_react","import_react","import_jsx_runtime","novu","ReactDOM","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","import_react","import_js","import_react","import_react","import_js","import_react","import_react"]}
|
package/dist/client/index.mjs
CHANGED
|
@@ -127,6 +127,7 @@ var Renderer = ({ options, novu, children }) => {
|
|
|
127
127
|
novuUI.updateTabs(options.tabs);
|
|
128
128
|
novuUI.updateOptions(options.options);
|
|
129
129
|
novuUI.updateRouterPush(options.routerPush);
|
|
130
|
+
novuUI.updatePreferencesFilter(options.preferencesFilter);
|
|
130
131
|
}, [options]);
|
|
131
132
|
if (!novuUI) {
|
|
132
133
|
return null;
|
|
@@ -186,6 +187,7 @@ var InboxChild = React5.memo((props) => {
|
|
|
186
187
|
localization,
|
|
187
188
|
appearance,
|
|
188
189
|
tabs,
|
|
190
|
+
preferencesFilter,
|
|
189
191
|
routerPush,
|
|
190
192
|
applicationIdentifier,
|
|
191
193
|
subscriberId,
|
|
@@ -199,10 +201,21 @@ var InboxChild = React5.memo((props) => {
|
|
|
199
201
|
localization,
|
|
200
202
|
appearance,
|
|
201
203
|
tabs,
|
|
204
|
+
preferencesFilter,
|
|
202
205
|
routerPush,
|
|
203
206
|
options: { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl }
|
|
204
207
|
};
|
|
205
|
-
}, [
|
|
208
|
+
}, [
|
|
209
|
+
localization,
|
|
210
|
+
appearance,
|
|
211
|
+
tabs,
|
|
212
|
+
preferencesFilter,
|
|
213
|
+
applicationIdentifier,
|
|
214
|
+
subscriberId,
|
|
215
|
+
subscriberHash,
|
|
216
|
+
backendUrl,
|
|
217
|
+
socketUrl
|
|
218
|
+
]);
|
|
206
219
|
if (isWithChildrenProps(props)) {
|
|
207
220
|
return /* @__PURE__ */ jsx4(Renderer, { options, novu, children: props.children });
|
|
208
221
|
}
|
|
@@ -413,7 +426,7 @@ var usePreferences = (props) => {
|
|
|
413
426
|
}, []);
|
|
414
427
|
const fetchPreferences = async () => {
|
|
415
428
|
setIsFetching(true);
|
|
416
|
-
const response = await preferences.list();
|
|
429
|
+
const response = await preferences.list(props?.filter);
|
|
417
430
|
if (response.error) {
|
|
418
431
|
setError(response.error);
|
|
419
432
|
onError?.(response.error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/Bell.tsx","../../src/utils/createContextAndHook.ts","../../src/context/RenderContext.tsx","../../src/components/Mounter.tsx","../../src/components/Inbox.tsx","../../src/components/Renderer.tsx","../../src/hooks/internal/useDataRef.ts","../../src/components/Preferences.tsx","../../src/components/Notifications.tsx","../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { BellRenderer } from '../utils/types';\n\nexport type BellProps = {\n renderBell?: BellRenderer;\n};\n\nexport const Bell = React.memo((props: BellProps) => {\n const { renderBell } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Bell',\n element,\n props: renderBell ? { renderBell: (el, unreadCount) => mountElement(el, renderBell(unreadCount)) } : undefined,\n });\n },\n [renderBell]\n );\n\n return <Mounter mount={mount} />;\n});\n","import React from 'react';\n\nexport function assertContextExists(contextVal: unknown, msgOrCtx: string | React.Context<any>): asserts contextVal {\n if (!contextVal) {\n throw typeof msgOrCtx === 'string' ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);\n }\n}\n\ntype Options = { assertCtxFn?: (v: unknown, msg: string) => void };\ntype ContextOf<T> = React.Context<{ value: T } | undefined>;\ntype UseCtxFn<T> = () => T;\n\n/**\n * Creates and returns a Context and two hooks that return the context value.\n * The Context type is derived from the type passed in by the user.\n * The first hook returned guarantees that the context exists so the returned value is always CtxValue\n * The second hook makes no guarantees, so the returned value can be CtxValue | undefined\n */\nexport const createContextAndHook = <CtxVal>(\n displayName: string,\n options?: Options\n): [ContextOf<CtxVal>, UseCtxFn<CtxVal>, UseCtxFn<CtxVal | Partial<CtxVal>>] => {\n const { assertCtxFn = assertContextExists } = options || {};\n const Ctx = React.createContext<{ value: CtxVal } | undefined>(undefined);\n Ctx.displayName = displayName;\n\n const useCtx = () => {\n const ctx = React.useContext(Ctx);\n assertCtxFn(ctx, `Component must be wrapped with the <Inbox /> Component`);\n\n return (ctx as any).value as CtxVal;\n };\n\n const useCtxWithoutGuarantee = () => {\n const ctx = React.useContext(Ctx);\n\n return ctx ? ctx.value : {};\n };\n\n return [Ctx, useCtx, useCtxWithoutGuarantee];\n};\n","import React from 'react';\nimport type { NovuUI } from '@novu/js/ui';\nimport { createContextAndHook } from '../utils/createContextAndHook';\n\nexport type MountedElement = React.ReactNode;\nexport type MountedElements = Map<HTMLElement, MountedElement>;\n\ntype RendererContextValue = {\n mountElement: (el: HTMLElement, mountedElement: MountedElement) => () => void;\n novuUI: NovuUI;\n};\n\nconst [RendererContext, useRendererContext] = createContextAndHook<RendererContextValue>('RendererContext');\n\nconst RendererProvider = (props: React.PropsWithChildren<{ value: RendererContextValue }>) => {\n return <RendererContext.Provider value={{ value: props.value }}>{props.children}</RendererContext.Provider>;\n};\n\nexport { useRendererContext as useRenderer, RendererProvider };\n","import React from 'react';\n\ntype MounterProps = {\n mount: (node: HTMLElement) => ((node: HTMLElement) => void) | void;\n};\n\n/**\n * Mounter allows you to mount a component to a DOM node.\n */\nexport function Mounter({ mount }: MounterProps) {\n const ref = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n let unmount: (node: HTMLDivElement) => void | undefined;\n const element = ref.current;\n if (element && mount) {\n const possibleUnmount = mount(element);\n if (possibleUnmount) {\n unmount = possibleUnmount;\n }\n }\n\n return () => {\n if (element && unmount) {\n unmount(element);\n }\n };\n }, [ref, mount]);\n\n return <div ref={ref} />;\n}\n","import React, { useMemo } from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { DefaultProps, DefaultInboxProps, WithChildrenProps } from '../utils/types';\nimport { NovuProvider, useNovu, useUnsafeNovu } from './index';\nimport { Mounter } from './Mounter';\nimport { Renderer } from './Renderer';\n\nexport type InboxProps = DefaultProps | WithChildrenProps;\n\nconst DefaultInbox = (props: DefaultInboxProps) => {\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n element,\n });\n },\n [open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n};\n\nexport const Inbox = React.memo((props: InboxProps) => {\n const { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl } = props;\n const novu = useUnsafeNovu();\n\n if (novu) {\n return <InboxChild {...props} />;\n }\n\n return (\n <NovuProvider\n applicationIdentifier={applicationIdentifier}\n subscriberId={subscriberId}\n subscriberHash={subscriberHash}\n backendUrl={backendUrl}\n socketUrl={socketUrl}\n >\n <InboxChild {...props} />\n </NovuProvider>\n );\n});\n\nexport const InboxChild = React.memo((props: InboxProps) => {\n const {\n localization,\n appearance,\n tabs,\n routerPush,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n } = props;\n const novu = useNovu();\n\n const options = useMemo(() => {\n return {\n localization,\n appearance,\n tabs,\n routerPush,\n options: { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl },\n };\n }, [localization, appearance, tabs, applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl]);\n\n if (isWithChildrenProps(props)) {\n return (\n <Renderer options={options} novu={novu}>\n {props.children}\n </Renderer>\n );\n }\n\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n\n return (\n <Renderer options={options} novu={novu}>\n <DefaultInbox\n open={open}\n renderNotification={renderNotification}\n renderBell={renderBell}\n onNotificationClick={onNotificationClick}\n onPrimaryActionClick={onPrimaryActionClick}\n onSecondaryActionClick={onSecondaryActionClick}\n />\n </Renderer>\n );\n});\n\nfunction isWithChildrenProps(props: InboxProps): props is WithChildrenProps {\n return 'children' in props;\n}\n","import React, { useCallback, useEffect, useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport { NovuUI } from '@novu/js/ui';\nimport type { NovuUIOptions } from '@novu/js/ui';\nimport { Novu } from '@novu/js';\nimport { MountedElement, RendererProvider } from '../context/RenderContext';\nimport { useDataRef } from '../hooks/internal/useDataRef';\n\ntype RendererProps = React.PropsWithChildren<{\n options: NovuUIOptions;\n novu?: Novu;\n}>;\n\n/**\n *\n * Renderer component that provides the NovuUI instance and mounts the elements on DOM in a portal\n */\nexport const Renderer = ({ options, novu, children }: RendererProps) => {\n const optionsRef = useDataRef({ ...options, novu });\n const [novuUI, setNovuUI] = useState<NovuUI | undefined>();\n const [mountedElements, setMountedElements] = useState(new Map<HTMLElement, MountedElement>());\n\n const mountElement = useCallback(\n (el: HTMLElement, mountedElement: MountedElement) => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.set(el, mountedElement);\n\n return newMountedElements;\n });\n\n return () => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.delete(el);\n\n return newMountedElements;\n });\n };\n },\n [setMountedElements]\n );\n\n useEffect(() => {\n const novu = new NovuUI(optionsRef.current);\n setNovuUI(novu);\n\n return () => {\n novu.unmount();\n };\n }, []);\n\n useEffect(() => {\n if (!novuUI) {\n return;\n }\n\n novuUI.updateAppearance(options.appearance);\n novuUI.updateLocalization(options.localization);\n novuUI.updateTabs(options.tabs);\n novuUI.updateOptions(options.options);\n novuUI.updateRouterPush(options.routerPush);\n }, [options]);\n\n if (!novuUI) {\n return null;\n }\n\n return (\n <RendererProvider value={{ mountElement, novuUI }}>\n {[...mountedElements].map(([element, mountedElement]) => {\n return ReactDOM.createPortal(mountedElement, element);\n })}\n\n {children}\n </RendererProvider>\n );\n};\n","import { useRef } from 'react';\n\nexport const useDataRef = <T>(data: T) => {\n const ref = useRef(data);\n ref.current = data;\n\n return ref;\n};\n","import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\n\nexport const Preferences = () => {\n const { novuUI } = useRenderer();\n\n const mount = React.useCallback((element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Preferences',\n element,\n });\n }, []);\n\n return <Mounter mount={mount} />;\n};\n","import React from 'react';\nimport type { NotificationClickHandler, NotificationActionClickHandler } from '@novu/js/ui';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { NotificationsRenderer } from '../utils/types';\n\nexport type NotificationProps = {\n renderNotification?: NotificationsRenderer;\n onNotificationClick?: NotificationClickHandler;\n onPrimaryActionClick?: NotificationActionClickHandler;\n onSecondaryActionClick?: NotificationActionClickHandler;\n};\n\nexport const Notifications = React.memo((props: NotificationProps) => {\n const { onNotificationClick, onPrimaryActionClick, renderNotification, onSecondaryActionClick } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Notifications',\n element,\n props: {\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n });\n },\n [renderNotification, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n});\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list();\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["React","React","jsx","jsx","React","React","novu","jsx","React","React","jsx","React","React","jsx","React","useMemo","jsx","useState","useEffect","useRef","useRef","useState","useEffect","useEffect","useState","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useEffect","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/Bell.tsx","../../src/utils/createContextAndHook.ts","../../src/context/RenderContext.tsx","../../src/components/Mounter.tsx","../../src/components/Inbox.tsx","../../src/components/Renderer.tsx","../../src/hooks/internal/useDataRef.ts","../../src/components/Preferences.tsx","../../src/components/Notifications.tsx","../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { BellRenderer } from '../utils/types';\n\nexport type BellProps = {\n renderBell?: BellRenderer;\n};\n\nexport const Bell = React.memo((props: BellProps) => {\n const { renderBell } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Bell',\n element,\n props: renderBell ? { renderBell: (el, unreadCount) => mountElement(el, renderBell(unreadCount)) } : undefined,\n });\n },\n [renderBell]\n );\n\n return <Mounter mount={mount} />;\n});\n","import React from 'react';\n\nexport function assertContextExists(contextVal: unknown, msgOrCtx: string | React.Context<any>): asserts contextVal {\n if (!contextVal) {\n throw typeof msgOrCtx === 'string' ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);\n }\n}\n\ntype Options = { assertCtxFn?: (v: unknown, msg: string) => void };\ntype ContextOf<T> = React.Context<{ value: T } | undefined>;\ntype UseCtxFn<T> = () => T;\n\n/**\n * Creates and returns a Context and two hooks that return the context value.\n * The Context type is derived from the type passed in by the user.\n * The first hook returned guarantees that the context exists so the returned value is always CtxValue\n * The second hook makes no guarantees, so the returned value can be CtxValue | undefined\n */\nexport const createContextAndHook = <CtxVal>(\n displayName: string,\n options?: Options\n): [ContextOf<CtxVal>, UseCtxFn<CtxVal>, UseCtxFn<CtxVal | Partial<CtxVal>>] => {\n const { assertCtxFn = assertContextExists } = options || {};\n const Ctx = React.createContext<{ value: CtxVal } | undefined>(undefined);\n Ctx.displayName = displayName;\n\n const useCtx = () => {\n const ctx = React.useContext(Ctx);\n assertCtxFn(ctx, `Component must be wrapped with the <Inbox /> Component`);\n\n return (ctx as any).value as CtxVal;\n };\n\n const useCtxWithoutGuarantee = () => {\n const ctx = React.useContext(Ctx);\n\n return ctx ? ctx.value : {};\n };\n\n return [Ctx, useCtx, useCtxWithoutGuarantee];\n};\n","import React from 'react';\nimport type { NovuUI } from '@novu/js/ui';\nimport { createContextAndHook } from '../utils/createContextAndHook';\n\nexport type MountedElement = React.ReactNode;\nexport type MountedElements = Map<HTMLElement, MountedElement>;\n\ntype RendererContextValue = {\n mountElement: (el: HTMLElement, mountedElement: MountedElement) => () => void;\n novuUI: NovuUI;\n};\n\nconst [RendererContext, useRendererContext] = createContextAndHook<RendererContextValue>('RendererContext');\n\nconst RendererProvider = (props: React.PropsWithChildren<{ value: RendererContextValue }>) => {\n return <RendererContext.Provider value={{ value: props.value }}>{props.children}</RendererContext.Provider>;\n};\n\nexport { useRendererContext as useRenderer, RendererProvider };\n","import React from 'react';\n\ntype MounterProps = {\n mount: (node: HTMLElement) => ((node: HTMLElement) => void) | void;\n};\n\n/**\n * Mounter allows you to mount a component to a DOM node.\n */\nexport function Mounter({ mount }: MounterProps) {\n const ref = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n let unmount: (node: HTMLDivElement) => void | undefined;\n const element = ref.current;\n if (element && mount) {\n const possibleUnmount = mount(element);\n if (possibleUnmount) {\n unmount = possibleUnmount;\n }\n }\n\n return () => {\n if (element && unmount) {\n unmount(element);\n }\n };\n }, [ref, mount]);\n\n return <div ref={ref} />;\n}\n","import React, { useMemo } from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { DefaultProps, DefaultInboxProps, WithChildrenProps } from '../utils/types';\nimport { NovuProvider, useNovu, useUnsafeNovu } from './index';\nimport { Mounter } from './Mounter';\nimport { Renderer } from './Renderer';\n\nexport type InboxProps = DefaultProps | WithChildrenProps;\n\nconst DefaultInbox = (props: DefaultInboxProps) => {\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n element,\n });\n },\n [open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n};\n\nexport const Inbox = React.memo((props: InboxProps) => {\n const { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl } = props;\n const novu = useUnsafeNovu();\n\n if (novu) {\n return <InboxChild {...props} />;\n }\n\n return (\n <NovuProvider\n applicationIdentifier={applicationIdentifier}\n subscriberId={subscriberId}\n subscriberHash={subscriberHash}\n backendUrl={backendUrl}\n socketUrl={socketUrl}\n >\n <InboxChild {...props} />\n </NovuProvider>\n );\n});\n\nexport const InboxChild = React.memo((props: InboxProps) => {\n const {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n routerPush,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n } = props;\n const novu = useNovu();\n\n const options = useMemo(() => {\n return {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n routerPush,\n options: { applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl },\n };\n }, [\n localization,\n appearance,\n tabs,\n preferencesFilter,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n ]);\n\n if (isWithChildrenProps(props)) {\n return (\n <Renderer options={options} novu={novu}>\n {props.children}\n </Renderer>\n );\n }\n\n const { open, renderNotification, renderBell, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick } =\n props;\n\n return (\n <Renderer options={options} novu={novu}>\n <DefaultInbox\n open={open}\n renderNotification={renderNotification}\n renderBell={renderBell}\n onNotificationClick={onNotificationClick}\n onPrimaryActionClick={onPrimaryActionClick}\n onSecondaryActionClick={onSecondaryActionClick}\n />\n </Renderer>\n );\n});\n\nfunction isWithChildrenProps(props: InboxProps): props is WithChildrenProps {\n return 'children' in props;\n}\n","import React, { useCallback, useEffect, useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport { NovuUI } from '@novu/js/ui';\nimport type { NovuUIOptions } from '@novu/js/ui';\nimport { Novu } from '@novu/js';\nimport { MountedElement, RendererProvider } from '../context/RenderContext';\nimport { useDataRef } from '../hooks/internal/useDataRef';\n\ntype RendererProps = React.PropsWithChildren<{\n options: NovuUIOptions;\n novu?: Novu;\n}>;\n\n/**\n *\n * Renderer component that provides the NovuUI instance and mounts the elements on DOM in a portal\n */\nexport const Renderer = ({ options, novu, children }: RendererProps) => {\n const optionsRef = useDataRef({ ...options, novu });\n const [novuUI, setNovuUI] = useState<NovuUI | undefined>();\n const [mountedElements, setMountedElements] = useState(new Map<HTMLElement, MountedElement>());\n\n const mountElement = useCallback(\n (el: HTMLElement, mountedElement: MountedElement) => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.set(el, mountedElement);\n\n return newMountedElements;\n });\n\n return () => {\n setMountedElements((prev) => {\n const newMountedElements = new Map(prev);\n newMountedElements.delete(el);\n\n return newMountedElements;\n });\n };\n },\n [setMountedElements]\n );\n\n useEffect(() => {\n const novu = new NovuUI(optionsRef.current);\n setNovuUI(novu);\n\n return () => {\n novu.unmount();\n };\n }, []);\n\n useEffect(() => {\n if (!novuUI) {\n return;\n }\n\n novuUI.updateAppearance(options.appearance);\n novuUI.updateLocalization(options.localization);\n novuUI.updateTabs(options.tabs);\n novuUI.updateOptions(options.options);\n novuUI.updateRouterPush(options.routerPush);\n novuUI.updatePreferencesFilter(options.preferencesFilter);\n }, [options]);\n\n if (!novuUI) {\n return null;\n }\n\n return (\n <RendererProvider value={{ mountElement, novuUI }}>\n {[...mountedElements].map(([element, mountedElement]) => {\n return ReactDOM.createPortal(mountedElement, element);\n })}\n\n {children}\n </RendererProvider>\n );\n};\n","import { useRef } from 'react';\n\nexport const useDataRef = <T>(data: T) => {\n const ref = useRef(data);\n ref.current = data;\n\n return ref;\n};\n","import React from 'react';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\n\nexport const Preferences = () => {\n const { novuUI } = useRenderer();\n\n const mount = React.useCallback((element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Preferences',\n element,\n });\n }, []);\n\n return <Mounter mount={mount} />;\n};\n","import React from 'react';\nimport type { NotificationClickHandler, NotificationActionClickHandler } from '@novu/js/ui';\nimport { useRenderer } from '../context/RenderContext';\nimport { Mounter } from './Mounter';\nimport { NotificationsRenderer } from '../utils/types';\n\nexport type NotificationProps = {\n renderNotification?: NotificationsRenderer;\n onNotificationClick?: NotificationClickHandler;\n onPrimaryActionClick?: NotificationActionClickHandler;\n onSecondaryActionClick?: NotificationActionClickHandler;\n};\n\nexport const Notifications = React.memo((props: NotificationProps) => {\n const { onNotificationClick, onPrimaryActionClick, renderNotification, onSecondaryActionClick } = props;\n const { novuUI, mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n return novuUI.mountComponent({\n name: 'Notifications',\n element,\n props: {\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n },\n });\n },\n [renderNotification, onNotificationClick, onPrimaryActionClick, onSecondaryActionClick]\n );\n\n return <Mounter mount={mount} />;\n});\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n filter?: { tags?: string[] };\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list(props?.filter);\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["React","React","jsx","jsx","React","React","novu","jsx","React","React","jsx","React","React","jsx","React","useMemo","jsx","useState","useEffect","useRef","useRef","useState","useEffect","useEffect","useState","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useEffect","useState","useEffect"]}
|
package/dist/hooks/index.d.mts
CHANGED
package/dist/hooks/index.d.ts
CHANGED
package/dist/hooks/index.js
CHANGED
|
@@ -178,7 +178,7 @@ var usePreferences = (props) => {
|
|
|
178
178
|
}, []);
|
|
179
179
|
const fetchPreferences = async () => {
|
|
180
180
|
setIsFetching(true);
|
|
181
|
-
const response = await preferences.list();
|
|
181
|
+
const response = await preferences.list(props?.filter);
|
|
182
182
|
if (response.error) {
|
|
183
183
|
setError(response.error);
|
|
184
184
|
onError?.(response.error);
|
package/dist/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/index.ts","../../src/hooks/useNotifications.ts","../../src/hooks/NovuProvider.tsx","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["export * from './useNotifications';\nexport * from './usePreferences';\nexport * from './useCounts';\nexport { NovuProvider, useNovu } from './NovuProvider';\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list();\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["import_react","import_js","import_react","import_react","import_js","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/index.ts","../../src/hooks/useNotifications.ts","../../src/hooks/NovuProvider.tsx","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["export * from './useNotifications';\nexport * from './usePreferences';\nexport * from './useCounts';\nexport { NovuProvider, useNovu } from './NovuProvider';\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n filter?: { tags?: string[] };\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list(props?.filter);\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["import_react","import_js","import_react","import_react","import_js","import_react","import_react"]}
|
package/dist/hooks/index.mjs
CHANGED
|
@@ -148,7 +148,7 @@ var usePreferences = (props) => {
|
|
|
148
148
|
}, []);
|
|
149
149
|
const fetchPreferences = async () => {
|
|
150
150
|
setIsFetching(true);
|
|
151
|
-
const response = await preferences.list();
|
|
151
|
+
const response = await preferences.list(props?.filter);
|
|
152
152
|
if (response.error) {
|
|
153
153
|
setError(response.error);
|
|
154
154
|
onError?.(response.error);
|
package/dist/hooks/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/useNotifications.ts","../../src/hooks/NovuProvider.tsx","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list();\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["useEffect","useState","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useEffect","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useNotifications.ts","../../src/hooks/NovuProvider.tsx","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n filter?: { tags?: string[] };\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list(props?.filter);\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["useEffect","useState","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useEffect","useState","useEffect"]}
|
package/dist/server/server.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, RouterPush } from '@novu/js/ui';
|
|
1
|
+
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, PreferencesFilter, RouterPush } from '@novu/js/ui';
|
|
2
2
|
export { Notification } from '@novu/js/ui';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { Novu, NovuOptions, Notification as Notification$1, NovuError, Preference, NotificationFilter } from '@novu/js';
|
|
@@ -23,6 +23,7 @@ type BaseProps = {
|
|
|
23
23
|
appearance?: Appearance;
|
|
24
24
|
localization?: Localization;
|
|
25
25
|
tabs?: Array<Tab>;
|
|
26
|
+
preferencesFilter?: PreferencesFilter;
|
|
26
27
|
routerPush?: RouterPush;
|
|
27
28
|
};
|
|
28
29
|
type DefaultProps = BaseProps & DefaultInboxProps & {
|
|
@@ -69,6 +70,9 @@ declare const useNotifications: (props?: UseNotificationsProps) => {
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
type UsePreferencesProps = {
|
|
73
|
+
filter?: {
|
|
74
|
+
tags?: string[];
|
|
75
|
+
};
|
|
72
76
|
onSuccess?: (data: Preference[]) => void;
|
|
73
77
|
onError?: (error: NovuError) => void;
|
|
74
78
|
};
|
package/dist/server/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, RouterPush } from '@novu/js/ui';
|
|
1
|
+
import { Notification, NotificationClickHandler, NotificationActionClickHandler, Appearance, Localization, Tab, PreferencesFilter, RouterPush } from '@novu/js/ui';
|
|
2
2
|
export { Notification } from '@novu/js/ui';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { Novu, NovuOptions, Notification as Notification$1, NovuError, Preference, NotificationFilter } from '@novu/js';
|
|
@@ -23,6 +23,7 @@ type BaseProps = {
|
|
|
23
23
|
appearance?: Appearance;
|
|
24
24
|
localization?: Localization;
|
|
25
25
|
tabs?: Array<Tab>;
|
|
26
|
+
preferencesFilter?: PreferencesFilter;
|
|
26
27
|
routerPush?: RouterPush;
|
|
27
28
|
};
|
|
28
29
|
type DefaultProps = BaseProps & DefaultInboxProps & {
|
|
@@ -69,6 +70,9 @@ declare const useNotifications: (props?: UseNotificationsProps) => {
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
type UsePreferencesProps = {
|
|
73
|
+
filter?: {
|
|
74
|
+
tags?: string[];
|
|
75
|
+
};
|
|
72
76
|
onSuccess?: (data: Preference[]) => void;
|
|
73
77
|
onError?: (error: NovuError) => void;
|
|
74
78
|
};
|
package/dist/server/server.js
CHANGED
|
@@ -180,7 +180,7 @@ var usePreferences = (props) => {
|
|
|
180
180
|
}, []);
|
|
181
181
|
const fetchPreferences = async () => {
|
|
182
182
|
setIsFetching(true);
|
|
183
|
-
const response = await preferences.list();
|
|
183
|
+
const response = await preferences.list(props == null ? void 0 : props.filter);
|
|
184
184
|
if (response.error) {
|
|
185
185
|
setError(response.error);
|
|
186
186
|
onError == null ? void 0 : onError(response.error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server.ts","../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["export * from './utils/types';\n/**\n * Exporting all components from the components folder\n * as empty functions to fix build errors in SSR\n * This will be replaced with actual components\n * when we implement the SSR components in @novu/js/ui\n */\nexport function Inbox() {}\nexport function Notifications() {}\nexport function Preferences() {}\nexport function Bell() {}\n\n//Hooks\nexport { NovuProvider } from './index';\nexport * from './hooks';\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list();\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["import_react","import_js","import_react","import_react","import_js","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server.ts","../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts"],"sourcesContent":["export * from './utils/types';\n/**\n * Exporting all components from the components folder\n * as empty functions to fix build errors in SSR\n * This will be replaced with actual components\n * when we implement the SSR components in @novu/js/ui\n */\nexport function Inbox() {}\nexport function Notifications() {}\nexport function Preferences() {}\nexport function Bell() {}\n\n//Hooks\nexport { NovuProvider } from './index';\nexport * from './hooks';\n","import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n filter?: { tags?: string[] };\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list(props?.filter);\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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":"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","names":["import_react","import_js","import_react","import_react","import_js","import_react","import_react"]}
|
package/dist/server/server.mjs
CHANGED
|
@@ -146,7 +146,7 @@ var usePreferences = (props) => {
|
|
|
146
146
|
}, []);
|
|
147
147
|
const fetchPreferences = async () => {
|
|
148
148
|
setIsFetching(true);
|
|
149
|
-
const response = await preferences.list();
|
|
149
|
+
const response = await preferences.list(props == null ? void 0 : props.filter);
|
|
150
150
|
if (response.error) {
|
|
151
151
|
setError(response.error);
|
|
152
152
|
onError == null ? void 0 : onError(response.error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts","../../src/server.ts"],"sourcesContent":["import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list();\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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","export * from './utils/types';\n/**\n * Exporting all components from the components folder\n * as empty functions to fix build errors in SSR\n * This will be replaced with actual components\n * when we implement the SSR components in @novu/js/ui\n */\nexport function Inbox() {}\nexport function Notifications() {}\nexport function Preferences() {}\nexport function Bell() {}\n\n//Hooks\nexport { NovuProvider } from './index';\nexport * from './hooks';\n"],"mappings":"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","names":["useEffect","useState","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useEffect","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/NovuProvider.tsx","../../src/hooks/useNotifications.ts","../../src/hooks/usePreferences.ts","../../src/hooks/useCounts.ts","../../src/hooks/internal/useWebsocketEvent.ts","../../src/utils/requestLock.ts","../../src/hooks/internal/useBrowserTabsChannel.ts","../../src/server.ts"],"sourcesContent":["import { Novu, NovuOptions } from '@novu/js';\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\n\ntype NovuProviderProps = NovuOptions & {\n children: ReactNode;\n};\n\nconst NovuContext = createContext<Novu | undefined>(undefined);\n\nexport const NovuProvider = ({\n children,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n useCache,\n}: NovuProviderProps) => {\n const novu = useMemo(\n () => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),\n [applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]\n );\n\n return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;\n};\n\nexport const useNovu = () => {\n const context = useContext(NovuContext);\n if (!context) {\n throw new Error('useNovu must be used within a <NovuProvider />');\n }\n\n return context;\n};\n\nexport const useUnsafeNovu = () => {\n const context = useContext(NovuContext);\n\n return context;\n};\n","import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps) => {\n const { tags, read, archived = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on, off } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n on('notifications.list.updated', sync);\n\n return () => {\n off('notifications.list.updated', sync);\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n","import { NovuError, Preference } from '@novu/js';\nimport { useEffect, useState } from 'react';\nimport { useNovu } from './NovuProvider';\n\ntype UsePreferencesProps = {\n filter?: { tags?: string[] };\n onSuccess?: (data: Preference[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype UsePreferencesResult = {\n preferences?: Preference[];\n error?: NovuError;\n isLoading: boolean; // initial loading\n isFetching: boolean; // the request is in flight\n refetch: () => Promise<void>;\n};\n\nexport const usePreferences = (props?: UsePreferencesProps): UsePreferencesResult => {\n const { onSuccess, onError } = props || {};\n const [data, setData] = useState<Preference[]>();\n const { preferences, on, off } = useNovu();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n\n const sync = (event: { data?: Preference[] }) => {\n if (!event.data) {\n return;\n }\n setData(event.data);\n };\n\n useEffect(() => {\n fetchPreferences();\n\n on('preferences.list.updated', sync);\n on('preferences.list.pending', sync);\n on('preferences.list.resolved', sync);\n\n return () => {\n off('preferences.list.updated', sync);\n off('preferences.list.pending', sync);\n off('preferences.list.resolved', sync);\n };\n }, []);\n\n const fetchPreferences = async () => {\n setIsFetching(true);\n const response = await preferences.list(props?.filter);\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n preferences.cache.clearAll();\n\n return fetchPreferences();\n };\n\n return {\n preferences: data,\n error,\n isLoading,\n isFetching,\n refetch,\n };\n};\n","import { useEffect, useState } from 'react';\nimport { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';\nimport { useNovu } from './NovuProvider';\nimport { useWebSocketEvent } from './internal/useWebsocketEvent';\n\ntype Count = {\n count: number;\n filter: NotificationFilter;\n};\n\ntype UseCountsProps = {\n filters: NotificationFilter[];\n onSuccess?: (data: Count[]) => void;\n onError?: (error: NovuError) => void;\n};\n\ntype 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 [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) => {\n const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);\n let countFiltersToFetch: NotificationFilter[] = [];\n if (notification) {\n // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const filter = filters[i];\n if (areTagsEqual(filter.tags, notification.tags)) {\n countFiltersToFetch.push(filter);\n }\n }\n } else {\n countFiltersToFetch = filters;\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 // eslint-disable-next-line no-plusplus\n for (let i = 0; i < existingCounts.length; i++) {\n const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));\n\n newCounts.push(countReceived || oldCounts![i]);\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();\n }, [JSON.stringify(filters)]);\n\n const refetch = async () => {\n await sync();\n };\n\n return { counts, error, refetch, isLoading, isFetching };\n};\n","import { EventHandler, Events, SocketEventNames } from '@novu/js';\nimport { useEffect } from 'react';\nimport { useNovu } from '../NovuProvider';\nimport { requestLock } from '../../utils/requestLock';\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 { postMessage } = useBrowserTabsChannel({ channelName: `nv.${webSocketEvent}`, onMessage });\n\n const updateReadCount: EventHandler<Events[E]> = (data) => {\n onMessage(data);\n postMessage(data);\n };\n\n useEffect(() => {\n const resolveLock = requestLock(`nv.${webSocketEvent}`, () => {\n novu.on(webSocketEvent, updateReadCount);\n });\n\n return () => {\n novu.off(webSocketEvent, updateReadCount);\n resolveLock();\n };\n }, []);\n};\n","export function requestLock(id: string, cb: (id: string) => void) {\n // Check if the Lock API is available\n if (!('locks' in navigator)) {\n // If Lock API is not available, immediately invoke the callback and return a no-op function\n cb(id);\n return () => {};\n }\n\n let isFulfilled = false;\n let promiseResolve: () => void;\n\n const promise = new Promise<void>((resolve) => {\n promiseResolve = resolve;\n });\n\n navigator.locks.request(id, () => {\n if (!isFulfilled) {\n cb(id);\n }\n\n return promise;\n });\n\n return () => {\n isFulfilled = true;\n promiseResolve();\n };\n}\n","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","export * from './utils/types';\n/**\n * Exporting all components from the components folder\n * as empty functions to fix build errors in SSR\n * This will be replaced with actual components\n * when we implement the SSR components in @novu/js/ui\n */\nexport function Inbox() {}\nexport function Notifications() {}\nexport function Preferences() {}\nexport function Bell() {}\n\n//Hooks\nexport { NovuProvider } from './index';\nexport * from './hooks';\n"],"mappings":"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","names":["useEffect","useState","useState","useEffect","useEffect","useState","useEffect","useEffect","useState","useEffect","useState","useEffect"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@novu/react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"repository": "https://github.com/novuhq/novu",
|
|
5
5
|
"description": "Novu's React SDK for building custom inbox notification experiences",
|
|
6
6
|
"author": "",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"build:watch": "tsup --watch",
|
|
51
51
|
"build": "tsup && pnpm run check-exports",
|
|
52
52
|
"lint": "eslint src",
|
|
53
|
-
"check-exports": "attw --pack ."
|
|
53
|
+
"check-exports": "attw --pack .",
|
|
54
|
+
"release:preview": "pnpx pkg-pr-new publish"
|
|
54
55
|
},
|
|
55
56
|
"browserslist": {
|
|
56
57
|
"production": [
|
|
@@ -70,7 +71,7 @@
|
|
|
70
71
|
"@types/react": "*",
|
|
71
72
|
"@types/react-dom": "*",
|
|
72
73
|
"tsup": "^8.2.1",
|
|
73
|
-
"typescript": "
|
|
74
|
+
"typescript": "5.6.2"
|
|
74
75
|
},
|
|
75
76
|
"peerDependencies": {
|
|
76
77
|
"react": ">=17",
|
|
@@ -82,6 +83,6 @@
|
|
|
82
83
|
}
|
|
83
84
|
},
|
|
84
85
|
"dependencies": {
|
|
85
|
-
"@novu/js": "^2.
|
|
86
|
+
"@novu/js": "^2.2.0"
|
|
86
87
|
}
|
|
87
88
|
}
|