- Split frontend/src/lib/api.ts (2042 lines) into 12 focused domain modules: client.ts (base HTTP/auth), calendar.ts, documents.ts, employees.ts, equipment.ts, feed.ts, messages.ts, notifications.ts, procurement.ts, requests.ts, utils.ts, and index.ts barrel that preserves all existing imports - Extract calendar modal state from AppShell into useCalendarModals hook - Extract CalendarModals and MobileDrawers into components/layout/ - AppShell: 745 → 460 lines, focused on layout concerns only - Fix setState-in-effect lint error with startTransition pattern - Stabilize notifications memo to prevent unnecessary re-renders - Fix flaky WS test: handle CancelledError in channels-testing cleanup - All 609 backend tests pass, TypeScript typecheck clean, ESLint clean
38 lines
2.8 KiB
TypeScript
38 lines
2.8 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
import type { RequestFn } from './utils';
|
|
|
|
export function createNotificationsApi(request: RequestFn) {
|
|
return {
|
|
getNotifications: (params?: { page?: number; page_size?: number; unread_only?: boolean }) => {
|
|
const qp = new URLSearchParams();
|
|
if (params?.page) qp.append('page', String(params.page));
|
|
if (params?.page_size) qp.append('page_size', String(params.page_size));
|
|
if (params?.unread_only) qp.append('unread_only', 'true');
|
|
const qs = qp.toString();
|
|
return request(qs ? `/api/v1/notifications/?${qs}` : '/api/v1/notifications/');
|
|
},
|
|
getUnreadNotificationsCount: (): Promise<{ count: number }> => request('/api/v1/notifications/count/'),
|
|
markNotificationAsRead: (id: number): Promise<void> => request(`/api/v1/notifications/${id}/read/`, { method: 'POST' }),
|
|
markAllNotificationsAsRead: (): Promise<void> => request('/api/v1/notifications/read-all/', { method: 'POST' }),
|
|
markCategoryAsRead: async (category: string): Promise<{ status: string; count: number }> => {
|
|
const { getVerbsByCategory } = await import('../verbTranslations');
|
|
const verbs = getVerbsByCategory(category);
|
|
return request('/api/v1/notifications/category/read/', { method: 'POST', body: JSON.stringify({ verbs, category }) });
|
|
},
|
|
// Push
|
|
getVapidPublicKey: (): Promise<{ vapid_public_key: string }> => request('/api/v1/notifications/push/vapid-key/'),
|
|
subscribePush: (data: { endpoint: string; keys: { p256dh: string; auth: string }; device_name?: string }): Promise<{ status: string; message: string; created: boolean }> =>
|
|
request('/api/v1/notifications/push/subscribe/', { method: 'POST', body: JSON.stringify(data) }),
|
|
unsubscribePush: (endpoint?: string): Promise<{ status: string; message: string }> =>
|
|
request('/api/v1/notifications/push/unsubscribe/', { method: 'DELETE', body: JSON.stringify({ endpoint }) }),
|
|
getPushSubscriptions: (): Promise<{ subscriptions: any[] }> => request('/api/v1/notifications/push/subscriptions/'),
|
|
// CRUD
|
|
deleteNotification: (id: number): Promise<void> => request(`/api/v1/notifications/${id}/`, { method: 'DELETE' }),
|
|
deleteAllReadNotifications: (): Promise<{ status: string; count: number }> => request('/api/v1/notifications/delete-all-read/', { method: 'DELETE' }),
|
|
// Preferences
|
|
getNotificationPreferences: () => request('/api/v1/notifications/preferences/'),
|
|
updateNotificationPreferences: (data: Record<string, any>) => request('/api/v1/notifications/preferences/', { method: 'PUT', body: JSON.stringify(data) }),
|
|
getVerbTypes: (): Promise<{ verb_types: any[] }> => request('/api/v1/notifications/verb-types/'),
|
|
};
|
|
}
|