@pfm-platform/notifications-data-access 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,25 +2,15 @@
2
2
 
3
3
  var reactQuery = require('@tanstack/react-query');
4
4
  var shared = require('@pfm-platform/shared');
5
- var axios = require('axios');
6
-
7
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
-
9
- var axios__default = /*#__PURE__*/_interopDefault(axios);
10
5
 
11
6
  // src/queries/useNotifications.ts
12
- var api = axios__default.default.create({
13
- baseURL: "/api",
14
- headers: {
15
- "Content-Type": "application/json"
16
- }
17
- });
18
7
 
19
8
  // src/keys.ts
20
9
  var notificationKeys = {
21
10
  all: ["notifications"],
22
11
  lists: () => [...notificationKeys.all, "list"],
23
- list: (userId) => [...notificationKeys.lists(), userId]
12
+ list: (userId) => [...notificationKeys.lists(), userId],
13
+ preferences: (userId) => [...notificationKeys.all, "preferences", userId]
24
14
  };
25
15
 
26
16
  // src/queries/useNotifications.ts
@@ -28,27 +18,45 @@ function useNotifications({ userId }, options) {
28
18
  return reactQuery.useQuery({
29
19
  queryKey: notificationKeys.list(userId),
30
20
  queryFn: async () => {
31
- const response = await api.get(`/users/${userId}/alerts/notifications`);
32
- const validated = shared.NotificationsResponseSchema.parse(response.data);
33
- return validated.notifications;
21
+ const { data, error } = await shared.supabase.from("notifications").select("*").eq("user_id", userId).order("created_at", { ascending: false });
22
+ if (error) throw new Error(error.message);
23
+ return shared.NotificationsResponseSchema.parse(data);
34
24
  },
35
25
  staleTime: 1e3 * 60 * 2,
36
26
  // 2 minutes (notifications change frequently)
37
27
  ...options
38
28
  });
39
29
  }
