Skip to content

Commit

Permalink
bring back hook
Browse files Browse the repository at this point in the history
  • Loading branch information
BiswaViraj committed Jan 16, 2025
1 parent d0c423d commit 09c2521
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 1 deletion.
1 change: 0 additions & 1 deletion packages/react/src/context/RendererContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import type { NovuUI } from '@novu/js/ui';
import { createContextAndHook } from '../utils/createContextAndHook';

export type MountedElement = React.ReactNode;
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './useNotifications';
export * from './usePreferences';
export * from './useCounts';
export { NovuProvider, useNovu } from './NovuProvider';
106 changes: 106 additions & 0 deletions packages/react/src/hooks/useCounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { useEffect, useState } from 'react';
import { Notification, NotificationFilter, NovuError, areTagsEqual } from '@novu/js';
import { useNovu } from './NovuProvider';
import { useWebSocketEvent } from './internal/useWebsocketEvent';

type Count = {
count: number;
filter: NotificationFilter;
};

type UseCountsProps = {
filters: NotificationFilter[];
onSuccess?: (data: Count[]) => void;
onError?: (error: NovuError) => void;
};

type UseCountsResult = {
counts?: Count[];
error?: NovuError;
isLoading: boolean; // initial loading
isFetching: boolean; // the request is in flight
refetch: () => Promise<void>;
};

export const useCounts = (props: UseCountsProps): UseCountsResult => {
const { filters, onSuccess, onError } = props;
const { notifications } = useNovu();
const [error, setError] = useState<NovuError>();
const [counts, setCounts] = useState<Count[]>();
const [isLoading, setIsLoading] = useState(true);
const [isFetching, setIsFetching] = useState(false);

const sync = async (notification?: Notification) => {
const existingCounts = counts ?? (new Array(filters.length).fill(undefined) as (Count | undefined)[]);
let countFiltersToFetch: NotificationFilter[] = [];
if (notification) {
// eslint-disable-next-line no-plusplus
for (let i = 0; i < existingCounts.length; i++) {
const filter = filters[i];
if (areTagsEqual(filter.tags, notification.tags)) {
countFiltersToFetch.push(filter);
}
}
} else {
countFiltersToFetch = filters;
}

if (countFiltersToFetch.length === 0) {
return;
}

setIsFetching(true);
const countsRes = await notifications.count({ filters: countFiltersToFetch });
setIsFetching(false);
setIsLoading(false);
if (countsRes.error) {
setError(countsRes.error);
onError?.(countsRes.error);

return;
}
const data = countsRes.data!;
onSuccess?.(data.counts);

setCounts((oldCounts) => {
const newCounts: Count[] = [];
const countsReceived = data.counts;

// eslint-disable-next-line no-plusplus
for (let i = 0; i < existingCounts.length; i++) {
const countReceived = countsReceived.find((c) => areTagsEqual(c.filter.tags, existingCounts[i]?.filter.tags));

newCounts.push(countReceived || oldCounts![i]);
}

return newCounts;
});
};

useWebSocketEvent({
event: 'notifications.notification_received',
eventHandler: (data) => {
sync(data.result);
},
});

useWebSocketEvent({
event: 'notifications.unread_count_changed',
eventHandler: () => {
sync();
},
});

useEffect(() => {
setError(undefined);
setIsLoading(true);
setIsFetching(false);
sync();
}, [JSON.stringify(filters)]);

const refetch = async () => {
await sync();
};

return { counts, error, refetch, isLoading, isFetching };
};

0 comments on commit 09c2521

Please sign in to comment.