Audit module (MGN-007): - AuditLogsPage.tsx: Full audit logs UI with filtering, stats cards, detail modal - Uses existing types, api, hooks from settings feature Notifications module (MGN-008): - types/notifications.types.ts: Complete types for channels, templates, preferences, in-app - api/notifications.api.ts: API clients for all notification operations - hooks/useNotifications.ts: 5 hooks (useChannels, useTemplates, useNotificationPreferences, useInAppNotifications, useNotificationBell) - NotificationsPage.tsx: Full notifications center with category cards, filtering, read/unread management Both modules complement complete backends with comprehensive frontend UIs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
149 lines
5.5 KiB
TypeScript
149 lines
5.5 KiB
TypeScript
import { api } from '@services/api/axios-instance';
|
|
import type {
|
|
NotificationChannel,
|
|
NotificationTemplate,
|
|
NotificationTemplateCreateInput,
|
|
NotificationPreference,
|
|
NotificationPreferenceUpdateInput,
|
|
Notification,
|
|
NotificationCreateInput,
|
|
NotificationStatus,
|
|
InAppNotification,
|
|
InAppNotificationCreateInput,
|
|
InAppNotificationsFilters,
|
|
InAppNotificationsResponse,
|
|
} from '../types';
|
|
|
|
const NOTIFICATIONS_BASE = '/api/v1/notifications';
|
|
|
|
// ============================================================================
|
|
// Channels API
|
|
// ============================================================================
|
|
|
|
export const channelsApi = {
|
|
getAll: async (): Promise<NotificationChannel[]> => {
|
|
const response = await api.get<NotificationChannel[]>(`${NOTIFICATIONS_BASE}/channels`);
|
|
return response.data;
|
|
},
|
|
|
|
getByCode: async (code: string): Promise<NotificationChannel> => {
|
|
const response = await api.get<NotificationChannel>(`${NOTIFICATIONS_BASE}/channels/${code}`);
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Templates API
|
|
// ============================================================================
|
|
|
|
export const templatesApi = {
|
|
getAll: async (): Promise<NotificationTemplate[]> => {
|
|
const response = await api.get<NotificationTemplate[]>(`${NOTIFICATIONS_BASE}/templates`);
|
|
return response.data;
|
|
},
|
|
|
|
getByCode: async (code: string): Promise<NotificationTemplate> => {
|
|
const response = await api.get<NotificationTemplate>(`${NOTIFICATIONS_BASE}/templates/${code}`);
|
|
return response.data;
|
|
},
|
|
|
|
create: async (data: NotificationTemplateCreateInput): Promise<NotificationTemplate> => {
|
|
const response = await api.post<NotificationTemplate>(`${NOTIFICATIONS_BASE}/templates`, data);
|
|
return response.data;
|
|
},
|
|
|
|
update: async (id: string, data: Partial<NotificationTemplateCreateInput>): Promise<NotificationTemplate> => {
|
|
const response = await api.patch<NotificationTemplate>(`${NOTIFICATIONS_BASE}/templates/${id}`, data);
|
|
return response.data;
|
|
},
|
|
|
|
delete: async (id: string): Promise<void> => {
|
|
await api.delete(`${NOTIFICATIONS_BASE}/templates/${id}`);
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Preferences API
|
|
// ============================================================================
|
|
|
|
export const preferencesApi = {
|
|
get: async (): Promise<NotificationPreference> => {
|
|
const response = await api.get<NotificationPreference>(`${NOTIFICATIONS_BASE}/preferences`);
|
|
return response.data;
|
|
},
|
|
|
|
update: async (data: NotificationPreferenceUpdateInput): Promise<NotificationPreference> => {
|
|
const response = await api.patch<NotificationPreference>(`${NOTIFICATIONS_BASE}/preferences`, data);
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Notifications API
|
|
// ============================================================================
|
|
|
|
export const notificationsApi = {
|
|
create: async (data: NotificationCreateInput): Promise<Notification> => {
|
|
const response = await api.post<Notification>(`${NOTIFICATIONS_BASE}`, data);
|
|
return response.data;
|
|
},
|
|
|
|
getPending: async (limit = 50): Promise<Notification[]> => {
|
|
const response = await api.get<Notification[]>(`${NOTIFICATIONS_BASE}/pending?limit=${limit}`);
|
|
return response.data;
|
|
},
|
|
|
|
updateStatus: async (id: string, status: NotificationStatus, errorMessage?: string): Promise<Notification> => {
|
|
const response = await api.patch<Notification>(`${NOTIFICATIONS_BASE}/${id}/status`, {
|
|
status,
|
|
errorMessage,
|
|
});
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// In-App Notifications API
|
|
// ============================================================================
|
|
|
|
export const inAppApi = {
|
|
getAll: async (filters: InAppNotificationsFilters = {}): Promise<InAppNotificationsResponse> => {
|
|
const params = new URLSearchParams();
|
|
if (filters.includeRead !== undefined) params.append('include_read', String(filters.includeRead));
|
|
if (filters.category) params.append('category', filters.category);
|
|
if (filters.page) params.append('page', String(filters.page));
|
|
if (filters.limit) params.append('limit', String(filters.limit));
|
|
|
|
const response = await api.get<InAppNotificationsResponse>(`${NOTIFICATIONS_BASE}/in-app?${params}`);
|
|
return response.data;
|
|
},
|
|
|
|
getUnreadCount: async (): Promise<number> => {
|
|
const response = await api.get<{ count: number }>(`${NOTIFICATIONS_BASE}/in-app/unread-count`);
|
|
return response.data.count;
|
|
},
|
|
|
|
markAsRead: async (id: string): Promise<InAppNotification> => {
|
|
const response = await api.post<InAppNotification>(`${NOTIFICATIONS_BASE}/in-app/${id}/read`);
|
|
return response.data;
|
|
},
|
|
|
|
markAllAsRead: async (): Promise<void> => {
|
|
await api.post(`${NOTIFICATIONS_BASE}/in-app/read-all`);
|
|
},
|
|
|
|
create: async (data: InAppNotificationCreateInput): Promise<InAppNotification> => {
|
|
const response = await api.post<InAppNotification>(`${NOTIFICATIONS_BASE}/in-app`, data);
|
|
return response.data;
|
|
},
|
|
|
|
archive: async (id: string): Promise<InAppNotification> => {
|
|
const response = await api.post<InAppNotification>(`${NOTIFICATIONS_BASE}/in-app/${id}/archive`);
|
|
return response.data;
|
|
},
|
|
|
|
delete: async (id: string): Promise<void> => {
|
|
await api.delete(`${NOTIFICATIONS_BASE}/in-app/${id}`);
|
|
},
|
|
};
|