@umituz/react-native-settings 1.11.4 → 2.4.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.
Files changed (167) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +129 -3
  3. package/lib/__tests__/setup.d.ts +5 -0
  4. package/lib/__tests__/setup.d.ts.map +1 -0
  5. package/lib/__tests__/setup.js +143 -0
  6. package/lib/__tests__/setup.js.map +1 -0
  7. package/lib/domain/repositories/ISettingsRepository.d.ts +51 -0
  8. package/lib/domain/repositories/ISettingsRepository.d.ts.map +1 -0
  9. package/lib/domain/repositories/ISettingsRepository.js +8 -0
  10. package/lib/domain/repositories/ISettingsRepository.js.map +1 -0
  11. package/lib/index.d.ts +35 -0
  12. package/lib/index.d.ts.map +1 -0
  13. package/lib/index.js +32 -0
  14. package/lib/index.js.map +1 -0
  15. package/lib/infrastructure/storage/SettingsStore.d.ts +36 -0
  16. package/lib/infrastructure/storage/SettingsStore.d.ts.map +1 -0
  17. package/lib/infrastructure/storage/SettingsStore.js +144 -0
  18. package/lib/infrastructure/storage/SettingsStore.js.map +1 -0
  19. package/lib/presentation/components/CloudSyncSetting.d.ts +16 -0
  20. package/lib/presentation/components/CloudSyncSetting.d.ts.map +1 -0
  21. package/lib/presentation/components/CloudSyncSetting.js +30 -0
  22. package/lib/presentation/components/CloudSyncSetting.js.map +1 -0
  23. package/lib/presentation/components/DisclaimerCard.d.ts +15 -0
  24. package/lib/presentation/components/DisclaimerCard.d.ts.map +1 -0
  25. package/lib/presentation/components/DisclaimerCard.js +73 -0
  26. package/lib/presentation/components/DisclaimerCard.js.map +1 -0
  27. package/lib/presentation/components/DisclaimerModal.d.ts +13 -0
  28. package/lib/presentation/components/DisclaimerModal.d.ts.map +1 -0
  29. package/lib/presentation/components/DisclaimerModal.js +62 -0
  30. package/lib/presentation/components/DisclaimerModal.js.map +1 -0
  31. package/lib/presentation/components/DisclaimerSetting.d.ts +39 -0
  32. package/lib/presentation/components/DisclaimerSetting.d.ts.map +1 -0
  33. package/lib/presentation/components/DisclaimerSetting.js +59 -0
  34. package/lib/presentation/components/DisclaimerSetting.js.map +1 -0
  35. package/lib/presentation/components/SettingItem.d.ts +45 -0
  36. package/lib/presentation/components/SettingItem.d.ts.map +1 -0
  37. package/lib/presentation/components/SettingItem.js +113 -0
  38. package/lib/presentation/components/SettingItem.js.map +1 -0
  39. package/lib/presentation/components/SettingsErrorBoundary.d.ts +23 -0
  40. package/lib/presentation/components/SettingsErrorBoundary.d.ts.map +1 -0
  41. package/lib/presentation/components/SettingsErrorBoundary.js +73 -0
  42. package/lib/presentation/components/SettingsErrorBoundary.js.map +1 -0
  43. package/lib/presentation/components/SettingsFooter.d.ts +11 -0
  44. package/lib/presentation/components/SettingsFooter.d.ts.map +1 -0
  45. package/lib/presentation/components/SettingsFooter.js +31 -0
  46. package/lib/presentation/components/SettingsFooter.js.map +1 -0
  47. package/lib/presentation/components/SettingsSection.d.ts +13 -0
  48. package/lib/presentation/components/SettingsSection.d.ts.map +1 -0
  49. package/lib/presentation/components/SettingsSection.js +37 -0
  50. package/lib/presentation/components/SettingsSection.js.map +1 -0
  51. package/lib/presentation/components/StorageClearSetting.d.ts +16 -0
  52. package/lib/presentation/components/StorageClearSetting.d.ts.map +1 -0
  53. package/lib/presentation/components/StorageClearSetting.js +21 -0
  54. package/lib/presentation/components/StorageClearSetting.js.map +1 -0
  55. package/lib/presentation/components/UserProfileHeader.d.ts +30 -0
  56. package/lib/presentation/components/UserProfileHeader.d.ts.map +1 -0
  57. package/lib/presentation/components/UserProfileHeader.js +119 -0
  58. package/lib/presentation/components/UserProfileHeader.js.map +1 -0
  59. package/lib/presentation/screens/AppearanceScreen.d.ts +8 -0
  60. package/lib/presentation/screens/AppearanceScreen.d.ts.map +1 -0
  61. package/lib/presentation/screens/AppearanceScreen.js +8 -0
  62. package/lib/presentation/screens/AppearanceScreen.js.map +1 -0
  63. package/lib/presentation/screens/SettingsScreen.d.ts +38 -0
  64. package/lib/presentation/screens/SettingsScreen.d.ts.map +1 -0
  65. package/lib/presentation/screens/SettingsScreen.js +37 -0
  66. package/lib/presentation/screens/SettingsScreen.js.map +1 -0
  67. package/lib/presentation/screens/components/AboutLegalSection.d.ts +15 -0
  68. package/lib/presentation/screens/components/AboutLegalSection.d.ts.map +1 -0
  69. package/lib/presentation/screens/components/AboutLegalSection.js +28 -0
  70. package/lib/presentation/screens/components/AboutLegalSection.js.map +1 -0
  71. package/lib/presentation/screens/components/AppearanceSection.d.ts +12 -0
  72. package/lib/presentation/screens/components/AppearanceSection.d.ts.map +1 -0
  73. package/lib/presentation/screens/components/AppearanceSection.js +21 -0
  74. package/lib/presentation/screens/components/AppearanceSection.js.map +1 -0
  75. package/lib/presentation/screens/components/LanguageSection.d.ts +12 -0
  76. package/lib/presentation/screens/components/LanguageSection.d.ts.map +1 -0
  77. package/lib/presentation/screens/components/LanguageSection.js +26 -0
  78. package/lib/presentation/screens/components/LanguageSection.js.map +1 -0
  79. package/lib/presentation/screens/components/NotificationsSection.d.ts +12 -0
  80. package/lib/presentation/screens/components/NotificationsSection.d.ts.map +1 -0
  81. package/lib/presentation/screens/components/NotificationsSection.js +58 -0
  82. package/lib/presentation/screens/components/NotificationsSection.js.map +1 -0
  83. package/lib/presentation/screens/components/SettingsContent.d.ts +36 -0
  84. package/lib/presentation/screens/components/SettingsContent.d.ts.map +1 -0
  85. package/lib/presentation/screens/components/SettingsContent.js +81 -0
  86. package/lib/presentation/screens/components/SettingsContent.js.map +1 -0
  87. package/lib/presentation/screens/components/SettingsHeader.d.ts +12 -0
  88. package/lib/presentation/screens/components/SettingsHeader.d.ts.map +1 -0
  89. package/lib/presentation/screens/components/SettingsHeader.js +59 -0
  90. package/lib/presentation/screens/components/SettingsHeader.js.map +1 -0
  91. package/lib/presentation/screens/components/index.d.ts +9 -0
  92. package/lib/presentation/screens/components/index.d.ts.map +1 -0
  93. package/lib/presentation/screens/components/index.js +9 -0
  94. package/lib/presentation/screens/components/index.js.map +1 -0
  95. package/lib/presentation/screens/hooks/useFeatureDetection.d.ts +21 -0
  96. package/lib/presentation/screens/hooks/useFeatureDetection.d.ts.map +1 -0
  97. package/lib/presentation/screens/hooks/useFeatureDetection.js +82 -0
  98. package/lib/presentation/screens/hooks/useFeatureDetection.js.map +1 -0
  99. package/lib/presentation/screens/types/CustomSection.d.ts +19 -0
  100. package/lib/presentation/screens/types/CustomSection.d.ts.map +1 -0
  101. package/lib/presentation/screens/types/CustomSection.js +6 -0
  102. package/lib/presentation/screens/types/CustomSection.js.map +1 -0
  103. package/lib/presentation/screens/types/ExtendedConfig.d.ts +68 -0
  104. package/lib/presentation/screens/types/ExtendedConfig.d.ts.map +1 -0
  105. package/lib/presentation/screens/types/ExtendedConfig.js +6 -0
  106. package/lib/presentation/screens/types/ExtendedConfig.js.map +1 -0
  107. package/lib/presentation/screens/types/FeatureConfig.d.ts +95 -0
  108. package/lib/presentation/screens/types/FeatureConfig.d.ts.map +1 -0
  109. package/lib/presentation/screens/types/FeatureConfig.js +6 -0
  110. package/lib/presentation/screens/types/FeatureConfig.js.map +1 -0
  111. package/lib/presentation/screens/types/SettingsConfig.d.ts +97 -0
  112. package/lib/presentation/screens/types/SettingsConfig.d.ts.map +1 -0
  113. package/lib/presentation/screens/types/SettingsConfig.js +6 -0
  114. package/lib/presentation/screens/types/SettingsConfig.js.map +1 -0
  115. package/lib/presentation/screens/types/index.d.ts +10 -0
  116. package/lib/presentation/screens/types/index.d.ts.map +1 -0
  117. package/lib/presentation/screens/types/index.js +6 -0
  118. package/lib/presentation/screens/types/index.js.map +1 -0
  119. package/lib/presentation/screens/utils/normalizeConfig.d.ts +44 -0
  120. package/lib/presentation/screens/utils/normalizeConfig.d.ts.map +1 -0
  121. package/lib/presentation/screens/utils/normalizeConfig.js +38 -0
  122. package/lib/presentation/screens/utils/normalizeConfig.js.map +1 -0
  123. package/package.json +46 -11
  124. package/src/__tests__/integration.test.tsx +371 -0
  125. package/src/__tests__/performance.test.tsx +369 -0
  126. package/src/__tests__/setup.test.tsx +20 -0
  127. package/src/__tests__/setup.ts +157 -0
  128. package/src/domain/repositories/ISettingsRepository.ts +0 -0
  129. package/src/index.ts +9 -1
  130. package/src/infrastructure/storage/SettingsStore.ts +90 -45
  131. package/src/infrastructure/storage/__tests__/SettingsStore.test.tsx +302 -0
  132. package/src/presentation/components/CloudSyncSetting.tsx +11 -17
  133. package/src/presentation/components/DisclaimerCard.tsx +115 -0
  134. package/src/presentation/components/DisclaimerModal.tsx +104 -0
  135. package/src/presentation/components/DisclaimerSetting.tsx +77 -159
  136. package/src/presentation/components/SettingItem.tsx +11 -2
  137. package/src/presentation/components/SettingsErrorBoundary.tsx +126 -0
  138. package/src/presentation/components/SettingsFooter.tsx +0 -0
  139. package/src/presentation/components/SettingsSection.tsx +0 -0
  140. package/src/presentation/components/StorageClearSetting.tsx +13 -8
  141. package/src/presentation/components/UserProfileHeader.tsx +48 -11
  142. package/src/presentation/components/__tests__/CloudSyncSetting.test.tsx +78 -0
  143. package/src/presentation/components/__tests__/DisclaimerCard.test.tsx +208 -0
  144. package/src/presentation/components/__tests__/DisclaimerModal.test.tsx +236 -0
  145. package/src/presentation/components/__tests__/DisclaimerSetting.test.tsx +74 -0
  146. package/src/presentation/components/__tests__/SettingItem.test.tsx +189 -0
  147. package/src/presentation/components/__tests__/SettingsErrorBoundary.test.tsx +186 -0
  148. package/src/presentation/screens/AppearanceScreen.tsx +0 -0
  149. package/src/presentation/screens/SettingsScreen.tsx +29 -159
  150. package/src/presentation/screens/__tests__/SettingsScreen.test.tsx +322 -0
  151. package/src/presentation/screens/components/AboutLegalSection.tsx +14 -5
  152. package/src/presentation/screens/components/AppearanceSection.tsx +1 -1
  153. package/src/presentation/screens/components/LanguageSection.tsx +2 -1
  154. package/src/presentation/screens/components/NotificationsSection.tsx +19 -14
  155. package/src/presentation/screens/components/SettingsContent.tsx +167 -0
  156. package/src/presentation/screens/components/SettingsHeader.tsx +79 -0
  157. package/src/presentation/screens/components/index.ts +0 -0
  158. package/src/presentation/screens/hooks/__tests__/useFeatureDetection.test.tsx +261 -0
  159. package/src/presentation/screens/hooks/useFeatureDetection.ts +15 -5
  160. package/src/presentation/screens/types/CustomSection.ts +20 -0
  161. package/src/presentation/screens/types/ExtendedConfig.ts +68 -0
  162. package/src/presentation/screens/types/FeatureConfig.ts +102 -0
  163. package/src/presentation/screens/types/SettingsConfig.ts +116 -0
  164. package/src/presentation/screens/types/index.ts +20 -0
  165. package/src/presentation/screens/utils/normalizeConfig.ts +2 -1
  166. package/src/presentation/screens/LanguageSelectionScreen.tsx +0 -204
  167. package/src/presentation/screens/types.ts +0 -263
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Settings Header Component
3
+ * Handles close button functionality
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, TouchableOpacity, StyleSheet } from "react-native";
8
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
9
+ import { useNavigation } from "@react-navigation/native";
10
+ import { useAppDesignTokens } from "@umituz/react-native-design-system-theme";
11
+ import { AtomicIcon } from "@umituz/react-native-design-system-atoms";
12
+
13
+ interface SettingsHeaderProps {
14
+ showCloseButton?: boolean;
15
+ onClose?: () => void;
16
+ }
17
+
18
+ export const SettingsHeader: React.FC<SettingsHeaderProps> = ({
19
+ showCloseButton = false,
20
+ onClose,
21
+ }) => {
22
+ const navigation = useNavigation();
23
+ const tokens = useAppDesignTokens();
24
+ const insets = useSafeAreaInsets();
25
+
26
+ const handleClose = () => {
27
+ if (onClose) {
28
+ onClose();
29
+ } else {
30
+ navigation.goBack();
31
+ }
32
+ };
33
+
34
+ if (!showCloseButton) {
35
+ return null;
36
+ }
37
+
38
+ return (
39
+ <View
40
+ style={[
41
+ styles.closeButtonContainer,
42
+ {
43
+ paddingTop: insets.top + tokens.spacing.xs,
44
+ paddingRight: tokens.spacing.md,
45
+ },
46
+ ]}
47
+ >
48
+ <TouchableOpacity
49
+ onPress={handleClose}
50
+ style={[
51
+ styles.closeButton,
52
+ {
53
+ backgroundColor: tokens.colors.surface,
54
+ },
55
+ ]}
56
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
57
+ >
58
+ <AtomicIcon name="X" size="lg" color="primary" />
59
+ </TouchableOpacity>
60
+ </View>
61
+ );
62
+ };
63
+
64
+ const styles = StyleSheet.create({
65
+ closeButtonContainer: {
66
+ position: "absolute",
67
+ top: 0,
68
+ right: 0,
69
+ zIndex: 10,
70
+ alignItems: "flex-end",
71
+ },
72
+ closeButton: {
73
+ width: 44,
74
+ height: 44,
75
+ borderRadius: 22,
76
+ justifyContent: "center",
77
+ alignItems: "center",
78
+ },
79
+ });
File without changes
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Tests for useFeatureDetection Hook
3
+ */
4
+
5
+ import { renderHook } from '@testing-library/react-hooks';
6
+ import { useFeatureDetection } from '../useFeatureDetection';
7
+ import type { NormalizedConfig } from '../../utils/normalizeConfig';
8
+
9
+ // Mock navigation
10
+ const mockNavigation = {
11
+ getState: jest.fn(() => ({
12
+ routes: [
13
+ { name: 'Settings' },
14
+ { name: 'Appearance' },
15
+ { name: 'Notifications' },
16
+ ],
17
+ })),
18
+ };
19
+
20
+ describe('useFeatureDetection', () => {
21
+ const mockConfig: NormalizedConfig = {
22
+ appearance: { enabled: true, config: { enabled: true } },
23
+ language: { enabled: true, config: { enabled: true } },
24
+ notifications: { enabled: true, config: { enabled: true } },
25
+ about: { enabled: true, config: { enabled: true } },
26
+ legal: { enabled: true, config: { enabled: true } },
27
+ account: { enabled: true, config: { enabled: true } },
28
+ support: { enabled: true, config: { enabled: true } },
29
+ developer: { enabled: true, config: { enabled: true } },
30
+ };
31
+
32
+ beforeEach(() => {
33
+ jest.clearAllMocks();
34
+ });
35
+
36
+ it('detects all features when enabled', () => {
37
+ const { result } = renderHook(() =>
38
+ useFeatureDetection(mockConfig, mockNavigation)
39
+ );
40
+
41
+ expect(result.current.appearance).toBe(true);
42
+ expect(result.current.language).toBe(true);
43
+ expect(result.current.notifications).toBe(true);
44
+ expect(result.current.about).toBe(true);
45
+ expect(result.current.legal).toBe(true);
46
+ expect(result.current.account).toBe(true);
47
+ expect(result.current.support).toBe(true);
48
+ expect(result.current.developer).toBe(true);
49
+ });
50
+
51
+ it('disables features when config disabled', () => {
52
+ const disabledConfig: NormalizedConfig = {
53
+ ...mockConfig,
54
+ appearance: { enabled: false, config: { enabled: true } },
55
+ notifications: { enabled: false, config: { enabled: true } },
56
+ };
57
+
58
+ const { result } = renderHook(() =>
59
+ useFeatureDetection(disabledConfig, mockNavigation)
60
+ );
61
+
62
+ expect(result.current.appearance).toBe(false);
63
+ expect(result.current.language).toBe(true);
64
+ expect(result.current.notifications).toBe(false);
65
+ expect(result.current.about).toBe(true);
66
+ });
67
+
68
+ it('checks navigation screen availability', () => {
69
+ const configWithRoutes: NormalizedConfig = {
70
+ ...mockConfig,
71
+ appearance: { enabled: true, config: { enabled: false, route: 'Appearance' } },
72
+ language: { enabled: true, config: { enabled: false, route: 'NonExistent' } },
73
+ };
74
+
75
+ const { result } = renderHook(() =>
76
+ useFeatureDetection(configWithRoutes, mockNavigation)
77
+ );
78
+
79
+ expect(result.current.appearance).toBe(true); // Route exists
80
+ expect(result.current.language).toBe(false); // Route doesn't exist
81
+ });
82
+
83
+ it('handles notification service availability', () => {
84
+ const { result } = renderHook(() =>
85
+ useFeatureDetection(mockConfig, mockNavigation, {
86
+ notificationServiceAvailable: false,
87
+ })
88
+ );
89
+
90
+ expect(result.current.notifications).toBe(false);
91
+ expect(result.current.appearance).toBe(true);
92
+ });
93
+
94
+ it('disables developer features in production', () => {
95
+ const originalDev = __DEV__;
96
+ (global as any).__DEV__ = false;
97
+
98
+ const { result } = renderHook(() =>
99
+ useFeatureDetection(mockConfig, mockNavigation)
100
+ );
101
+
102
+ expect(result.current.developer).toBe(false);
103
+ expect(result.current.appearance).toBe(true);
104
+
105
+ (global as any).__DEV__ = originalDev;
106
+ });
107
+
108
+ it('enables developer features in development', () => {
109
+ const originalDev = __DEV__;
110
+ (global as any).__DEV__ = true;
111
+
112
+ const { result } = renderHook(() =>
113
+ useFeatureDetection(mockConfig, mockNavigation)
114
+ );
115
+
116
+ expect(result.current.developer).toBe(true);
117
+
118
+ (global as any).__DEV__ = originalDev;
119
+ });
120
+
121
+ it('handles complex navigation state', () => {
122
+ const complexNavigation = {
123
+ getState: jest.fn(() => ({
124
+ routes: [
125
+ {
126
+ name: 'TabNavigator',
127
+ state: {
128
+ routes: [
129
+ {
130
+ name: 'SettingsStack',
131
+ state: {
132
+ routes: [
133
+ { name: 'Settings' },
134
+ { name: 'Appearance' },
135
+ ],
136
+ },
137
+ },
138
+ ],
139
+ },
140
+ },
141
+ ],
142
+ })),
143
+ };
144
+
145
+ const { result } = renderHook(() =>
146
+ useFeatureDetection(mockConfig, complexNavigation)
147
+ );
148
+
149
+ expect(result.current.appearance).toBe(true);
150
+ });
151
+
152
+ it('handles navigation errors gracefully', () => {
153
+ const errorNavigation = {
154
+ getState: jest.fn(() => {
155
+ throw new Error('Navigation error');
156
+ }),
157
+ };
158
+
159
+ const { result } = renderHook(() =>
160
+ useFeatureDetection(mockConfig, errorNavigation)
161
+ );
162
+
163
+ expect(result.current.appearance).toBe(false);
164
+ expect(result.current.language).toBe(false);
165
+ });
166
+
167
+ it('handles missing navigation state', () => {
168
+ const emptyNavigation = {
169
+ getState: jest.fn(() => null),
170
+ };
171
+
172
+ const { result } = renderHook(() =>
173
+ useFeatureDetection(mockConfig, emptyNavigation)
174
+ );
175
+
176
+ expect(result.current.appearance).toBe(false);
177
+ expect(result.current.language).toBe(false);
178
+ });
179
+
180
+ it('handles malformed navigation routes', () => {
181
+ const malformedNavigation = {
182
+ getState: jest.fn(() => ({
183
+ routes: null,
184
+ })),
185
+ };
186
+
187
+ const { result } = renderHook(() =>
188
+ useFeatureDetection(mockConfig, malformedNavigation)
189
+ );
190
+
191
+ expect(result.current.appearance).toBe(false);
192
+ });
193
+
194
+ it('memoizes results correctly', () => {
195
+ const { result, rerender } = renderHook(() =>
196
+ useFeatureDetection(mockConfig, mockNavigation)
197
+ );
198
+
199
+ const firstResult = result.current;
200
+
201
+ rerender();
202
+
203
+ expect(result.current).toBe(firstResult);
204
+ });
205
+
206
+ it('updates when config changes', () => {
207
+ const { result, rerender } = renderHook(
208
+ ({ config }) => useFeatureDetection(config, mockNavigation),
209
+ {
210
+ initialProps: { config: mockConfig },
211
+ }
212
+ );
213
+
214
+ expect(result.current.appearance).toBe(true);
215
+
216
+ const newConfig = {
217
+ ...mockConfig,
218
+ appearance: { enabled: false, config: { enabled: true } },
219
+ };
220
+
221
+ rerender({ config: newConfig });
222
+
223
+ expect(result.current.appearance).toBe(false);
224
+ });
225
+
226
+ it('updates when navigation changes', () => {
227
+ const { result, rerender } = renderHook(
228
+ ({ navigation }) => useFeatureDetection(mockConfig, navigation),
229
+ {
230
+ initialProps: { navigation: mockNavigation },
231
+ }
232
+ );
233
+
234
+ expect(result.current.appearance).toBe(true);
235
+
236
+ const newNavigation = {
237
+ getState: jest.fn(() => ({
238
+ routes: [{ name: 'Settings' }], // No Appearance route
239
+ })),
240
+ };
241
+
242
+ rerender({ navigation: newNavigation });
243
+
244
+ expect(result.current.appearance).toBe(false);
245
+ });
246
+
247
+ it('handles default route names', () => {
248
+ const configWithoutRoutes: NormalizedConfig = {
249
+ ...mockConfig,
250
+ appearance: { enabled: true, config: { enabled: false } }, // No route specified
251
+ language: { enabled: true, config: { enabled: false } },
252
+ };
253
+
254
+ const { result } = renderHook(() =>
255
+ useFeatureDetection(configWithoutRoutes, mockNavigation)
256
+ );
257
+
258
+ expect(result.current.appearance).toBe(true); // Should check default "Appearance" route
259
+ expect(result.current.language).toBe(true); // Should check default "LanguageSelection" route
260
+ });
261
+ });
@@ -7,11 +7,16 @@ import { useMemo } from "react";
7
7
  import type { NormalizedConfig } from "../utils/normalizeConfig";
