From 6d2ad2089c99d188cee7067939b6b57fdc1b80f9 Mon Sep 17 00:00:00 2001 From: Chii Yuen Date: Wed, 24 Sep 2025 18:23:47 +0800 Subject: [PATCH 1/3] feat: add useClearHistory hook --- packages/react-sdk/src/hooks/index.ts | 1 + .../react-sdk/src/hooks/useClearHistory.ts | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 packages/react-sdk/src/hooks/useClearHistory.ts diff --git a/packages/react-sdk/src/hooks/index.ts b/packages/react-sdk/src/hooks/index.ts index 2e429dc5..051e3896 100644 --- a/packages/react-sdk/src/hooks/index.ts +++ b/packages/react-sdk/src/hooks/index.ts @@ -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'; diff --git a/packages/react-sdk/src/hooks/useClearHistory.ts b/packages/react-sdk/src/hooks/useClearHistory.ts new file mode 100644 index 00000000..26ee5552 --- /dev/null +++ b/packages/react-sdk/src/hooks/useClearHistory.ts @@ -0,0 +1,45 @@ +import useSWRMutation from 'swr/mutation'; +import { useDialectContext } from '../context'; +import { getRequestHeaders } from './internal/api-v2-helpers'; +import { CACHE_KEY_READ_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_READ_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; + }, + ); + + return { + clear: trigger, + isLoading: isMutating, + error, + }; +} From a62eb37d01011899d932eb5444d122149c0b6026 Mon Sep 17 00:00:00 2001 From: Chii Yuen Date: Wed, 24 Sep 2025 18:24:48 +0800 Subject: [PATCH 2/3] feat: add clear history button --- packages/react-ui/src/ui/core/Header.tsx | 17 +++++++++++++++++ .../NotificationsFeed/NotificationsFeed.tsx | 4 +++- .../NotificationsFeedHeader.tsx | 7 +++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/react-ui/src/ui/core/Header.tsx b/packages/react-ui/src/ui/core/Header.tsx index 26831364..654dad95 100644 --- a/packages/react-ui/src/ui/core/Header.tsx +++ b/packages/react-ui/src/ui/core/Header.tsx @@ -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; } @@ -23,6 +25,16 @@ const BackButton: React.FC<{ onBackClick: HeaderProps['onBackClick'] }> = ({ /> ); +const ClearNotificationsButton: React.FC<{ onClearNotificationsClick: HeaderProps['onClearNotificationsClick'] }> = ({ + onClearNotificationsClick, +}) => ( + } + /> +); + const SettingsButton: React.FC<{ onSettingsClick: HeaderProps['onSettingsClick']; }> = ({ onSettingsClick }) => ( @@ -48,9 +60,11 @@ export function Header({ showCloseButton = true, showSettingsButton = true, showBackButton = true, + showClearNotificationsButton = false, onSettingsClick, onBackClick, onCloseClick, + onClearNotificationsClick, }: HeaderProps) { const leftButtons = ( <>{showBackButton && } @@ -58,6 +72,9 @@ export function Header({ const rightButtons = (
+ {showClearNotificationsButton && ( + + )} {showSettingsButton && ( )} diff --git a/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeed.tsx b/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeed.tsx index 3d274be4..0a3ee32e 100644 --- a/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeed.tsx +++ b/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeed.tsx @@ -1,4 +1,5 @@ import { + useClearHistory, useHistory, useReadHistory, useSubscribe, @@ -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, @@ -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(() => { diff --git a/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeedHeader.tsx b/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeedHeader.tsx index 6d1ae74d..ce45372b 100644 --- a/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeedHeader.tsx +++ b/packages/react-ui/src/ui/notifications/NotificationsFeed/NotificationsFeedHeader.tsx @@ -1,3 +1,4 @@ +import { useClearHistory, useHistory } from '@dialectlabs/react-sdk'; import { Header } from '../../core'; import { useExternalProps } from '../internal/ExternalPropsProvider'; import { Route, useRouter } from '../internal/Router'; @@ -5,6 +6,8 @@ import { Route, useRouter } from '../internal/Router'; export const NotificationsFeedHeader = () => { const { setOpen } = useExternalProps(); const { setRoute } = useRouter(); + const { clear } = useClearHistory(); + const { refresh } = useHistory(); return (
{ showBackButton={false} showSettingsButton={true} showCloseButton={!!setOpen} + showClearNotificationsButton={true} onSettingsClick={() => setRoute(Route.Settings)} onCloseClick={() => setOpen?.(false)} + onClearNotificationsClick={() => { + clear().then(() => refresh()); + }} /> ); }; From e4a5da1fbf1927de88d8afc04effc01861774f79 Mon Sep 17 00:00:00 2001 From: Chii Yuen Date: Sat, 27 Sep 2025 01:04:52 +0800 Subject: [PATCH 3/3] fix: add separate cache key for useClearHistory --- packages/react-sdk/src/hooks/internal/swrCache.ts | 5 +++++ packages/react-sdk/src/hooks/useClearHistory.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/react-sdk/src/hooks/internal/swrCache.ts b/packages/react-sdk/src/hooks/internal/swrCache.ts index 6adccb67..f7ad6303 100644 --- a/packages/react-sdk/src/hooks/internal/swrCache.ts +++ b/packages/react-sdk/src/hooks/internal/swrCache.ts @@ -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'; diff --git a/packages/react-sdk/src/hooks/useClearHistory.ts b/packages/react-sdk/src/hooks/useClearHistory.ts index 26ee5552..f7324cf2 100644 --- a/packages/react-sdk/src/hooks/useClearHistory.ts +++ b/packages/react-sdk/src/hooks/useClearHistory.ts @@ -1,7 +1,7 @@ import useSWRMutation from 'swr/mutation'; import { useDialectContext } from '../context'; import { getRequestHeaders } from './internal/api-v2-helpers'; -import { CACHE_KEY_READ_MUTATION } from './internal/swrCache'; +import { CACHE_KEY_CLEAR_MUTATION } from './internal/swrCache'; import useDialectSdk from './useDialectSdk'; export default function useClearHistory() { @@ -12,7 +12,7 @@ export default function useClearHistory() { const sdk = useDialectSdk(); const { trigger, isMutating, error } = useSWRMutation( - appId && clientKey ? CACHE_KEY_READ_MUTATION(appId) : null, + appId && clientKey ? CACHE_KEY_CLEAR_MUTATION(appId) : null, async () => { if (!appId || !clientKey) { return;