30
+ function useNotificationPreferences({ userId }, options) {
31
+ return reactQuery.useQuery({
32
+ queryKey: notificationKeys.preferences(userId),
33
+ queryFn: async () => {
34
+ const { data, error } = await shared.supabase.from("notification_preferences").select("*").eq("user_id", userId).single();
35
+ if (error) throw new Error(error.message);
36
+ const row = shared.NotificationPreferencesRowSchema.parse(data);
37
+ return {
38
+ emailNotifications: row.email_notifications,
39
+ pushNotifications: row.push_notifications,
40
+ frequency: row.frequency
41
+ };
42
+ },
43
+ staleTime: 1e3 * 60 * 5,
44
+ // 5 minutes (preferences change infrequently)
45
+ ...options
46
+ });
47
+ }
40
48
  function useCreateNotification(options) {
41
49
  const queryClient = reactQuery.useQueryClient();
42
- const { mode } = shared.useAppMode();
43
50
  return reactQuery.useMutation({
44
51
  mutationFn: async ({ userId, data }) => {
45
- const schema = mode === "admin" ? shared.NotificationCreateSchemaAdmin : shared.NotificationCreateSchemaUser;
46
- const validated = schema.parse(data);
47
- const response = await api.post(
48
- `/users/${userId}/alerts/notifications`,
49
- validated
50
- );
51
- return shared.NotificationSchema.parse(response.data);
52
+ const { data: row, error } = await shared.supabase.from("notifications").insert({
53
+ user_id: userId,
54
+ message: data.message,
55
+ alert_type: data.alert_type,
56
+ ...data.created_at ? { created_at: data.created_at } : {}
57
+ }).select().single();
58
+ if (error) throw new Error(error.message);
59
+ return shared.NotificationRowSchema.parse(row);
52
60
  },
53
61
  onSuccess: (_, { userId }) => {
54
62
  queryClient.invalidateQueries({
@@ -60,20 +68,15 @@ function useCreateNotification(options) {
60
68
  }
61
69
  function useUpdateNotification(options) {
62
70
  const queryClient = reactQuery.useQueryClient();
63
- const { mode } = shared.useAppMode();
64
71
  return reactQuery.useMutation({
65
72
  mutationFn: async ({
66
73
  userId,
67
74
  notificationId,
68
75
  data
69
76
  }) => {
70
- const schema = mode === "admin" ? shared.NotificationUpdateSchemaAdmin : shared.NotificationUpdateSchemaUser;
71
- const validated = schema.parse(data);
72
- const response = await api.put(
73
- `/users/${userId}/alerts/notifications/${notificationId}`,
74
- validated
75
- );
76
- return shared.NotificationSchema.parse(response.data);
77
+ const { data: row, error } = await shared.supabase.from("notifications").update(data).eq("id", notificationId).eq("user_id", userId).select().single();
78
+ if (error) throw new Error(error.message);
79
+ return shared.NotificationRowSchema.parse(row);
77
80
  },
78
81
  onSuccess: (_, { userId }) => {
79
82
  queryClient.invalidateQueries({
@@ -87,7 +90,8 @@ function useDeleteNotification(options) {
87
90
  const queryClient = reactQuery.useQueryClient();
88
91
  return reactQuery.useMutation({
89
92
  mutationFn: async ({ userId, notificationId }) => {
90
- await api.delete(`/users/${userId}/alerts/notifications/${notificationId}`);
93
+ const { error } = await shared.supabase.from("notifications").delete().eq("id", notificationId).eq("user_id", userId);
94
+ if (error) throw new Error(error.message);
91
95
  },
92
96
  onSuccess: (_, { userId }) => {
93
97
  queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });
@@ -95,12 +99,42 @@ function useDeleteNotification(options) {
95
99
  ...options
96
100
  });
97
101
  }
102
+ function useUpdateNotificationPreferences(options) {
103
+ const queryClient = reactQuery.useQueryClient();
104
+ return reactQuery.useMutation({
105
+ mutationFn: async ({ userId, data }) => {
106
+ const dbData = { user_id: userId };
107
+ if (data.emailNotifications !== void 0) {
108
+ dbData.email_notifications = data.emailNotifications;
109
+ }
110
+ if (data.pushNotifications !== void 0) {
111
+ dbData.push_notifications = data.pushNotifications;
112
+ }
113
+ if (data.frequency !== void 0) {
114
+ dbData.frequency = data.frequency;
115
+ }
116
+ const { data: row, error } = await shared.supabase.from("notification_preferences").upsert(dbData).select().single();
117
+ if (error) throw new Error(error.message);
118
+ const validated = shared.NotificationPreferencesRowSchema.parse(row);
119
+ return {
120
+ emailNotifications: validated.email_notifications,
121
+ pushNotifications: validated.push_notifications,
122
+ frequency: validated.frequency
123
+ };
124
+ },
125
+ onSuccess: (_, { userId }) => {
126
+ queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });
127
+ },
128
+ ...options
129
+ });
130
+ }
98
131
 
99
- exports.api = api;
100
132
  exports.notificationKeys = notificationKeys;
101
133
  exports.useCreateNotification = useCreateNotification;
102
134
  exports.useDeleteNotification = useDeleteNotification;
135
+ exports.useNotificationPreferences = useNotificationPreferences;
103
136
  exports.useNotifications = useNotifications;
104
137
  exports.useUpdateNotification = useUpdateNotification;
138
+ exports.useUpdateNotificationPreferences = useUpdateNotificationPreferences;
105
139
  //# sourceMappingURL=index.cjs.map
106
140
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/keys.ts","../src/queries/useNotifications.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts"],"names":["axios","useQuery","NotificationsResponseSchema","useQueryClient","useAppMode","useMutation","NotificationCreateSchemaAdmin","NotificationCreateSchemaUser","NotificationSchema","NotificationUpdateSchemaAdmin","NotificationUpdateSchemaUser"],"mappings":"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","file":"index.cjs","sourcesContent":["import axios from 'axios';\n\n/**\n * Axios instance for Notifications API\n * Base URL configured through environment variables or defaults to relative path\n */\nexport const api = axios.create({\n baseURL: '/api',\n headers: {\n 'Content-Type': 'application/json',\n },\n});\n","/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { Notification, NotificationsResponseSchema } from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * GET /users/:userId/alerts/notifications\n *\n * Notifications are system-generated based on alert configurations\n * Read-only domain (no create/update operations)\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<Notification[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/alerts/notifications`);\n const validated = NotificationsResponseSchema.parse(response.data);\n return validated.notifications;\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationCreateSchemaAdmin,\n NotificationCreateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n *\n * Creates a notification manually for testing purposes.\n * Uses mode switching for validation:\n * - Admin mode: Allows manual notification creation for test data\n * - User mode: Blocked (notifications are system-generated)\n *\n * @example\n * ```tsx\n * const createNotification = useCreateNotification();\n *\n * createNotification.mutate({\n * userId: 'user123',\n * data: {\n * message: 'Test notification',\n * alert_type: 'AccountThresholdAlert',\n * created_at: new Date().toISOString() // Optional\n * }\n * });\n * ```\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationCreateSchemaAdmin\n : NotificationCreateSchemaUser;\n\n // Validate notification data\n const validated = schema.parse(data);\n\n // POST to create new notification\n const response = await api.post(\n `/users/${userId}/alerts/notifications`,\n validated\n );\n\n // Return created notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationUpdateSchemaAdmin,\n NotificationUpdateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: number;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n *\n * Updates notification fields for testing purposes.\n * Uses mode switching for validation:\n * - Admin mode: Allows updating notifications for test scenarios\n * - User mode: Blocked (notifications are system-generated)\n *\n * @example\n * ```tsx\n * const updateNotification = useUpdateNotification();\n *\n * updateNotification.mutate({\n * userId: 'user123',\n * notificationId: 1,\n * data: {\n * message: 'Updated test notification'\n * }\n * });\n * ```\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationUpdateSchemaAdmin\n : NotificationUpdateSchemaUser;\n\n // Validate notification update data\n const validated = schema.parse(data);\n\n // PUT to update notification\n const response = await api.put(\n `/users/${userId}/alerts/notifications/${notificationId}`,\n validated\n );\n\n // Return updated notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: number;\n}\n\n/**\n * Delete a notification\n * DELETE /users/:userId/alerts/notifications/:notificationId\n *\n * Notifications are system-generated, deletion only removes from view\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n await api.delete(`/users/${userId}/alerts/notifications/${notificationId}`);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications list to refetch without deleted item\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/keys.ts","../src/queries/useNotifications.ts","../src/queries/useNotificationPreferences.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts","../src/mutations/useUpdateNotificationPreferences.ts"],"names":["useQuery","supabase","NotificationsResponseSchema","NotificationPreferencesRowSchema","useQueryClient","useMutation","NotificationRowSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n preferences: (userId: string) => [...notificationKeys.all, 'preferences', userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { NotificationsResponseSchema, type NotificationRow } from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notifications')\n .select('*')\n .eq('user_id', userId)\n .order('created_at', { ascending: false });\n\n if (error) throw new Error(error.message);\n return NotificationsResponseSchema.parse(data);\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationPreferencesParams {\n userId: string;\n}\n\n/**\n * Fetch user notification preferences\n * Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId\n *\n * Transforms snake_case DB columns to camelCase for feature/UI layers\n */\nexport function useNotificationPreferences(\n { userId }: UseNotificationPreferencesParams,\n options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.preferences(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notification_preferences')\n .select('*')\n .eq('user_id', userId)\n .single();\n\n if (error) throw new Error(error.message);\n\n const row = NotificationPreferencesRowSchema.parse(data);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: row.email_notifications,\n pushNotifications: row.push_notifications,\n frequency: row.frequency,\n } as NotificationPreferences;\n },\n staleTime: 1000 * 60 * 5, // 5 minutes (preferences change infrequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .insert({\n user_id: userId,\n message: data.message,\n alert_type: data.alert_type,\n ...(data.created_at ? { created_at: data.created_at } : {}),\n } as TablesInsert<'notifications'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesUpdate,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n is_read?: boolean;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: string;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .update(data as TablesUpdate<'notifications'>)\n .eq('id', notificationId)\n .eq('user_id', userId)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: string;\n}\n\n/**\n * Delete a notification\n * Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n const { error } = await supabase\n .from('notifications')\n .delete()\n .eq('id', notificationId)\n .eq('user_id', userId);\n\n if (error) throw new Error(error.message);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UpdateNotificationPreferencesParams {\n userId: string;\n data: Partial<NotificationPreferences>;\n}\n\n/**\n * Update user notification preferences\n * Supabase: UPSERT notification_preferences\n *\n * Transforms camelCase input → snake_case for Supabase,\n * then transforms response back to camelCase\n */\nexport function useUpdateNotificationPreferences(\n options?: UseMutationOptions<\n NotificationPreferences,\n Error,\n UpdateNotificationPreferencesParams\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: UpdateNotificationPreferencesParams) => {\n // Transform camelCase → snake_case for Supabase\n const dbData: Record<string, unknown> = { user_id: userId };\n if (data.emailNotifications !== undefined) {\n dbData.email_notifications = data.emailNotifications;\n }\n if (data.pushNotifications !== undefined) {\n dbData.push_notifications = data.pushNotifications;\n }\n if (data.frequency !== undefined) {\n dbData.frequency = data.frequency;\n }\n\n const { data: row, error } = await supabase\n .from('notification_preferences')\n .upsert(dbData as TablesInsert<'notification_preferences'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n\n const validated = NotificationPreferencesRowSchema.parse(row);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: validated.email_notifications,\n pushNotifications: validated.push_notifications,\n frequency: validated.frequency,\n } as NotificationPreferences;\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });\n },\n ...options,\n });\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,25 +1,39 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
3
- import { Notification, AlertType } from '@pfm-platform/shared';
4
- import * as axios from 'axios';
3
+ import { NotificationRow, NotificationPreferences, AlertType } from '@pfm-platform/shared';
5
4
 
6
5
  interface UseNotificationsParams {
7
6
  userId: string;
8
7
  }
9
8
  /**
10
9
  * Fetch all notifications for a user
11
- * GET /users/:userId/alerts/notifications
12
- *
13
- * Notifications are system-generated based on alert configurations
14
- * Read-only domain (no create/update operations)
10
+ * Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC
15
11
  */
16
- declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<Notification[]>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
17
- id: number;
18
- message: string;
12
+ declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
13
+ id: string;
14
+ user_id: string;
15
+ alert_id: string | null;
19
16
  alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
20
- created_at: string;
17
+ message: string;
18
+ is_read: boolean;
19
+ created_at: string | null;
21
20
  }[], Error>;
22
21
 
22
+ interface UseNotificationPreferencesParams {
23
+ userId: string;
24
+ }
25
+ /**
26
+ * Fetch user notification preferences
27
+ * Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId
28
+ *
29
+ * Transforms snake_case DB columns to camelCase for feature/UI layers
30
+ */
31
+ declare function useNotificationPreferences({ userId }: UseNotificationPreferencesParams, options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
32
+ emailNotifications: boolean;
33
+ pushNotifications: boolean;
34
+ frequency: "weekly" | "realtime" | "daily";
35
+ }, Error>;
36
+
23
37
  /**
24
38
  * Notification create data interface
25
39
  */
@@ -37,31 +51,15 @@ interface CreateNotificationParams {
37
51
  }
38
52
  /**
39
53
  * Mutation hook for creating a new notification
40
- *
41
- * Creates a notification manually for testing purposes.
42
- * Uses mode switching for validation:
43
- * - Admin mode: Allows manual notification creation for test data
44
- * - User mode: Blocked (notifications are system-generated)
45
- *
46
- * @example
47
- * ```tsx
48
- * const createNotification = useCreateNotification();
49
- *
50
- * createNotification.mutate({
51
- * userId: 'user123',
52
- * data: {
53
- * message: 'Test notification',
54
- * alert_type: 'AccountThresholdAlert',
55
- * created_at: new Date().toISOString() // Optional
56
- * }
57
- * });
58
- * ```
59
54
  */
60
- declare function useCreateNotification(options?: Omit<UseMutationOptions<Notification, Error, CreateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
61
- id: number;
62
- message: string;
55
+ declare function useCreateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, CreateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
56
+ id: string;
57
+ user_id: string;
58
+ alert_id: string | null;
63
59
  alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
64
- created_at: string;
60
+ message: string;
61
+ is_read: boolean;
62
+ created_at: string | null;
65
63
  }, Error, CreateNotificationParams, unknown>;
66
64
 
67
65
  /**
@@ -70,55 +68,56 @@ declare function useCreateNotification(options?: Omit<UseMutationOptions<Notific
70
68
  interface NotificationUpdate {
71
69
  message?: string;
72
70
  alert_type?: AlertType;
71
+ is_read?: boolean;
73
72
  }
74
73
  /**
75
74
  * Parameters for useUpdateNotification mutation
76
75
  */
77
76
  interface UpdateNotificationParams {
78
77
  userId: string;
79
- notificationId: number;
78
+ notificationId: string;
80
79
  data: NotificationUpdate;
81
80
  }
82
81
  /**
83
82
  * Mutation hook for updating a notification
84
- *
85
- * Updates notification fields for testing purposes.
86
- * Uses mode switching for validation:
87
- * - Admin mode: Allows updating notifications for test scenarios
88
- * - User mode: Blocked (notifications are system-generated)
89
- *
90
- * @example
91
- * ```tsx
92
- * const updateNotification = useUpdateNotification();
93
- *
94
- * updateNotification.mutate({
95
- * userId: 'user123',
96
- * notificationId: 1,
97
- * data: {
98
- * message: 'Updated test notification'
99
- * }
100
- * });
101
- * ```
102
83
  */
103
- declare function useUpdateNotification(options?: Omit<UseMutationOptions<Notification, Error, UpdateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
104
- id: number;
105
- message: string;
84
+ declare function useUpdateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
85
+ id: string;
86
+ user_id: string;
87
+ alert_id: string | null;
106
88
  alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
107
- created_at: string;
89
+ message: string;
90
+ is_read: boolean;
91
+ created_at: string | null;
108
92
  }, Error, UpdateNotificationParams, unknown>;
109
93
 
110
94
  interface DeleteNotificationParams {
111
95
  userId: string;
112
- notificationId: number;
96
+ notificationId: string;
113
97
  }
114
98
  /**
115
99
  * Delete a notification
116
- * DELETE /users/:userId/alerts/notifications/:notificationId
117
- *
118
- * Notifications are system-generated, deletion only removes from view
100
+ * Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId
119
101
  */
120
102
  declare function useDeleteNotification(options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<void, Error, DeleteNotificationParams, unknown>;
121
103
 
104
+ interface UpdateNotificationPreferencesParams {
105
+ userId: string;
106
+ data: Partial<NotificationPreferences>;
107
+ }
108
+ /**
109
+ * Update user notification preferences
110
+ * Supabase: UPSERT notification_preferences
111
+ *
112
+ * Transforms camelCase input → snake_case for Supabase,
113
+ * then transforms response back to camelCase
114
+ */
115
+ declare function useUpdateNotificationPreferences(options?: UseMutationOptions<NotificationPreferences, Error, UpdateNotificationPreferencesParams>): _tanstack_react_query.UseMutationResult<{
116
+ emailNotifications: boolean;
117
+ pushNotifications: boolean;
118
+ frequency: "weekly" | "realtime" | "daily";
119
+ }, Error, UpdateNotificationPreferencesParams, unknown>;
120
+
122
121
  /**
123
122
  * Query key factory for Notifications domain
124
123
  */
@@ -126,12 +125,7 @@ declare const notificationKeys: {
126
125
  all: readonly ["notifications"];
127
126
  lists: () => readonly ["notifications", "list"];
128
127
  list: (userId: string) => readonly ["notifications", "list", string];
128
+ preferences: (userId: string) => readonly ["notifications", "preferences", string];
129
129
  };
130
130
 
131
- /**
132
- * Axios instance for Notifications API
133
- * Base URL configured through environment variables or defaults to relative path
134
- */
135
- declare const api: axios.AxiosInstance;
136
-
137
- export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UseNotificationsParams, api, notificationKeys, useCreateNotification, useDeleteNotification, useNotifications, useUpdateNotification };
131
+ export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UpdateNotificationPreferencesParams, type UseNotificationPreferencesParams, type UseNotificationsParams, notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
package/dist/index.d.ts CHANGED
@@ -1,25 +1,39 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
3
- import { Notification, AlertType } from '@pfm-platform/shared';
4
- import * as axios from 'axios';
3
+ import { NotificationRow, NotificationPreferences, AlertType } from '@pfm-platform/shared';
5
4
 
6
5
  interface UseNotificationsParams {
7
6
  userId: string;
8
7
  }
9
8
  /**
10
9
  * Fetch all notifications for a user
11
- * GET /users/:userId/alerts/notifications
12
- *
13
- * Notifications are system-generated based on alert configurations
14
- * Read-only domain (no create/update operations)
10
+ * Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC
15
11
  */
16
- declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<Notification[]>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
17
- id: number;
18
- message: string;
12
+ declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
13
+ id: string;
14
+ user_id: string;
15
+ alert_id: string | null;
19
16
  alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
20
- created_at: string;
17
+ message: string;
18
+ is_read: boolean;
19
+ created_at: string | null;
21
20
  }[], Error>;
22
21
 
22
+ interface UseNotificationPreferencesParams {
23
+ userId: string;
24
+ }
25
+ /**
26
+ * Fetch user notification preferences
27
+ * Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId
28
+ *
29
+ * Transforms snake_case DB columns to camelCase for feature/UI layers
30
+ */
31
+ declare function useNotificationPreferences({ userId }: UseNotificationPreferencesParams, options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
32
+ emailNotifications: boolean;
33
+ pushNotifications: boolean;
34
+ frequency: "weekly" | "realtime" | "daily";
35
+ }, Error>;
36
+
23
37
  /**
24
38
  * Notification create data interface
25
39
  */
@@ -37,31 +51,15 @@ interface CreateNotificationParams {
37
51
  }
38
52
  /**
39
53
  * Mutation hook for creating a new notification
40
- *
41
- * Creates a notification manually for testing purposes.
42
- * Uses mode switching for validation:
43
- * - Admin mode: Allows manual notification creation for test data
44
- * - User mode: Blocked (notifications are system-generated)
45
- *
46
- * @example
47
- * ```tsx
48
- * const createNotification = useCreateNotification();
49
- *
50
- * createNotification.mutate({
51
- * userId: 'user123',
52
- * data: {
53
- * message: 'Test notification',
54
- * alert_type: 'AccountThresholdAlert',
55
- * created_at: new Date().toISOString() // Optional
56
- * }
57
- * });
58
- * ```
59
54
  */
60
- declare function useCreateNotification(options?: Omit<UseMutationOptions<Notification, Error, CreateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
61
- id: number;
62
- message: string;
55
+ declare function useCreateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, CreateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
56
+ id: string;
57
+ user_id: string;
58
+ alert_id: string | null;
63
59
  alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
64
- created_at: string;
60
+ message: string;
61
+ is_read: boolean;
62
+ created_at: string | null;
65
63
  }, Error, CreateNotificationParams, unknown>;
66
64
 
67
65
  /**
@@ -70,55 +68,56 @@ declare function useCreateNotification(options?: Omit<UseMutationOptions<Notific
70
68
  interface NotificationUpdate {
71
69
  message?: string;
72
70
  alert_type?: AlertType;
71
+ is_read?: boolean;
73
72
  }
74
73
  /**
75
74
  * Parameters for useUpdateNotification mutation
76
75
  */
77
76
  interface UpdateNotificationParams {
78
77
  userId: string;
79
- notificationId: number;
78
+ notificationId: string;
80
79
  data: NotificationUpdate;
81
80
  }
82
81
  /**
83
82
  * Mutation hook for updating a notification
84
- *
85
- * Updates notification fields for testing purposes.
86
- * Uses mode switching for validation:
87
- * - Admin mode: Allows updating notifications for test scenarios
88
- * - User mode: Blocked (notifications are system-generated)
89
- *
90
- * @example
91
- * ```tsx
92
- * const updateNotification = useUpdateNotification();
93
- *
94
- * updateNotification.mutate({
95
- * userId: 'user123',
96
- * notificationId: 1,
97
- * data: {
98
- * message: 'Updated test notification'
99
- * }
100
- * });
101
- * ```
102
83
  */
103
- declare function useUpdateNotification(options?: Omit<UseMutationOptions<Notification, Error, UpdateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
104
- id: number;
105
- message: string;
84
+ declare function useUpdateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
85
+ id: string;
86
+ user_id: string;
87
+ alert_id: string | null;
106
88
  alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
107
- created_at: string;
89
+ message: string;
90
+ is_read: boolean;
91
+ created_at: string | null;
108
92
  }, Error, UpdateNotificationParams, unknown>;
109
93
 
110
94
  interface DeleteNotificationParams {
111
95
  userId: string;
112
- notificationId: number;
96
+ notificationId: string;
113
97
  }
114
98
  /**
115
99
  * Delete a notification
116
- * DELETE /users/:userId/alerts/notifications/:notificationId
117
- *
118
- * Notifications are system-generated, deletion only removes from view
100
+ * Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId
119
101
  */
120
102
  declare function useDeleteNotification(options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<void, Error, DeleteNotificationParams, unknown>;
121
103
 
104
+ interface UpdateNotificationPreferencesParams {
105
+ userId: string;
106
+ data: Partial<NotificationPreferences>;
107
+ }
108
+ /**
109
+ * Update user notification preferences
110
+ * Supabase: UPSERT notification_preferences
111
+ *
112
+ * Transforms camelCase input → snake_case for Supabase,
113
+ * then transforms response back to camelCase
114
+ */
115
+ declare function useUpdateNotificationPreferences(options?: UseMutationOptions<NotificationPreferences, Error, UpdateNotificationPreferencesParams>): _tanstack_react_query.UseMutationResult<{
116
+ emailNotifications: boolean;
117
+ pushNotifications: boolean;
118
+ frequency: "weekly" | "realtime" | "daily";
119
+ }, Error, UpdateNotificationPreferencesParams, unknown>;
120
+
122
121
  /**
123
122
  * Query key factory for Notifications domain
124
123
  */
@@ -126,12 +125,7 @@ declare const notificationKeys: {
126
125
  all: readonly ["notifications"];
127
126
  lists: () => readonly ["notifications", "list"];
128
127
  list: (userId: string) => readonly ["notifications", "list", string];
128
+ preferences: (userId: string) => readonly ["notifications", "preferences", string];
129
129
  };
130
130
 
131
- /**
132
- * Axios instance for Notifications API
133
- * Base URL configured through environment variables or defaults to relative path
134
- */
135
- declare const api: axios.AxiosInstance;
136
-
137
- export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UseNotificationsParams, api, notificationKeys, useCreateNotification, useDeleteNotification, useNotifications, useUpdateNotification };
131
+ export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UpdateNotificationPreferencesParams, type UseNotificationPreferencesParams, type UseNotificationsParams, notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
package/dist/index.js CHANGED
@@ -1,20 +1,14 @@
1
1
  import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
2
- import { NotificationsResponseSchema, useAppMode, NotificationCreateSchemaAdmin, NotificationCreateSchemaUser, NotificationSchema, NotificationUpdateSchemaAdmin, NotificationUpdateSchemaUser } from '@pfm-platform/shared';
3
- import axios from 'axios';
2
+ import { supabase, NotificationsResponseSchema, NotificationPreferencesRowSchema, NotificationRowSchema } from '@pfm-platform/shared';
4
3
 
5
4
  // src/queries/useNotifications.ts
6
- var api = axios.create({
7
- baseURL: "/api",
8
- headers: {
9
- "Content-Type": "application/json"
10
- }
11
- });
12
5
 
13
6
  // src/keys.ts
14
7
  var notificationKeys = {
15
8
  all: ["notifications"],
16
9
  lists: () => [...notificationKeys.all, "list"],
17
- list: (userId) => [...notificationKeys.lists(), userId]
10
+ list: (userId) => [...notificationKeys.lists(), userId],
11
+ preferences: (userId) => [...notificationKeys.all, "preferences", userId]
18
12
  };
19
13
 
20
14
  // src/queries/useNotifications.ts
@@ -22,27 +16,45 @@ function useNotifications({ userId }, options) {
22
16
  return useQuery({
23
17
  queryKey: notificationKeys.list(userId),
24
18
  queryFn: async () => {
25
- const response = await api.get(`/users/${userId}/alerts/notifications`);
26
- const validated = NotificationsResponseSchema.parse(response.data);
27
- return validated.notifications;
19
+ const { data, error } = await supabase.from("notifications").select("*").eq("user_id", userId).order("created_at", { ascending: false });
20
+ if (error) throw new Error(error.message);
21
+ return NotificationsResponseSchema.parse(data);
28
22
  },
29
23
  staleTime: 1e3 * 60 * 2,
30
24
  // 2 minutes (notifications change frequently)
31
25
  ...options
32
26
  });
33
27
  }
28
+ function useNotificationPreferences({ userId }, options) {
29
+ return useQuery({
30
+ queryKey: notificationKeys.preferences(userId),
31
+ queryFn: async () => {
32
+ const { data, error } = await supabase.from("notification_preferences").select("*").eq("user_id", userId).single();
33
+ if (error) throw new Error(error.message);
34
+ const row = NotificationPreferencesRowSchema.parse(data);
35
+ return {
36
+ emailNotifications: row.email_notifications,
37
+ pushNotifications: row.push_notifications,
38
+ frequency: row.frequency
39
+ };
40
+ },
41
+ staleTime: 1e3 * 60 * 5,
42
+ // 5 minutes (preferences change infrequently)
43
+ ...options
44
+ });
45
+ }
34
46
  function useCreateNotification(options) {
35
47
  const queryClient = useQueryClient();
36
- const { mode } = useAppMode();
37
48
  return useMutation({
38
49
  mutationFn: async ({ userId, data }) => {
39
- const schema = mode === "admin" ? NotificationCreateSchemaAdmin : NotificationCreateSchemaUser;
40
- const validated = schema.parse(data);
41
- const response = await api.post(
42
- `/users/${userId}/alerts/notifications`,
43
- validated
44
- );
45
- return NotificationSchema.parse(response.data);
50
+ const { data: row, error } = await supabase.from("notifications").insert({
51
+ user_id: userId,
52
+ message: data.message,
53
+ alert_type: data.alert_type,
54
+ ...data.created_at ? { created_at: data.created_at } : {}
55
+ }).select().single();
56
+ if (error) throw new Error(error.message);
57
+ return NotificationRowSchema.parse(row);
46
58
  },
47
59
  onSuccess: (_, { userId }) => {
48
60
  queryClient.invalidateQueries({
@@ -54,20 +66,15 @@ function useCreateNotification(options) {
54
66
  }
55
67
  function useUpdateNotification(options) {
56
68
  const queryClient = useQueryClient();
57
- const { mode } = useAppMode();
58
69
  return useMutation({
59
70
  mutationFn: async ({
60
71
  userId,
61
72
  notificationId,
62
73
  data
63
74
  }) => {
64
- const schema = mode === "admin" ? NotificationUpdateSchemaAdmin : NotificationUpdateSchemaUser;
65
- const validated = schema.parse(data);
66
- const response = await api.put(
67
- `/users/${userId}/alerts/notifications/${notificationId}`,
68
- validated
69
- );
70
- return NotificationSchema.parse(response.data);
75
+ const { data: row, error } = await supabase.from("notifications").update(data).eq("id", notificationId).eq("user_id", userId).select().single();
76
+ if (error) throw new Error(error.message);
77
+ return NotificationRowSchema.parse(row);
71
78
  },
72
79
  onSuccess: (_, { userId }) => {
73
80
  queryClient.invalidateQueries({
@@ -81,7 +88,8 @@ function useDeleteNotification(options) {
81
88
  const queryClient = useQueryClient();
82
89
  return useMutation({
83
90
  mutationFn: async ({ userId, notificationId }) => {
84
- await api.delete(`/users/${userId}/alerts/notifications/${notificationId}`);
91
+ const { error } = await supabase.from("notifications").delete().eq("id", notificationId).eq("user_id", userId);
92
+ if (error) throw new Error(error.message);
85
93
  },
86
94
  onSuccess: (_, { userId }) => {
87
95
  queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });
@@ -89,7 +97,36 @@ function useDeleteNotification(options) {
89
97
  ...options
90
98
  });
91
99
  }
100
+ function useUpdateNotificationPreferences(options) {
101
+ const queryClient = useQueryClient();
102
+ return useMutation({
103
+ mutationFn: async ({ userId, data }) => {
104
+ const dbData = { user_id: userId };
105
+ if (data.emailNotifications !== void 0) {
106
+ dbData.email_notifications = data.emailNotifications;
107
+ }
108
+ if (data.pushNotifications !== void 0) {
109
+ dbData.push_notifications = data.pushNotifications;
110
+ }
111
+ if (data.frequency !== void 0) {
112
+ dbData.frequency = data.frequency;
113
+ }
114
+ const { data: row, error } = await supabase.from("notification_preferences").upsert(dbData).select().single();
115
+ if (error) throw new Error(error.message);
116
+ const validated = NotificationPreferencesRowSchema.parse(row);
117
+ return {
118
+ emailNotifications: validated.email_notifications,
119
+ pushNotifications: validated.push_notifications,
120
+ frequency: validated.frequency
121
+ };
122
+ },
123
+ onSuccess: (_, { userId }) => {
124
+ queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });
125
+ },
126
+ ...options
127
+ });
128
+ }
92
129
 
93
- export { api, notificationKeys, useCreateNotification, useDeleteNotification, useNotifications, useUpdateNotification };
130
+ export { notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
94
131
  //# sourceMappingURL=index.js.map
95
132
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/keys.ts","../src/queries/useNotifications.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts"],"names":["useQueryClient","useAppMode","useMutation","NotificationSchema"],"mappings":"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","file":"index.js","sourcesContent":["import axios from 'axios';\n\n/**\n * Axios instance for Notifications API\n * Base URL configured through environment variables or defaults to relative path\n */\nexport const api = axios.create({\n baseURL: '/api',\n headers: {\n 'Content-Type': 'application/json',\n },\n});\n","/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { Notification, NotificationsResponseSchema } from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * GET /users/:userId/alerts/notifications\n *\n * Notifications are system-generated based on alert configurations\n * Read-only domain (no create/update operations)\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<Notification[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/alerts/notifications`);\n const validated = NotificationsResponseSchema.parse(response.data);\n return validated.notifications;\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationCreateSchemaAdmin,\n NotificationCreateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n *\n * Creates a notification manually for testing purposes.\n * Uses mode switching for validation:\n * - Admin mode: Allows manual notification creation for test data\n * - User mode: Blocked (notifications are system-generated)\n *\n * @example\n * ```tsx\n * const createNotification = useCreateNotification();\n *\n * createNotification.mutate({\n * userId: 'user123',\n * data: {\n * message: 'Test notification',\n * alert_type: 'AccountThresholdAlert',\n * created_at: new Date().toISOString() // Optional\n * }\n * });\n * ```\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationCreateSchemaAdmin\n : NotificationCreateSchemaUser;\n\n // Validate notification data\n const validated = schema.parse(data);\n\n // POST to create new notification\n const response = await api.post(\n `/users/${userId}/alerts/notifications`,\n validated\n );\n\n // Return created notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationUpdateSchemaAdmin,\n NotificationUpdateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: number;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n *\n * Updates notification fields for testing purposes.\n * Uses mode switching for validation:\n * - Admin mode: Allows updating notifications for test scenarios\n * - User mode: Blocked (notifications are system-generated)\n *\n * @example\n * ```tsx\n * const updateNotification = useUpdateNotification();\n *\n * updateNotification.mutate({\n * userId: 'user123',\n * notificationId: 1,\n * data: {\n * message: 'Updated test notification'\n * }\n * });\n * ```\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationUpdateSchemaAdmin\n : NotificationUpdateSchemaUser;\n\n // Validate notification update data\n const validated = schema.parse(data);\n\n // PUT to update notification\n const response = await api.put(\n `/users/${userId}/alerts/notifications/${notificationId}`,\n validated\n );\n\n // Return updated notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: number;\n}\n\n/**\n * Delete a notification\n * DELETE /users/:userId/alerts/notifications/:notificationId\n *\n * Notifications are system-generated, deletion only removes from view\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n await api.delete(`/users/${userId}/alerts/notifications/${notificationId}`);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications list to refetch without deleted item\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/keys.ts","../src/queries/useNotifications.ts","../src/queries/useNotificationPreferences.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts","../src/mutations/useUpdateNotificationPreferences.ts"],"names":["useQuery","useQueryClient","useMutation","NotificationRowSchema","NotificationPreferencesRowSchema"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n preferences: (userId: string) => [...notificationKeys.all, 'preferences', userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { NotificationsResponseSchema, type NotificationRow } from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notifications')\n .select('*')\n .eq('user_id', userId)\n .order('created_at', { ascending: false });\n\n if (error) throw new Error(error.message);\n return NotificationsResponseSchema.parse(data);\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationPreferencesParams {\n userId: string;\n}\n\n/**\n * Fetch user notification preferences\n * Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId\n *\n * Transforms snake_case DB columns to camelCase for feature/UI layers\n */\nexport function useNotificationPreferences(\n { userId }: UseNotificationPreferencesParams,\n options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.preferences(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notification_preferences')\n .select('*')\n .eq('user_id', userId)\n .single();\n\n if (error) throw new Error(error.message);\n\n const row = NotificationPreferencesRowSchema.parse(data);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: row.email_notifications,\n pushNotifications: row.push_notifications,\n frequency: row.frequency,\n } as NotificationPreferences;\n },\n staleTime: 1000 * 60 * 5, // 5 minutes (preferences change infrequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .insert({\n user_id: userId,\n message: data.message,\n alert_type: data.alert_type,\n ...(data.created_at ? { created_at: data.created_at } : {}),\n } as TablesInsert<'notifications'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesUpdate,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n is_read?: boolean;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: string;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .update(data as TablesUpdate<'notifications'>)\n .eq('id', notificationId)\n .eq('user_id', userId)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: string;\n}\n\n/**\n * Delete a notification\n * Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n const { error } = await supabase\n .from('notifications')\n .delete()\n .eq('id', notificationId)\n .eq('user_id', userId);\n\n if (error) throw new Error(error.message);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UpdateNotificationPreferencesParams {\n userId: string;\n data: Partial<NotificationPreferences>;\n}\n\n/**\n * Update user notification preferences\n * Supabase: UPSERT notification_preferences\n *\n * Transforms camelCase input → snake_case for Supabase,\n * then transforms response back to camelCase\n */\nexport function useUpdateNotificationPreferences(\n options?: UseMutationOptions<\n NotificationPreferences,\n Error,\n UpdateNotificationPreferencesParams\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: UpdateNotificationPreferencesParams) => {\n // Transform camelCase → snake_case for Supabase\n const dbData: Record<string, unknown> = { user_id: userId };\n if (data.emailNotifications !== undefined) {\n dbData.email_notifications = data.emailNotifications;\n }\n if (data.pushNotifications !== undefined) {\n dbData.push_notifications = data.pushNotifications;\n }\n if (data.frequency !== undefined) {\n dbData.frequency = data.frequency;\n }\n\n const { data: row, error } = await supabase\n .from('notification_preferences')\n .upsert(dbData as TablesInsert<'notification_preferences'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n\n const validated = NotificationPreferencesRowSchema.parse(row);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: validated.email_notifications,\n pushNotifications: validated.push_notifications,\n frequency: validated.frequency,\n } as NotificationPreferences;\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });\n },\n ...options,\n });\n}\n"]}
package/package.json CHANGED
@@ -1,21 +1,20 @@
1
1
  {
2
2
  "name": "@pfm-platform/notifications-data-access",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "dependencies": {
7
- "axios": "^1.13.2",
8
7
  "zod": "4.1.12",
9
- "@pfm-platform/shared": "0.0.1"
8
+ "@pfm-platform/shared": "0.2.1"
10
9
  },
11
10
  "devDependencies": {
12
- "@testing-library/react": "^16.3.0",
13
- "@vitejs/plugin-react": "^5.1.1",
14
- "@vitest/coverage-v8": "^4.0.9",
11
+ "@testing-library/react": "^16.3.2",
12
+ "@vitejs/plugin-react": "^5.1.4",
13
+ "@vitest/coverage-v8": "^4.0.18",
15
14
  "jsdom": "^27.2.0",
16
- "react-dom": "19.2.0",
15
+ "react-dom": "19.2.4",
17
16
  "typescript": "5.9.3",
18
- "vitest": "4.0.9"
17
+ "vitest": "4.0.18"
19
18
  },
20
19
  "module": "./dist/index.js",
21
20
  "types": "./dist/index.d.ts",