@umituz/react-native-notifications 1.0.5 → 1.1.0
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/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -1
- package/lib/infrastructure/hooks/actions/useNotificationActions.d.ts +4 -13
- package/lib/infrastructure/hooks/actions/useNotificationActions.d.ts.map +1 -1
- package/lib/infrastructure/hooks/actions/useNotificationActions.js +4 -70
- package/lib/infrastructure/hooks/actions/useNotificationActions.js.map +1 -1
- package/lib/infrastructure/hooks/actions/useNotificationManagementActions.d.ts +8 -0
- package/lib/infrastructure/hooks/actions/useNotificationManagementActions.d.ts.map +1 -0
- package/lib/infrastructure/hooks/actions/useNotificationManagementActions.js +78 -0
- package/lib/infrastructure/hooks/actions/useNotificationManagementActions.js.map +1 -0
- package/lib/infrastructure/hooks/state/useNotificationsState.d.ts +8 -8
- package/lib/infrastructure/hooks/useNotificationSettings.d.ts +2 -2
- package/lib/infrastructure/hooks/useNotifications.d.ts +21 -1
- package/lib/infrastructure/hooks/useNotifications.d.ts.map +1 -1
- package/lib/infrastructure/hooks/useNotifications.js +30 -9
- package/lib/infrastructure/hooks/useNotifications.js.map +1 -1
- package/lib/infrastructure/hooks/utils/useNotificationRefresh.d.ts +5 -10
- package/lib/infrastructure/hooks/utils/useNotificationRefresh.d.ts.map +1 -1
- package/lib/infrastructure/hooks/utils/useNotificationRefresh.js +32 -15
- package/lib/infrastructure/hooks/utils/useNotificationRefresh.js.map +1 -1
- package/lib/infrastructure/services/NotificationBadgeManager.d.ts +5 -0
- package/lib/infrastructure/services/NotificationBadgeManager.d.ts.map +1 -0
- package/lib/infrastructure/services/NotificationBadgeManager.js +29 -0
- package/lib/infrastructure/services/NotificationBadgeManager.js.map +1 -0
- package/lib/infrastructure/services/NotificationManager.d.ts +5 -84
- package/lib/infrastructure/services/NotificationManager.d.ts.map +1 -1
- package/lib/infrastructure/services/NotificationManager.js +36 -203
- package/lib/infrastructure/services/NotificationManager.js.map +1 -1
- package/lib/infrastructure/services/NotificationPermissions.d.ts +6 -0
- package/lib/infrastructure/services/NotificationPermissions.d.ts.map +1 -0
- package/lib/infrastructure/services/NotificationPermissions.js +75 -0
- package/lib/infrastructure/services/NotificationPermissions.js.map +1 -0
- package/lib/infrastructure/services/NotificationScheduler.d.ts +8 -0
- package/lib/infrastructure/services/NotificationScheduler.d.ts.map +1 -0
- package/lib/infrastructure/services/NotificationScheduler.js +72 -0
- package/lib/infrastructure/services/NotificationScheduler.js.map +1 -0
- package/lib/infrastructure/services/delivery/NotificationDelivery.d.ts +2 -8
- package/lib/infrastructure/services/delivery/NotificationDelivery.d.ts.map +1 -1
- package/lib/infrastructure/services/delivery/NotificationDelivery.js +27 -13
- package/lib/infrastructure/services/delivery/NotificationDelivery.js.map +1 -1
- package/lib/infrastructure/storage/NotificationsStore.d.ts +8 -1
- package/lib/infrastructure/storage/NotificationsStore.d.ts.map +1 -1
- package/lib/infrastructure/storage/NotificationsStore.js +2 -1
- package/lib/infrastructure/storage/NotificationsStore.js.map +1 -1
- package/lib/infrastructure/utils/dev.d.ts +5 -0
- package/lib/infrastructure/utils/dev.d.ts.map +1 -0
- package/lib/infrastructure/utils/dev.js +24 -0
- package/lib/infrastructure/utils/dev.js.map +1 -0
- package/lib/presentation/screens/NotificationsScreen.d.ts +14 -4
- package/lib/presentation/screens/NotificationsScreen.d.ts.map +1 -1
- package/lib/presentation/screens/NotificationsScreen.js +12 -15
- package/lib/presentation/screens/NotificationsScreen.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/NotificationManager.test.ts +215 -0
- package/src/__tests__/useNotificationActions.test.ts +189 -0
- package/src/__tests__/useNotificationRefresh.test.ts +213 -0
- package/src/index.ts +7 -0
- package/src/infrastructure/hooks/actions/useNotificationActions.ts +8 -110
- package/src/infrastructure/hooks/actions/useNotificationManagementActions.ts +131 -0
- package/src/infrastructure/hooks/useNotifications.ts +37 -11
- package/src/infrastructure/hooks/utils/useNotificationRefresh.ts +40 -16
- package/src/infrastructure/services/NotificationBadgeManager.ts +28 -0
- package/src/infrastructure/services/NotificationManager.ts +51 -217
- package/src/infrastructure/services/NotificationPermissions.ts +80 -0
- package/src/infrastructure/services/NotificationScheduler.ts +77 -0
- package/src/infrastructure/services/delivery/NotificationDelivery.ts +32 -14
- package/src/infrastructure/storage/NotificationsStore.ts +3 -2
- package/src/infrastructure/utils/dev.ts +25 -0
- package/src/presentation/screens/NotificationsScreen.tsx +31 -18
- package/src/types/global.d.ts +255 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
|
+
import type {
|
|
4
|
+
Notification,
|
|
5
|
+
NotificationChannel,
|
|
6
|
+
NotificationPreferences,
|
|
7
|
+
} from '../types';
|
|
8
|
+
import { ChannelManager } from '../../services/channels/ChannelManager';
|
|
9
|
+
import { PreferencesManager } from '../../services/preferences/PreferencesManager';
|
|
10
|
+
import { devLog } from '../../utils/dev';
|
|
11
|
+
|
|
12
|
+
export const useNotificationManagementActions = (state: any, setters: any) => {
|
|
13
|
+
const { setNotifications, setUnreadCount, setChannels, setPreferences, setError } = setters;
|
|
14
|
+
|
|
15
|
+
const channelManager = new ChannelManager();
|
|
16
|
+
const preferencesManager = new PreferencesManager();
|
|
17
|
+
|
|
18
|
+
const deleteNotification = useCallback(
|
|
19
|
+
async (notificationId: string): Promise<boolean> => {
|
|
20
|
+
try {
|
|
21
|
+
const data = await AsyncStorage.getItem('@notifications:list');
|
|
22
|
+
const notifications: Notification[] = data ? JSON.parse(data) : [];
|
|
23
|
+
|
|
24
|
+
const deleted = notifications.find((n) => n.id === notificationId);
|
|
25
|
+
const filtered = notifications.filter((n) => n.id !== notificationId);
|
|
26
|
+
|
|
27
|
+
await AsyncStorage.setItem(
|
|
28
|
+
'@notifications:list',
|
|
29
|
+
JSON.stringify(filtered)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
setNotifications((prev: Notification[]) =>
|
|
33
|
+
prev.filter((n) => n.id !== notificationId)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if (deleted && !deleted.read) {
|
|
37
|
+
setUnreadCount((prev: number) => Math.max(0, prev - 1));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
devLog('[useNotificationManagementActions] Deleted notification:', notificationId);
|
|
41
|
+
|
|
42
|
+
return true;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
setError(
|
|
45
|
+
err instanceof Error ? err.message : 'Failed to delete notification'
|
|
46
|
+
);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
[setNotifications, setUnreadCount, setError]
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const registerChannel = useCallback(
|
|
54
|
+
async (
|
|
55
|
+
channelType: 'push' | 'in_app',
|
|
56
|
+
preferences: Record<string, any> = {}
|
|
57
|
+
): Promise<NotificationChannel | null> => {
|
|
58
|
+
try {
|
|
59
|
+
const channel = await channelManager.register(channelType, preferences);
|
|
60
|
+
if (channel) {
|
|
61
|
+
setChannels((prev: NotificationChannel[]) => [...prev, channel]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
devLog('[useNotificationManagementActions] Channel registered:', channel?.id);
|
|
65
|
+
|
|
66
|
+
return channel;
|
|
67
|
+
} catch (err) {
|
|
68
|
+
setError(
|
|
69
|
+
err instanceof Error ? err.message : 'Failed to register channel'
|
|
70
|
+
);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
[setChannels, setError]
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const verifyChannel = useCallback(
|
|
78
|
+
async (channelId: string): Promise<boolean> => {
|
|
79
|
+
try {
|
|
80
|
+
const success = await channelManager.verify(channelId);
|
|
81
|
+
if (success) {
|
|
82
|
+
setChannels((prev: NotificationChannel[]) =>
|
|
83
|
+
prev.map((c) =>
|
|
84
|
+
c.id === channelId ? { ...c, is_verified: true } : c
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
devLog('[useNotificationManagementActions] Channel verified:', channelId, success);
|
|
90
|
+
|
|
91
|
+
return success;
|
|
92
|
+
} catch (err) {
|
|
93
|
+
setError(
|
|
94
|
+
err instanceof Error ? err.message : 'Failed to verify channel'
|
|
95
|
+
);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
[setChannels, setError]
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const updatePreferences = useCallback(
|
|
103
|
+
async (newPreferences: Partial<NotificationPreferences>): Promise<boolean> => {
|
|
104
|
+
try {
|
|
105
|
+
const success = await preferencesManager.update(newPreferences);
|
|
106
|
+
if (success) {
|
|
107
|
+
setPreferences((prev: NotificationPreferences | null) =>
|
|
108
|
+
prev ? { ...prev, ...newPreferences } : null
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
devLog('[useNotificationManagementActions] Preferences updated:', newPreferences);
|
|
113
|
+
|
|
114
|
+
return success;
|
|
115
|
+
} catch (err) {
|
|
116
|
+
setError(
|
|
117
|
+
err instanceof Error ? err.message : 'Failed to update preferences'
|
|
118
|
+
);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
[setPreferences, setError]
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
deleteNotification,
|
|
127
|
+
registerChannel,
|
|
128
|
+
verifyChannel,
|
|
129
|
+
updatePreferences,
|
|
130
|
+
};
|
|
131
|
+
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useEffect, useCallback } from 'react';
|
|
2
2
|
import { useNotificationsState } from './state/useNotificationsState';
|
|
3
3
|
import { useNotificationActions } from './actions/useNotificationActions';
|
|
4
|
+
import { useNotificationManagementActions } from './actions/useNotificationManagementActions';
|
|
4
5
|
import { useNotificationRefresh } from './utils/useNotificationRefresh';
|
|
5
6
|
import type { UseNotificationsOptions } from './types';
|
|
7
|
+
import { devLog } from '../utils/dev';
|
|
6
8
|
|
|
7
9
|
export * from './types';
|
|
8
10
|
|
|
@@ -31,10 +33,25 @@ export function useNotifications(userId: string, options: UseNotificationsOption
|
|
|
31
33
|
};
|
|
32
34
|
|
|
33
35
|
const actions = useNotificationActions(state, setters);
|
|
36
|
+
const managementActions = useNotificationManagementActions(state, setters);
|
|
34
37
|
const refresh = useNotificationRefresh(pageSize, setters);
|
|
35
38
|
|
|
36
|
-
const loadMoreNotifications = () =>
|
|
37
|
-
refresh.loadMoreNotifications(state.notifications.length, state.hasMore, state.loading)
|
|
39
|
+
const loadMoreNotifications = useCallback(() =>
|
|
40
|
+
refresh.loadMoreNotifications(state.notifications.length, state.hasMore, state.loading),
|
|
41
|
+
[refresh, state.notifications.length, state.hasMore, state.loading]
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const cleanup = useCallback(() => {
|
|
45
|
+
setNotifications([]);
|
|
46
|
+
setChannels([]);
|
|
47
|
+
setUnreadCount(0);
|
|
48
|
+
setPreferences(null);
|
|
49
|
+
setError(null);
|
|
50
|
+
setLoading(false);
|
|
51
|
+
setHasMore(true);
|
|
52
|
+
|
|
53
|
+
devLog('[useNotifications] Cleaned up notification state');
|
|
54
|
+
}, [setNotifications, setChannels, setUnreadCount, setPreferences, setError, setLoading, setHasMore]);
|
|
38
55
|
|
|
39
56
|
// Load initial data
|
|
40
57
|
useEffect(() => {
|
|
@@ -43,14 +60,11 @@ export function useNotifications(userId: string, options: UseNotificationsOption
|
|
|
43
60
|
refresh.refreshChannels();
|
|
44
61
|
refresh.refreshPreferences();
|
|
45
62
|
} else {
|
|
46
|
-
|
|
47
|
-
setChannels([]);
|
|
48
|
-
setUnreadCount(0);
|
|
49
|
-
setPreferences(null);
|
|
63
|
+
cleanup();
|
|
50
64
|
}
|
|
51
|
-
}, [userId]);
|
|
65
|
+
}, [userId, cleanup]);
|
|
52
66
|
|
|
53
|
-
// Auto-refresh setup
|
|
67
|
+
// Auto-refresh setup with proper cleanup
|
|
54
68
|
useEffect(() => {
|
|
55
69
|
if (!autoRefresh || !userId) return;
|
|
56
70
|
|
|
@@ -58,13 +72,25 @@ export function useNotifications(userId: string, options: UseNotificationsOption
|
|
|
58
72
|
refresh.refreshNotifications();
|
|
59
73
|
}, refreshInterval);
|
|
60
74
|
|
|
61
|
-
return () =>
|
|
75
|
+
return () => {
|
|
76
|
+
clearInterval(interval);
|
|
77
|
+
devLog('[useNotifications] Auto-refresh interval cleared');
|
|
78
|
+
};
|
|
62
79
|
}, [autoRefresh, userId, refreshInterval]);
|
|
63
80
|
|
|
81
|
+
// Cleanup on unmount
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
return () => {
|
|
84
|
+
devLog('[useNotifications] Component unmounted, cleaning up');
|
|
85
|
+
};
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
64
88
|
return {
|
|
65
89
|
...state,
|
|
66
90
|
...actions,
|
|
91
|
+
...managementActions,
|
|
67
92
|
...refresh,
|
|
68
93
|
loadMoreNotifications,
|
|
94
|
+
cleanup,
|
|
69
95
|
};
|
|
70
|
-
}
|
|
96
|
+
}
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
2
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
3
|
import type { Notification } from '../types';
|
|
4
4
|
import { ChannelManager } from '../../services/channels/ChannelManager';
|
|
5
5
|
import { PreferencesManager } from '../../services/preferences/PreferencesManager';
|
|
6
|
+
import { devLog, devError } from '../../utils/dev';
|
|
6
7
|
|
|
7
|
-
/**
|
|
8
|
-
* useNotificationRefresh - Offline Notification Refresh
|
|
9
|
-
*
|
|
10
|
-
* Uses AsyncStorage for local data.
|
|
11
|
-
* NO backend - pure offline.
|
|
12
|
-
*/
|
|
13
8
|
export const useNotificationRefresh = (pageSize: number, setters: any) => {
|
|
14
9
|
const {
|
|
15
10
|
setNotifications,
|
|
@@ -21,39 +16,57 @@ export const useNotificationRefresh = (pageSize: number, setters: any) => {
|
|
|
21
16
|
setHasMore,
|
|
22
17
|
} = setters;
|
|
23
18
|
|
|
24
|
-
const channelManager = new ChannelManager();
|
|
25
|
-
const preferencesManager = new PreferencesManager();
|
|
19
|
+
const channelManager = useRef(new ChannelManager()).current;
|
|
20
|
+
const preferencesManager = useRef(new PreferencesManager()).current;
|
|
21
|
+
const abortController = useRef<AbortController | null>(null);
|
|
22
|
+
|
|
23
|
+
const cleanup = useCallback(() => {
|
|
24
|
+
if (abortController.current) {
|
|
25
|
+
abortController.current.abort();
|
|
26
|
+
abortController.current = null;
|
|
27
|
+
}
|
|
28
|
+
}, []);
|
|
26
29
|
|
|
27
30
|
const refreshNotifications = useCallback(async () => {
|
|
28
31
|
try {
|
|
32
|
+
cleanup();
|
|
33
|
+
abortController.current = new AbortController();
|
|
34
|
+
|
|
29
35
|
setLoading(true);
|
|
30
36
|
setError(null);
|
|
31
37
|
|
|
32
|
-
// Load from AsyncStorage
|
|
33
38
|
const data = await AsyncStorage.getItem('@notifications:list');
|
|
34
39
|
const allNotifications: Notification[] = data ? JSON.parse(data) : [];
|
|
35
40
|
|
|
36
|
-
// Paginate
|
|
37
41
|
const paginated = allNotifications.slice(0, pageSize);
|
|
38
42
|
const unread = allNotifications.filter((n) => !n.read).length;
|
|
39
43
|
|
|
40
44
|
setNotifications(paginated);
|
|
41
45
|
setUnreadCount(unread);
|
|
42
46
|
setHasMore(allNotifications.length > pageSize);
|
|
47
|
+
|
|
48
|
+
devLog('[useNotificationRefresh] Refreshed notifications:', paginated.length);
|
|
43
49
|
} catch (err) {
|
|
50
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
44
53
|
setError(
|
|
45
54
|
err instanceof Error ? err.message : 'Failed to load notifications'
|
|
46
55
|
);
|
|
47
56
|
} finally {
|
|
48
57
|
setLoading(false);
|
|
58
|
+
cleanup();
|
|
49
59
|
}
|
|
50
|
-
}, [pageSize, setNotifications, setUnreadCount, setHasMore, setLoading, setError]);
|
|
60
|
+
}, [pageSize, setNotifications, setUnreadCount, setHasMore, setLoading, setError, cleanup]);
|
|
51
61
|
|
|
52
62
|
const loadMoreNotifications = useCallback(
|
|
53
63
|
async (currentLength: number, hasMore: boolean, loading: boolean) => {
|
|
54
64
|
if (!hasMore || loading) return;
|
|
55
65
|
|
|
56
66
|
try {
|
|
67
|
+
cleanup();
|
|
68
|
+
abortController.current = new AbortController();
|
|
69
|
+
|
|
57
70
|
setLoading(true);
|
|
58
71
|
setError(null);
|
|
59
72
|
|
|
@@ -67,7 +80,12 @@ export const useNotificationRefresh = (pageSize: number, setters: any) => {
|
|
|
67
80
|
|
|
68
81
|
setNotifications((prev: any[]) => [...prev, ...moreNotifications]);
|
|
69
82
|
setHasMore(allNotifications.length > currentLength + pageSize);
|
|
83
|
+
|
|
84
|
+
devLog('[useNotificationRefresh] Loaded more notifications:', moreNotifications.length);
|
|
70
85
|
} catch (err) {
|
|
86
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
71
89
|
setError(
|
|
72
90
|
err instanceof Error
|
|
73
91
|
? err.message
|
|
@@ -75,17 +93,20 @@ export const useNotificationRefresh = (pageSize: number, setters: any) => {
|
|
|
75
93
|
);
|
|
76
94
|
} finally {
|
|
77
95
|
setLoading(false);
|
|
96
|
+
cleanup();
|
|
78
97
|
}
|
|
79
98
|
},
|
|
80
|
-
[pageSize, setNotifications, setHasMore, setLoading, setError]
|
|
99
|
+
[pageSize, setNotifications, setHasMore, setLoading, setError, cleanup]
|
|
81
100
|
);
|
|
82
101
|
|
|
83
102
|
const refreshChannels = useCallback(async () => {
|
|
84
103
|
try {
|
|
85
104
|
const channelsData = await channelManager.getActiveChannels();
|
|
86
105
|
setChannels(channelsData);
|
|
106
|
+
|
|
107
|
+
devLog('[useNotificationRefresh] Refreshed channels:', channelsData.length);
|
|
87
108
|
} catch (err) {
|
|
88
|
-
|
|
109
|
+
devError('[useNotificationRefresh] Failed to refresh channels:', err);
|
|
89
110
|
}
|
|
90
111
|
}, [setChannels]);
|
|
91
112
|
|
|
@@ -93,8 +114,10 @@ export const useNotificationRefresh = (pageSize: number, setters: any) => {
|
|
|
93
114
|
try {
|
|
94
115
|
const prefsData = await preferencesManager.get();
|
|
95
116
|
setPreferences(prefsData);
|
|
117
|
+
|
|
118
|
+
devLog('[useNotificationRefresh] Refreshed preferences');
|
|
96
119
|
} catch (err) {
|
|
97
|
-
|
|
120
|
+
devError('[useNotificationRefresh] Failed to refresh preferences:', err);
|
|
98
121
|
}
|
|
99
122
|
}, [setPreferences]);
|
|
100
123
|
|
|
@@ -103,5 +126,6 @@ export const useNotificationRefresh = (pageSize: number, setters: any) => {
|
|
|
103
126
|
loadMoreNotifications,
|
|
104
127
|
refreshChannels,
|
|
105
128
|
refreshPreferences,
|
|
129
|
+
cleanup,
|
|
106
130
|
};
|
|
107
|
-
};
|
|
131
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Notifications from 'expo-notifications';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import { devError } from '../utils/dev';
|
|
4
|
+
|
|
5
|
+
export class NotificationBadgeManager {
|
|
6
|
+
async getBadgeCount(): Promise<number> {
|
|
7
|
+
try {
|
|
8
|
+
if (Platform.OS === 'ios') {
|
|
9
|
+
return await Notifications.getBadgeCountAsync();
|
|
10
|
+
}
|
|
11
|
+
return 0;
|
|
12
|
+
} catch (error) {
|
|
13
|
+
devError('[NotificationBadgeManager] Get badge count failed:', error);
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async setBadgeCount(count: number): Promise<void> {
|
|
19
|
+
try {
|
|
20
|
+
if (Platform.OS === 'ios') {
|
|
21
|
+
await Notifications.setBadgeCountAsync(count);
|
|
22
|
+
}
|
|
23
|
+
} catch (error) {
|
|
24
|
+
devError('[NotificationBadgeManager] Set badge count failed:', error);
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|