mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 08:33:36 +00:00
- Added Notification Service to manage project-level notifications, including creation, listing, marking as read, and dismissing notifications. - Introduced Event History Service to store and manage historical events, allowing for listing, retrieval, deletion, and replaying of events. - Integrated notifications into the server and UI, providing real-time updates for feature statuses and operations. - Enhanced sidebar and project switcher components to display unread notifications count. - Created dedicated views for managing notifications and event history, improving user experience and accessibility. These changes enhance the application's ability to inform users about important events and statuses, improving overall usability and responsiveness.
130 lines
3.7 KiB
TypeScript
130 lines
3.7 KiB
TypeScript
/**
|
|
* Notifications Store - State management for project-level notifications
|
|
*/
|
|
|
|
import { create } from 'zustand';
|
|
import type { Notification } from '@automaker/types';
|
|
|
|
// ============================================================================
|
|
// State Interface
|
|
// ============================================================================
|
|
|
|
interface NotificationsState {
|
|
// Notifications for the current project
|
|
notifications: Notification[];
|
|
unreadCount: number;
|
|
isLoading: boolean;
|
|
error: string | null;
|
|
|
|
// Popover state
|
|
isPopoverOpen: boolean;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Actions Interface
|
|
// ============================================================================
|
|
|
|
interface NotificationsActions {
|
|
// Data management
|
|
setNotifications: (notifications: Notification[]) => void;
|
|
setUnreadCount: (count: number) => void;
|
|
addNotification: (notification: Notification) => void;
|
|
markAsRead: (notificationId: string) => void;
|
|
markAllAsRead: () => void;
|
|
dismissNotification: (notificationId: string) => void;
|
|
dismissAll: () => void;
|
|
|
|
// Loading state
|
|
setLoading: (loading: boolean) => void;
|
|
setError: (error: string | null) => void;
|
|
|
|
// Popover state
|
|
setPopoverOpen: (open: boolean) => void;
|
|
|
|
// Reset
|
|
reset: () => void;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Initial State
|
|
// ============================================================================
|
|
|
|
const initialState: NotificationsState = {
|
|
notifications: [],
|
|
unreadCount: 0,
|
|
isLoading: false,
|
|
error: null,
|
|
isPopoverOpen: false,
|
|
};
|
|
|
|
// ============================================================================
|
|
// Store
|
|
// ============================================================================
|
|
|
|
export const useNotificationsStore = create<NotificationsState & NotificationsActions>(
|
|
(set, get) => ({
|
|
...initialState,
|
|
|
|
// Data management
|
|
setNotifications: (notifications) =>
|
|
set({
|
|
notifications,
|
|
unreadCount: notifications.filter((n) => !n.read).length,
|
|
}),
|
|
|
|
setUnreadCount: (count) => set({ unreadCount: count }),
|
|
|
|
addNotification: (notification) =>
|
|
set((state) => ({
|
|
notifications: [notification, ...state.notifications],
|
|
unreadCount: notification.read ? state.unreadCount : state.unreadCount + 1,
|
|
})),
|
|
|
|
markAsRead: (notificationId) =>
|
|
set((state) => {
|
|
const notification = state.notifications.find((n) => n.id === notificationId);
|
|
if (!notification || notification.read) return state;
|
|
|
|
return {
|
|
notifications: state.notifications.map((n) =>
|
|
n.id === notificationId ? { ...n, read: true } : n
|
|
),
|
|
unreadCount: Math.max(0, state.unreadCount - 1),
|
|
};
|
|
}),
|
|
|
|
markAllAsRead: () =>
|
|
set((state) => ({
|
|
notifications: state.notifications.map((n) => ({ ...n, read: true })),
|
|
unreadCount: 0,
|
|
})),
|
|
|
|
dismissNotification: (notificationId) =>
|
|
set((state) => {
|
|
const notification = state.notifications.find((n) => n.id === notificationId);
|
|
if (!notification) return state;
|
|
|
|
return {
|
|
notifications: state.notifications.filter((n) => n.id !== notificationId),
|
|
unreadCount: notification.read ? state.unreadCount : Math.max(0, state.unreadCount - 1),
|
|
};
|
|
}),
|
|
|
|
dismissAll: () =>
|
|
set({
|
|
notifications: [],
|
|
unreadCount: 0,
|
|
}),
|
|
|
|
// Loading state
|
|
setLoading: (loading) => set({ isLoading: loading }),
|
|
setError: (error) => set({ error }),
|
|
|
|
// Popover state
|
|
setPopoverOpen: (open) => set({ isPopoverOpen: open }),
|
|
|
|
// Reset
|
|
reset: () => set(initialState),
|
|
})
|
|
);
|