Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/react-sdk/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type {
HistoricalAlert,
History,
} from './useHistory';
export { default as useClearHistory } from './useClearHistory';
export { default as useReadHistory } from './useReadHistory';
export { default as useSubscribe } from './useSubscribe';
export { default as useUnreadSummary } from './useUnreadSummary';
Expand Down
5 changes: 5 additions & 0 deletions packages/react-sdk/src/hooks/internal/swrCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export const CACHE_KEY_READ_MUTATION = (appId: string) => [
appId,
];

export const CACHE_KEY_CLEAR_MUTATION = (appId: string) => [
'CLEAR_HISTORY',
appId,
];

// v1 cache keys

export const CACHE_KEY_THREADS = 'THREADS';
Expand Down
45 changes: 45 additions & 0 deletions packages/react-sdk/src/hooks/useClearHistory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import useSWRMutation from 'swr/mutation';
import { useDialectContext } from '../context';
import { getRequestHeaders } from './internal/api-v2-helpers';
import { CACHE_KEY_CLEAR_MUTATION } from './internal/swrCache';
import useDialectSdk from './useDialectSdk';

export default function useClearHistory() {
const {
clientKey,
app: { id: appId },
} = useDialectContext();
const sdk = useDialectSdk();

const { trigger, isMutating, error } = useSWRMutation(
appId && clientKey ? CACHE_KEY_CLEAR_MUTATION(appId) : null,
async () => {
if (!appId || !clientKey) {
return;
}

const response = await fetch(
`${sdk.config.dialectCloud.v2Url}/v2/history/clear`,
{
method: 'POST',
body: JSON.stringify({
appId,
}),
headers: await getRequestHeaders(sdk, clientKey),
},
);

if (!response.ok) {
throw await response.json();
}

return response.json() as Promise<void>;
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type casting is incorrect. response.json() returns Promise<any>, but you're casting it as Promise<void>. Since the API likely returns some response data, either remove the type assertion or change it to Promise<any> or the actual expected response type.

Suggested change
return response.json() as Promise<void>;
return response.json();

Copilot uses AI. Check for mistakes.

},
);

return {
clear: trigger,
isLoading: isMutating,
error,
};
}
17 changes: 17 additions & 0 deletions packages/react-ui/src/ui/core/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import { IconButton } from './primitives';
interface HeaderProps {
title: string;
showBackButton: boolean;
showClearNotificationsButton?: boolean;
showSettingsButton: boolean;
showCloseButton: boolean;
onBackClick?: () => void;
onClearNotificationsClick?: () => void;
onSettingsClick?: () => void;
onCloseClick?: () => void;
}
Expand All @@ -23,6 +25,16 @@ const BackButton: React.FC<{ onBackClick: HeaderProps['onBackClick'] }> = ({
/>
);

const ClearNotificationsButton: React.FC<{ onClearNotificationsClick: HeaderProps['onClearNotificationsClick'] }> = ({
onClearNotificationsClick,
}) => (
<IconButton
className={ClassTokens.Icon.Secondary}
onClick={onClearNotificationsClick}
icon={<Icons.Trash />}
/>
);

const SettingsButton: React.FC<{
onSettingsClick: HeaderProps['onSettingsClick'];
}> = ({ onSettingsClick }) => (
Expand All @@ -48,16 +60,21 @@ export function Header({
showCloseButton = true,
showSettingsButton = true,
showBackButton = true,
showClearNotificationsButton = false,
onSettingsClick,
onBackClick,
onCloseClick,
onClearNotificationsClick,
}: HeaderProps) {
const leftButtons = (
<>{showBackButton && <BackButton onBackClick={onBackClick} />}</>
);

const rightButtons = (
<div className="dt-flex dt-gap-3">
{showClearNotificationsButton && (
<ClearNotificationsButton onClearNotificationsClick={onClearNotificationsClick} />
)}
{showSettingsButton && (
<SettingsButton onSettingsClick={onSettingsClick} />
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
useClearHistory,
useHistory,
useReadHistory,
useSubscribe,
Expand Down Expand Up @@ -45,6 +46,7 @@ NotificationsFeed.Container = function NotificationsFeeContainer() {
const { isLoading: isSubscribeLoading, error: subscribeError } =
useSubscribe();
const { read } = useReadHistory();
const { error: clearError } = useClearHistory();
const { refresh: refreshSummary } = useUnreadSummary({
revalidateOnMount: false,
revalidateOnFocus: false,
Expand All @@ -54,7 +56,7 @@ NotificationsFeed.Container = function NotificationsFeeContainer() {
const notificationsCount = notifications.length;

const isLoading = isHistoryLoading || isSubscribeLoading;
const hasError = !!subscribeError || !!historyError;
const hasError = !!subscribeError || !!historyError || !!clearError;
const isEmpty = notificationsCount === 0;

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { useClearHistory, useHistory } from '@dialectlabs/react-sdk';
import { Header } from '../../core';
import { useExternalProps } from '../internal/ExternalPropsProvider';
import { Route, useRouter } from '../internal/Router';

export const NotificationsFeedHeader = () => {
const { setOpen } = useExternalProps();
const { setRoute } = useRouter();
const { clear } = useClearHistory();
const { refresh } = useHistory();

return (
<Header
title="Notifications"
showBackButton={false}
showSettingsButton={true}
showCloseButton={!!setOpen}
showClearNotificationsButton={true}
onSettingsClick={() => setRoute(Route.Settings)}
onCloseClick={() => setOpen?.(false)}
onClearNotificationsClick={() => {
clear().then(() => refresh());
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for the clear operation. If clear() fails, the promise chain will be rejected but there's no catch handler to prevent unhandled promise rejection.

Suggested change
clear().then(() => refresh());
clear()
.then(() => refresh())
.catch((err) => {
console.error('Failed to clear notifications:', err);
});

Copilot uses AI. Check for mistakes.

}}
/>
);
};