mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-14 17:41:22 +08:00
233 lines
6.8 KiB
TypeScript
233 lines
6.8 KiB
TypeScript
// ========================================
|
|
// useNotifications Hook
|
|
// ========================================
|
|
// Convenient hook for notification and toast management
|
|
|
|
import { useCallback } from 'react';
|
|
import {
|
|
useNotificationStore,
|
|
selectToasts,
|
|
selectWsStatus,
|
|
selectWsLastMessage,
|
|
selectIsPanelVisible,
|
|
selectPersistentNotifications,
|
|
} from '../stores/notificationStore';
|
|
import type { Toast, ToastType, WebSocketStatus, WebSocketMessage } from '../types/store';
|
|
|
|
export interface UseNotificationsReturn {
|
|
/** Current toast queue */
|
|
toasts: Toast[];
|
|
/** WebSocket connection status */
|
|
wsStatus: WebSocketStatus;
|
|
/** Last WebSocket message received */
|
|
wsLastMessage: WebSocketMessage | null;
|
|
/** Whether WebSocket is connected */
|
|
isWsConnected: boolean;
|
|
/** Whether notification panel is visible */
|
|
isPanelVisible: boolean;
|
|
/** Persistent notifications (stored in localStorage) */
|
|
persistentNotifications: Toast[];
|
|
/** Add a toast notification */
|
|
addToast: (type: ToastType, title: string, message?: string, options?: ToastOptions) => string;
|
|
/** Show info toast */
|
|
info: (title: string, message?: string) => string;
|
|
/** Show success toast */
|
|
success: (title: string, message?: string) => string;
|
|
/** Show warning toast */
|
|
warning: (title: string, message?: string) => string;
|
|
/** Show error toast (persistent by default) */
|
|
error: (title: string, message?: string) => string;
|
|
/** Remove a toast */
|
|
removeToast: (id: string) => void;
|
|
/** Clear all toasts */
|
|
clearAllToasts: () => void;
|
|
/** Set WebSocket status */
|
|
setWsStatus: (status: WebSocketStatus) => void;
|
|
/** Set last WebSocket message */
|
|
setWsLastMessage: (message: WebSocketMessage | null) => void;
|
|
/** Toggle notification panel */
|
|
togglePanel: () => void;
|
|
/** Set panel visibility */
|
|
setPanelVisible: (visible: boolean) => void;
|
|
/** Add persistent notification */
|
|
addPersistentNotification: (type: ToastType, title: string, message?: string) => void;
|
|
/** Remove persistent notification */
|
|
removePersistentNotification: (id: string) => void;
|
|
/** Clear all persistent notifications */
|
|
clearPersistentNotifications: () => void;
|
|
}
|
|
|
|
export interface ToastOptions {
|
|
/** Duration in ms (0 = persistent) */
|
|
duration?: number;
|
|
/** Whether toast can be dismissed */
|
|
dismissible?: boolean;
|
|
/** Action button */
|
|
action?: {
|
|
label: string;
|
|
onClick: () => void;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Hook for managing notifications and toasts
|
|
* @returns Notification state and actions
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* const { toasts, info, success, error, removeToast } = useNotifications();
|
|
*
|
|
* const handleSave = async () => {
|
|
* try {
|
|
* await save();
|
|
* success('Saved', 'Your changes have been saved');
|
|
* } catch (e) {
|
|
* error('Error', 'Failed to save changes');
|
|
* }
|
|
* };
|
|
* ```
|
|
*/
|
|
export function useNotifications(): UseNotificationsReturn {
|
|
const toasts = useNotificationStore(selectToasts);
|
|
const wsStatus = useNotificationStore(selectWsStatus);
|
|
const wsLastMessage = useNotificationStore(selectWsLastMessage);
|
|
const isPanelVisible = useNotificationStore(selectIsPanelVisible);
|
|
const persistentNotifications = useNotificationStore(selectPersistentNotifications);
|
|
|
|
// Actions
|
|
const addToastAction = useNotificationStore((state) => state.addToast);
|
|
const removeToastAction = useNotificationStore((state) => state.removeToast);
|
|
const clearAllToastsAction = useNotificationStore((state) => state.clearAllToasts);
|
|
const setWsStatusAction = useNotificationStore((state) => state.setWsStatus);
|
|
const setWsLastMessageAction = useNotificationStore((state) => state.setWsLastMessage);
|
|
const togglePanelAction = useNotificationStore((state) => state.togglePanel);
|
|
const setPanelVisibleAction = useNotificationStore((state) => state.setPanelVisible);
|
|
const addPersistentAction = useNotificationStore((state) => state.addPersistentNotification);
|
|
const removePersistentAction = useNotificationStore((state) => state.removePersistentNotification);
|
|
const clearPersistentAction = useNotificationStore((state) => state.clearPersistentNotifications);
|
|
|
|
// Computed
|
|
const isWsConnected = wsStatus === 'connected';
|
|
|
|
// Callbacks
|
|
const addToast = useCallback(
|
|
(type: ToastType, title: string, message?: string, options?: ToastOptions): string => {
|
|
return addToastAction({
|
|
type,
|
|
title,
|
|
message,
|
|
duration: options?.duration,
|
|
dismissible: options?.dismissible,
|
|
action: options?.action,
|
|
});
|
|
},
|
|
[addToastAction]
|
|
);
|
|
|
|
const info = useCallback(
|
|
(title: string, message?: string): string => {
|
|
return addToast('info', title, message);
|
|
},
|
|
[addToast]
|
|
);
|
|
|
|
const success = useCallback(
|
|
(title: string, message?: string): string => {
|
|
return addToast('success', title, message);
|
|
},
|
|
[addToast]
|
|
);
|
|
|
|
const warning = useCallback(
|
|
(title: string, message?: string): string => {
|
|
return addToast('warning', title, message);
|
|
},
|
|
[addToast]
|
|
);
|
|
|
|
const error = useCallback(
|
|
(title: string, message?: string): string => {
|
|
// Error toasts are persistent by default
|
|
return addToast('error', title, message, { duration: 0 });
|
|
},
|
|
[addToast]
|
|
);
|
|
|
|
const removeToast = useCallback(
|
|
(id: string) => {
|
|
removeToastAction(id);
|
|
},
|
|
[removeToastAction]
|
|
);
|
|
|
|
const clearAllToasts = useCallback(() => {
|
|
clearAllToastsAction();
|
|
}, [clearAllToastsAction]);
|
|
|
|
const setWsStatus = useCallback(
|
|
(status: WebSocketStatus) => {
|
|
setWsStatusAction(status);
|
|
},
|
|
[setWsStatusAction]
|
|
);
|
|
|
|
const setWsLastMessage = useCallback(
|
|
(message: WebSocketMessage | null) => {
|
|
setWsLastMessageAction(message);
|
|
},
|
|
[setWsLastMessageAction]
|
|
);
|
|
|
|
const togglePanel = useCallback(() => {
|
|
togglePanelAction();
|
|
}, [togglePanelAction]);
|
|
|
|
const setPanelVisible = useCallback(
|
|
(visible: boolean) => {
|
|
setPanelVisibleAction(visible);
|
|
},
|
|
[setPanelVisibleAction]
|
|
);
|
|
|
|
const addPersistentNotification = useCallback(
|
|
(type: ToastType, title: string, message?: string) => {
|
|
addPersistentAction({ type, title, message });
|
|
},
|
|
[addPersistentAction]
|
|
);
|
|
|
|
const removePersistentNotification = useCallback(
|
|
(id: string) => {
|
|
removePersistentAction(id);
|
|
},
|
|
[removePersistentAction]
|
|
);
|
|
|
|
const clearPersistentNotifications = useCallback(() => {
|
|
clearPersistentAction();
|
|
}, [clearPersistentAction]);
|
|
|
|
return {
|
|
toasts,
|
|
wsStatus,
|
|
wsLastMessage,
|
|
isWsConnected,
|
|
isPanelVisible,
|
|
persistentNotifications,
|
|
addToast,
|
|
info,
|
|
success,
|
|
warning,
|
|
error,
|
|
removeToast,
|
|
clearAllToasts,
|
|
setWsStatus,
|
|
setWsLastMessage,
|
|
togglePanel,
|
|
setPanelVisible,
|
|
addPersistentNotification,
|
|
removePersistentNotification,
|
|
clearPersistentNotifications,
|
|
};
|
|
}
|