8
8
 
9
9
  // Optional notification service
10
- let notificationService: any = null;
10
+ let notificationService: {
11
+ hasPermissions?: () => Promise<boolean>;
12
+ requestPermissions?: () => Promise<void>;
13
+ } | null = null;
11
14
  try {
12
15
  // eslint-disable-next-line @typescript-eslint/no-require-imports
13
- notificationService = require("@umituz/react-native-notifications")
14
- .notificationService;
16
+ const module = require("@umituz/react-native-notifications");
17
+ if (module?.notificationService && typeof module.notificationService === 'object') {
18
+ notificationService = module.notificationService;
19
+ }
15
20
  } catch {
16
21
  // Package not available
17
22
  }
@@ -51,10 +56,15 @@ function hasNavigationScreen(
51
56
  export function useFeatureDetection(
52
57
  normalizedConfig: NormalizedConfig,
53
58
  navigation: any,
59
+ options?: {
60
+ notificationServiceAvailable?: boolean;
61
+ },
54
62
  ) {
55
63
  return useMemo(() => {
56
64
  const { appearance, language, notifications, about, legal, account, support, developer } =
57
65
  normalizedConfig;
66
+
67
+ const notificationServiceAvailable = options?.notificationServiceAvailable ?? notificationService !== null;
58
68
 
59
69
  return {
60
70
  appearance:
@@ -77,7 +87,7 @@ export function useFeatureDetection(
77
87
  notifications.enabled &&
78
88
  (notifications.config?.enabled === true ||
79
89
  (notifications.config?.enabled !== false &&
80
- notificationService !== null &&
90
+ notificationServiceAvailable &&
81
91
  hasNavigationScreen(
82
92
  navigation,
83
93
  notifications.config?.route || "Notifications",
@@ -103,6 +113,6 @@ export function useFeatureDetection(
103
113
  support: support.enabled,
104
114
  developer: developer.enabled && __DEV__,
105
115
  };
106
- }, [normalizedConfig, navigation]);
116
+ }, [normalizedConfig, navigation, options]);
107
117
  }
108
118
 
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Custom Settings Section Type
3
+ * Allows apps to add custom sections to the settings screen
4
+ */
5
+
6
+ import type { ReactNode } from "react";
7
+
8
+ /**
9
+ * Custom Settings Section
10
+ */
11
+ export interface CustomSettingsSection {
12
+ /** Section title */
13
+ title: string;
14
+ /** Section content (React nodes) */
15
+ content: ReactNode;
16
+ /** Section order (lower = higher in list) */
17
+ order?: number;
18
+ /** Section ID for identification */
19
+ id?: string;
20
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Extended Configuration Types
3
+ * Account, Support, and Developer configurations
4
+ */
5
+
6
+ import type { ComponentType } from "react";
7
+ import type { FeatureVisibility } from "./FeatureConfig";
8
+
9
+ /**
10
+ * Account Settings Configuration
11
+ */
12
+ export interface AccountConfig {
13
+ /** Show account section */
14
+ enabled?: FeatureVisibility;
15
+ /** Custom navigation route for account screen */
16
+ route?: string;
17
+ /** Custom account title */
18
+ title?: string;
19
+ /** Custom account description */
20
+ description?: string;
21
+ }
22
+
23
+ /**
24
+ * Support Settings Configuration
25
+ */
26
+ export interface SupportConfig {
27
+ /** Show support section */
28
+ enabled?: FeatureVisibility;
29
+ /** Support items configuration */
30
+ items?: {
31
+ /** Live support configuration */
32
+ liveSupport?: {
33
+ enabled?: boolean;
34
+ route?: string;
35
+ title?: string;
36
+ description?: string;
37
+ };
38
+ /** Help support configuration */
39
+ helpSupport?: {
40
+ enabled?: boolean;
41
+ route?: string;
42
+ title?: string;
43
+ description?: string;
44
+ };
45
+ };
46
+ /** Custom support section title */
47
+ title?: string;
48
+ }
49
+
50
+ /**
51
+ * Developer Settings Configuration
52
+ */
53
+ export interface DeveloperConfig {
54
+ /** Show developer section (only in __DEV__ mode) */
55
+ enabled?: boolean;
56
+ /** Developer settings items */
57
+ items?: Array<{
58
+ title: string;
59
+ description?: string;
60
+ route?: string;
61
+ onPress?: () => void;
62
+ icon?: ComponentType<{ size?: number; color?: string }>;
63
+ iconColor?: string;
64
+ titleColor?: string;
65
+ }>;
66
+ /** Custom developer section title */
67
+ title?: string;
68
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Feature Configuration Types
3
+ * Core types for feature visibility and configuration
4
+ */
5
+
6
+ import type { ComponentType, ReactNode } from "react";
7
+
8
+ /**
9
+ * Feature visibility configuration
10
+ * - true: Always show (if navigation screen exists)
11
+ * - false: Never show
12
+ * - 'auto': Automatically detect (check if navigation screen exists and package is available)
13
+ */
14
+ export type FeatureVisibility = boolean | "auto";
15
+
16
+ /**
17
+ * Appearance Settings Configuration
18
+ */
19
+ export interface AppearanceConfig {
20
+ /** Show appearance section */
21
+ enabled?: FeatureVisibility;
22
+ /** Custom navigation route for appearance screen */
23
+ route?: string;
24
+ /** Show theme toggle */
25
+ showTheme?: boolean;
26
+ /** Custom appearance title */
27
+ title?: string;
28
+ /** Custom appearance description */
29
+ description?: string;
30
+ /** Default route name when no custom route provided */
31
+ defaultRoute?: string;
32
+ }
33
+
34
+ /**
35
+ * Language Settings Configuration
36
+ */
37
+ export interface LanguageConfig {
38
+ /** Show language section */
39
+ enabled?: FeatureVisibility;
40
+ /** Custom navigation route for language selection screen */
41
+ route?: string;
42
+ /** Custom language title */
43
+ title?: string;
44
+ /** Custom language description */
45
+ description?: string;
46
+ /** Default language display when no language is detected */
47
+ defaultLanguageDisplay?: string;
48
+ }
49
+
50
+ /**
51
+ * Notifications Settings Configuration
52
+ */
53
+ export interface NotificationsConfig {
54
+ /** Show notifications section */
55
+ enabled?: FeatureVisibility;
56
+ /** Show notification toggle switch */
57
+ showToggle?: boolean;
58
+ /** Initial toggle value */
59
+ initialValue?: boolean;
60
+ /** Toggle change handler */
61
+ onToggleChange?: (value: boolean) => void;
62
+ /** Custom navigation route for notifications screen */
63
+ route?: string;
64
+ /** Custom notifications title */
65
+ title?: string;
66
+ /** Custom notifications description */
67
+ description?: string;
68
+ /** Default route name when no custom route provided */
69
+ defaultRoute?: string;
70
+ }
71
+
72
+ /**
73
+ * About Settings Configuration
74
+ */
75
+ export interface AboutConfig {
76
+ /** Show about section */
77
+ enabled?: FeatureVisibility;
78
+ /** Custom navigation route for about screen */
79
+ route?: string;
80
+ /** Custom about title */
81
+ title?: string;
82
+ /** Custom about description */
83
+ description?: string;
84
+ /** Default route name when no custom route provided */
85
+ defaultRoute?: string;
86
+ }
87
+
88
+ /**
89
+ * Legal Settings Configuration
90
+ */
91
+ export interface LegalConfig {
92
+ /** Show legal section */
93
+ enabled?: FeatureVisibility;
94
+ /** Custom navigation route for legal screen */
95
+ route?: string;
96
+ /** Custom legal title */
97
+ title?: string;
98
+ /** Custom legal description */
99
+ description?: string;
100
+ /** Default route name when no custom route provided */
101
+ defaultRoute?: string;
102
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Main Settings Configuration Type
3
+ * Combines all feature configurations
4
+ */
5
+
6
+ import type { FeatureVisibility } from "./FeatureConfig";
7
+ import type {
8
+ AppearanceConfig,
9
+ LanguageConfig,
10
+ NotificationsConfig,
11
+ AboutConfig,
12
+ LegalConfig,
13
+ } from "./FeatureConfig";
14
+ import type {
15
+ AccountConfig,
16
+ SupportConfig,
17
+ DeveloperConfig,
18
+ } from "./ExtendedConfig";
19
+
20
+ /**
21
+ * Main Settings Configuration
22
+ *
23
+ * Controls which settings features are visible in the SettingsScreen.
24
+ * Each feature can be configured with:
25
+ * - Simple: boolean | 'auto' (quick setup)
26
+ * - Advanced: Detailed config object (full control)
27
+ *
28
+ * @example
29
+ * // Simple configuration
30
+ * const config: SettingsConfig = {
31
+ * appearance: true,
32
+ * notifications: 'auto',
33
+ * about: false,
34
+ * };
35
+ *
36
+ * @example
37
+ * // Advanced configuration
38
+ * const config: SettingsConfig = {
39
+ * appearance: {
40
+ * enabled: true,
41
+ * route: 'CustomAppearance',
42
+ * showLanguage: true,
43
+ * showTheme: true,
44
+ * },
45
+ * notifications: {
46
+ * enabled: 'auto',
47
+ * showToggle: true,
48
+ * initialValue: false,
49
+ * onToggleChange: (value) => console.log(value),
50
+ * },
51
+ * support: {
52
+ * enabled: true,
53
+ * items: {
54
+ * liveSupport: {
55
+ * enabled: true,
56
+ * route: 'ChatSupport',
57
+ * title: 'Live Chat',
58
+ * },
59
+ * },
60
+ * },
61
+ * };
62
+ */
63
+ export interface SettingsConfig {
64
+ /**
65
+ * Appearance settings (Theme customization)
66
+ * @default 'auto'
67
+ */
68
+ appearance?: FeatureVisibility | AppearanceConfig;
69
+
70
+ /**
71
+ * Language settings
72
+ * @default 'auto'
73
+ */
74
+ language?: FeatureVisibility | LanguageConfig;
75
+
76
+ /**
77
+ * Notifications settings
78
+ * @default 'auto'
79
+ */
80
+ notifications?: FeatureVisibility | NotificationsConfig;
81
+
82
+ /**
83
+ * About settings
84
+ * @default 'auto'
85
+ */
86
+ about?: FeatureVisibility | AboutConfig;
87
+
88
+ /**
89
+ * Legal settings (Terms, Privacy Policy)
90
+ * @default 'auto'
91
+ */
92
+ legal?: FeatureVisibility | LegalConfig;
93
+
94
+ /**
95
+ * Account settings
96
+ * @default false
97
+ */
98
+ account?: FeatureVisibility | AccountConfig;
99
+
100
+ /**
101
+ * Support settings
102
+ * @default false
103
+ */
104
+ support?: FeatureVisibility | SupportConfig;
105
+
106
+ /**
107
+ * Developer settings (only shown in __DEV__ mode)
108
+ * @default false
109
+ */
110
+ developer?: boolean | DeveloperConfig;
111
+
112
+ /**
113
+ * Custom empty state text when no settings are available
114
+ */
115
+ emptyStateText?: string;
116
+ }