@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
|
@@ -1,54 +1,67 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Notifications Screen -
|
|
2
|
+
* Notifications Screen - Dynamic and Reusable
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* A clean notification settings screen that accepts all text and configuration
|
|
5
|
+
* as props to make it completely reusable across different applications.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React, { useMemo } from 'react';
|
|
9
9
|
import { View, StyleSheet, ActivityIndicator } from 'react-native';
|
|
10
10
|
import { AtomicIcon, AtomicSwitch, AtomicCard, AtomicText, ScreenLayout, STATIC_TOKENS } from '@umituz/react-native-design-system';
|
|
11
|
-
|
|
12
11
|
import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
|
|
13
12
|
import { useNotificationSettings } from '../../infrastructure/hooks/useNotificationSettings';
|
|
14
13
|
import type { DesignTokens } from '@umituz/react-native-design-system';
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
15
|
+
export interface NotificationsScreenProps {
|
|
16
|
+
translations: {
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
loadingText?: string;
|
|
20
|
+
};
|
|
21
|
+
iconName?: string;
|
|
22
|
+
iconColor?: string;
|
|
23
|
+
testID?: string;
|
|
24
|
+
}
|
|
22
25
|
|
|
23
|
-
export const NotificationsScreen: React.FC = (
|
|
24
|
-
|
|
26
|
+
export const NotificationsScreen: React.FC<NotificationsScreenProps> = ({
|
|
27
|
+
translations,
|
|
28
|
+
iconName = 'Bell',
|
|
29
|
+
iconColor = 'primary',
|
|
30
|
+
testID = 'notifications-screen',
|
|
31
|
+
}) => {
|
|
25
32
|
const tokens = useAppDesignTokens();
|
|
26
33
|
const styles = useMemo(() => getStyles(tokens), [tokens]);
|
|
27
34
|
const { notificationsEnabled, setNotificationsEnabled, isLoading } = useNotificationSettings();
|
|
28
35
|
|
|
29
36
|
if (isLoading) {
|
|
30
37
|
return (
|
|
31
|
-
<ScreenLayout testID=
|
|
38
|
+
<ScreenLayout testID={testID}>
|
|
32
39
|
<View style={styles.loadingContainer}>
|
|
33
40
|
<ActivityIndicator size="large" color={tokens.colors.primary} />
|
|
41
|
+
<AtomicText
|
|
42
|
+
type="bodyMedium"
|
|
43
|
+
style={{ color: tokens.colors.textSecondary, marginTop: STATIC_TOKENS.spacing.md }}
|
|
44
|
+
>
|
|
45
|
+
{translations.loadingText || 'Loading...'}
|
|
46
|
+
</AtomicText>
|
|
34
47
|
</View>
|
|
35
48
|
</ScreenLayout>
|
|
36
49
|
);
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
return (
|
|
40
|
-
<ScreenLayout testID=
|
|
53
|
+
<ScreenLayout testID={testID} hideScrollIndicator>
|
|
41
54
|
<AtomicCard style={styles.card}>
|
|
42
55
|
<View style={styles.settingItem}>
|
|
43
56
|
<View style={styles.iconContainer}>
|
|
44
|
-
<AtomicIcon name=
|
|
57
|
+
<AtomicIcon name={iconName} size="lg" color={iconColor} />
|
|
45
58
|
</View>
|
|
46
59
|
<View style={styles.textContainer}>
|
|
47
60
|
<AtomicText type="bodyLarge" style={{ color: tokens.colors.textPrimary }}>
|
|
48
|
-
{
|
|
61
|
+
{translations.title}
|
|
49
62
|
</AtomicText>
|
|
50
63
|
<AtomicText type="bodySmall" style={{ color: tokens.colors.textSecondary, marginTop: STATIC_TOKENS.spacing.xs }}>
|
|
51
|
-
{
|
|
64
|
+
{translations.description}
|
|
52
65
|
</AtomicText>
|
|
53
66
|
</View>
|
|
54
67
|
<AtomicSwitch
|
|
@@ -91,4 +104,4 @@ const getStyles = (tokens: DesignTokens) => StyleSheet.create({
|
|
|
91
104
|
},
|
|
92
105
|
});
|
|
93
106
|
|
|
94
|
-
export default NotificationsScreen;
|
|
107
|
+
export default NotificationsScreen;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
declare const __DEV__: boolean;
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
namespace React {
|
|
5
|
+
interface ReactElement {
|
|
6
|
+
type: any;
|
|
7
|
+
props: any;
|
|
8
|
+
key: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface ReactNode {
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare module 'react' {
|
|
18
|
+
export interface FunctionComponent<P = {}> {
|
|
19
|
+
(props: P): React.ReactElement | null;
|
|
20
|
+
displayName?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type FC<P = {}> = FunctionComponent<P>;
|
|
24
|
+
|
|
25
|
+
export function useState<S>(initialState: S | (() => S)): [S, (value: S | ((prevState: S) => S)) => void];
|
|
26
|
+
export function useEffect(effect: () => void | (() => void), deps?: any[]): void;
|
|
27
|
+
export function useCallback<T extends (...args: any[]) => any>(callback: T, deps: any[]): T;
|
|
28
|
+
export function useMemo<T>(factory: () => T, deps: any[]): T;
|
|
29
|
+
export function useRef<T>(initialValue: T): { current: T };
|
|
30
|
+
|
|
31
|
+
export interface ReactElement {
|
|
32
|
+
type: any;
|
|
33
|
+
props: any;
|
|
34
|
+
key: any;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ReactNode {
|
|
38
|
+
[key: string]: any;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const createElement: any;
|
|
42
|
+
const Component: any;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare module '@react-native-async-storage/async-storage' {
|
|
46
|
+
export interface AsyncStorageStatic {
|
|
47
|
+
getItem(key: string): Promise<string | null>;
|
|
48
|
+
setItem(key: string, value: string): Promise<void>;
|
|
49
|
+
removeItem(key: string): Promise<void>;
|
|
50
|
+
clear(): Promise<void>;
|
|
51
|
+
getAllKeys(): Promise<string[]>;
|
|
52
|
+
multiGet(keys: string[]): Promise<[string, string | null][]>;
|
|
53
|
+
multiSet(keyValuePairs: [string, string][]): Promise<void>;
|
|
54
|
+
multiRemove(keys: string[]): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
const AsyncStorage: AsyncStorageStatic;
|
|
57
|
+
export default AsyncStorage;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
declare module 'expo-notifications' {
|
|
61
|
+
export interface NotificationContentInput {
|
|
62
|
+
title: string;
|
|
63
|
+
body: string;
|
|
64
|
+
data?: Record<string, any>;
|
|
65
|
+
sound?: string | boolean;
|
|
66
|
+
badge?: number;
|
|
67
|
+
categoryIdentifier?: string;
|
|
68
|
+
priority?: AndroidNotificationPriority;
|
|
69
|
+
vibrate?: number[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface NotificationRequestInput {
|
|
73
|
+
content: NotificationContentInput;
|
|
74
|
+
trigger?: NotificationTriggerInput | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface NotificationTriggerInput {
|
|
78
|
+
date?: Date;
|
|
79
|
+
repeats?: boolean;
|
|
80
|
+
channelId?: string;
|
|
81
|
+
hour?: number;
|
|
82
|
+
minute?: number;
|
|
83
|
+
weekday?: number;
|
|
84
|
+
day?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ScheduledNotification {
|
|
88
|
+
identifier: string;
|
|
89
|
+
content: NotificationContentInput;
|
|
90
|
+
trigger: NotificationTriggerInput;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export enum AndroidImportance {
|
|
94
|
+
DEFAULT = 'default',
|
|
95
|
+
HIGH = 'high',
|
|
96
|
+
MAX = 'max',
|
|
97
|
+
LOW = 'low',
|
|
98
|
+
MIN = 'min',
|
|
99
|
+
UNSPECIFIED = 'unspecified',
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export enum AndroidNotificationPriority {
|
|
103
|
+
DEFAULT = 'default',
|
|
104
|
+
HIGH = 'high',
|
|
105
|
+
LOW = 'low',
|
|
106
|
+
MAX = 'max',
|
|
107
|
+
MIN = 'min',
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface AndroidChannel {
|
|
111
|
+
name: string;
|
|
112
|
+
importance: AndroidImportance;
|
|
113
|
+
vibrationPattern?: number[];
|
|
114
|
+
sound?: string;
|
|
115
|
+
lightColor?: string;
|
|
116
|
+
enableVibrate?: boolean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface NotificationPermissionsResponse {
|
|
120
|
+
status: 'granted' | 'denied' | 'undetermined';
|
|
121
|
+
granted?: boolean;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function setNotificationHandler(handler: {
|
|
125
|
+
handleNotification: () => Promise<{
|
|
126
|
+
shouldShowAlert: boolean;
|
|
127
|
+
shouldPlaySound: boolean;
|
|
128
|
+
shouldSetBadge: boolean;
|
|
129
|
+
}>;
|
|
130
|
+
}): void;
|
|
131
|
+
|
|
132
|
+
export function scheduleNotificationAsync(request: NotificationRequestInput): Promise<string>;
|
|
133
|
+
export function cancelScheduledNotificationAsync(identifier: string): Promise<void>;
|
|
134
|
+
export function cancelAllScheduledNotificationsAsync(): Promise<void>;
|
|
135
|
+
export function getAllScheduledNotificationsAsync(): Promise<ScheduledNotification[]>;
|
|
136
|
+
export function dismissAllNotificationsAsync(): Promise<void>;
|
|
137
|
+
export function getPermissionsAsync(): Promise<NotificationPermissionsResponse>;
|
|
138
|
+
export function requestPermissionsAsync(): Promise<NotificationPermissionsResponse>;
|
|
139
|
+
export function setNotificationChannelAsync(id: string, channel: AndroidChannel): Promise<void>;
|
|
140
|
+
export function getBadgeCountAsync(): Promise<number>;
|
|
141
|
+
export function setBadgeCountAsync(count: number): Promise<void>;
|
|
142
|
+
export function getExpoPushTokenAsync(options?: any): Promise<{ data: string }>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
declare module 'expo-device' {
|
|
146
|
+
export const isDevice: boolean;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
declare module 'react-native' {
|
|
150
|
+
export interface PlatformStatic {
|
|
151
|
+
OS: 'ios' | 'android';
|
|
152
|
+
Version: string | number;
|
|
153
|
+
isPad?: boolean;
|
|
154
|
+
isTVOS?: boolean;
|
|
155
|
+
select<T>(specifics: { ios?: T; android?: T; default?: T }): T;
|
|
156
|
+
}
|
|
157
|
+
export const Platform: PlatformStatic;
|
|
158
|
+
|
|
159
|
+
export interface StyleSheetStatic {
|
|
160
|
+
create<T>(styles: T): T;
|
|
161
|
+
}
|
|
162
|
+
export const StyleSheet: StyleSheetStatic;
|
|
163
|
+
|
|
164
|
+
export interface ViewStatic {
|
|
165
|
+
new (props: any): any;
|
|
166
|
+
}
|
|
167
|
+
export const View: ViewStatic;
|
|
168
|
+
|
|
169
|
+
export interface ActivityIndicatorStatic {
|
|
170
|
+
new (props: any): any;
|
|
171
|
+
}
|
|
172
|
+
export const ActivityIndicator: ActivityIndicatorStatic;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
declare module 'zustand' {
|
|
176
|
+
export interface StoreApi<T> {
|
|
177
|
+
getState: () => T;
|
|
178
|
+
setState: (partial: T | Partial<T> | ((state: T) => T | Partial<T>), replace?: boolean) => void;
|
|
179
|
+
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
|
|
180
|
+
destroy: () => void;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function create<TState extends object>(
|
|
184
|
+
stateCreator: (
|
|
185
|
+
set: (
|
|
186
|
+
partial: TState | Partial<TState> | ((state: TState) => TState | Partial<TState>),
|
|
187
|
+
replace?: boolean,
|
|
188
|
+
) => void,
|
|
189
|
+
get: () => TState,
|
|
190
|
+
api: StoreApi<TState>,
|
|
191
|
+
) => TState,
|
|
192
|
+
): StoreApi<TState> & ((selector?: (state: TState) => any) => any);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
declare module '@umituz/react-native-design-system' {
|
|
196
|
+
export interface AtomicIconProps {
|
|
197
|
+
name: string;
|
|
198
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
199
|
+
color?: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface AtomicSwitchProps {
|
|
203
|
+
value: boolean;
|
|
204
|
+
onValueChange: (value: boolean) => void;
|
|
205
|
+
testID?: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface AtomicCardProps {
|
|
209
|
+
style?: any;
|
|
210
|
+
children?: React.ReactNode;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface AtomicTextProps {
|
|
214
|
+
type: 'bodySmall' | 'bodyMedium' | 'bodyLarge';
|
|
215
|
+
style?: any;
|
|
216
|
+
children?: React.ReactNode;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface ScreenLayoutProps {
|
|
220
|
+
testID?: string;
|
|
221
|
+
hideScrollIndicator?: boolean;
|
|
222
|
+
children?: React.ReactNode;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const AtomicIcon: React.FC<AtomicIconProps>;
|
|
226
|
+
export const AtomicSwitch: React.FC<AtomicSwitchProps>;
|
|
227
|
+
export const AtomicCard: React.FC<AtomicCardProps>;
|
|
228
|
+
export const AtomicText: React.FC<AtomicTextProps>;
|
|
229
|
+
export const ScreenLayout: React.FC<ScreenLayoutProps>;
|
|
230
|
+
|
|
231
|
+
export const STATIC_TOKENS: {
|
|
232
|
+
spacing: {
|
|
233
|
+
xs: number;
|
|
234
|
+
sm: number;
|
|
235
|
+
md: number;
|
|
236
|
+
lg: number;
|
|
237
|
+
xl: number;
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export interface DesignTokens {
|
|
242
|
+
colors: {
|
|
243
|
+
primary: string;
|
|
244
|
+
textPrimary: string;
|
|
245
|
+
textSecondary: string;
|
|
246
|
+
surface: string;
|
|
247
|
+
surfaceSecondary: string;
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
declare module '@umituz/react-native-design-system-theme' {
|
|
253
|
+
export function useAppDesignTokens(): import('@umituz/react-native-design-system').DesignTokens;
|
|
254
|
+
}
|
|
255
|
+
|