@umituz/react-native-settings 4.20.62 → 4.21.2

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 (70) hide show
  1. package/package.json +6 -61
  2. package/src/domains/feedback/domain/entities/FeedbackEntity.ts +8 -8
  3. package/src/domains/gamification/components/AchievementCard.tsx +142 -0
  4. package/src/domains/gamification/components/AchievementItem.tsx +182 -0
  5. package/src/domains/gamification/components/AchievementToast.tsx +122 -0
  6. package/src/domains/gamification/components/GamificationScreen/AchievementsList.tsx +84 -0
  7. package/src/domains/gamification/components/GamificationScreen/Header.tsx +29 -0
  8. package/src/domains/gamification/components/GamificationScreen/StatsGrid.tsx +51 -0
  9. package/src/domains/gamification/components/GamificationScreen/index.tsx +111 -0
  10. package/src/domains/gamification/components/GamificationScreen/styles.ts +43 -0
  11. package/src/domains/gamification/components/GamificationScreen/types.ts +77 -0
  12. package/src/domains/gamification/components/GamificationScreenWrapper.tsx +4 -4
  13. package/src/domains/gamification/components/GamificationSettingsItem.tsx +1 -1
  14. package/src/domains/gamification/components/LevelProgress.tsx +129 -0
  15. package/src/domains/gamification/components/PointsBadge.tsx +60 -0
  16. package/src/domains/gamification/components/StatsCard.tsx +89 -0
  17. package/src/domains/gamification/components/StreakDisplay.tsx +119 -0
  18. package/src/domains/gamification/components/index.ts +13 -0
  19. package/src/domains/gamification/examples/gamification.config.example.ts +1 -1
  20. package/src/domains/gamification/hooks/useGamification.ts +91 -0
  21. package/src/domains/gamification/index.ts +46 -19
  22. package/src/domains/gamification/store/gamificationStore.ts +162 -0
  23. package/src/domains/gamification/types/index.ts +95 -23
  24. package/src/domains/gamification/types/settings.ts +28 -0
  25. package/src/domains/gamification/utils/calculations.ts +85 -0
  26. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -51
  27. package/.github/ISSUE_TEMPLATE/documentation.md +0 -52
  28. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -63
  29. package/.github/PULL_REQUEST_TEMPLATE.md +0 -84
  30. package/AI_AGENT_GUIDELINES.md +0 -367
  31. package/ARCHITECTURE.md +0 -246
  32. package/CHANGELOG.md +0 -67
  33. package/CODE_OF_CONDUCT.md +0 -75
  34. package/CONTRIBUTING.md +0 -107
  35. package/DOCUMENTATION_MIGRATION.md +0 -319
  36. package/DOCUMENTATION_TEMPLATE.md +0 -155
  37. package/SECURITY.md +0 -98
  38. package/SETTINGS_SCREEN_GUIDE.md +0 -185
  39. package/TESTING.md +0 -358
  40. package/src/__tests__/integration.test.tsx +0 -371
  41. package/src/__tests__/performance.test.tsx +0 -369
  42. package/src/__tests__/setup.test.tsx +0 -20
  43. package/src/__tests__/setup.ts +0 -154
  44. package/src/domains/about/__tests__/integration.test.tsx +0 -328
  45. package/src/domains/about/__tests__/types.d.ts +0 -5
  46. package/src/domains/about/domain/entities/__tests__/AppInfo.test.ts +0 -93
  47. package/src/domains/about/infrastructure/repositories/__tests__/AboutRepository.test.ts +0 -153
  48. package/src/domains/about/presentation/components/__tests__/AboutContent.simple.test.tsx +0 -178
  49. package/src/domains/about/presentation/components/__tests__/AboutContent.test.tsx +0 -293
  50. package/src/domains/about/presentation/components/__tests__/AboutHeader.test.tsx +0 -201
  51. package/src/domains/about/presentation/components/__tests__/AboutSettingItem.test.tsx +0 -71
  52. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.simple.test.tsx +0 -229
  53. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.test.tsx +0 -240
  54. package/src/domains/about/presentation/screens/__tests__/AboutScreen.simple.test.tsx +0 -199
  55. package/src/domains/about/presentation/screens/__tests__/AboutScreen.test.tsx +0 -366
  56. package/src/domains/about/utils/__tests__/index.test.ts +0 -408
  57. package/src/domains/appearance/__tests__/components/AppearanceScreen.test.tsx +0 -195
  58. package/src/domains/appearance/__tests__/hooks/index.test.tsx +0 -232
  59. package/src/domains/appearance/__tests__/integration/index.test.tsx +0 -207
  60. package/src/domains/appearance/__tests__/services/appearanceService.test.ts +0 -299
  61. package/src/domains/appearance/__tests__/setup.ts +0 -88
  62. package/src/domains/appearance/__tests__/stores/appearanceStore.test.tsx +0 -175
  63. package/src/domains/cloud-sync/presentation/components/__tests__/CloudSyncSetting.test.tsx +0 -78
  64. package/src/domains/legal/__tests__/ContentValidationService.test.ts +0 -195
  65. package/src/domains/legal/__tests__/StyleCacheService.test.ts +0 -110
  66. package/src/domains/legal/__tests__/UrlHandlerService.test.ts +0 -71
  67. package/src/domains/legal/__tests__/setup.ts +0 -82
  68. package/src/presentation/components/__tests__/SettingsErrorBoundary.test.tsx +0 -186
  69. package/src/presentation/screens/__tests__/SettingsScreen.test.tsx +0 -322
  70. package/src/presentation/screens/hooks/__tests__/useFeatureDetection.test.tsx +0 -261
@@ -1,322 +0,0 @@
1
- /**
2
- * Tests for SettingsScreen Component
3
- */
4
-
5
- import React from 'react';
6
- import { render, fireEvent } from '@testing-library/react-native';
7
- import { SettingsScreen } from '../SettingsScreen';
8
- import { NavigationContainer } from '@react-navigation/native';
9
-
10
- // Mock dependencies
11
- jest.mock('@umituz/react-native-design-system', () => ({
12
- useDesignSystemTheme: () => ({
13
- themeMode: 'light',
14
- }),
15
- useAppDesignTokens: () => ({
16
- colors: {
17
- backgroundPrimary: '#ffffff',
18
- },
19
- }),
20
- }));
21
-
22
- jest.mock('../components/SettingsHeader', () => 'SettingsHeader');
23
- jest.mock('../components/SettingsContent', () => 'SettingsContent');
24
- jest.mock('../components/SettingsErrorBoundary', () => 'SettingsErrorBoundary');
25
- jest.mock('../utils/normalizeConfig', () => ({
26
- normalizeSettingsConfig: jest.fn((config) => ({
27
- appearance: { enabled: true, config: { enabled: true } },
28
- language: { enabled: true, config: { enabled: true } },
29
- notifications: { enabled: true, config: { enabled: true } },
30
- about: { enabled: true, config: { enabled: true } },
31
- legal: { enabled: true, config: { enabled: true } },
32
- account: { enabled: true, config: { enabled: true } },
33
- support: { enabled: true, config: { enabled: true } },
34
- developer: { enabled: true, config: { enabled: true } },
35
- })),
36
- }));
37
-
38
- jest.mock('../hooks/useFeatureDetection', () => ({
39
- useFeatureDetection: jest.fn(() => ({
40
- appearance: true,
41
- language: true,
42
- notifications: true,
43
- about: true,
44
- legal: true,
45
- account: true,
46
- support: true,
47
- developer: false,
48
- })),
49
- }));
50
-
51
- // Mock navigation
52
- const mockNavigation = {
53
- navigate: jest.fn(),
54
- goBack: jest.fn(),
55
- getState: jest.fn(() => ({
56
- routes: [{ name: 'Settings' }],
57
- })),
58
- };
59
-
60
- jest.mock('@react-navigation/native', () => ({
61
- useNavigation: () => mockNavigation,
62
- }));
63
-
64
- // Wrapper component for navigation context
65
- const TestWrapper = ({ children }: { children: React.ReactNode }) => (
66
- <NavigationContainer>
67
- {children}
68
- </NavigationContainer>
69
- );
70
-
71
- describe('SettingsScreen', () => {
72
- beforeEach(() => {
73
- jest.clearAllMocks();
74
- });
75
-
76
- it('renders correctly with default props', () => {
77
- const { getByTestId } = render(
78
- <TestWrapper>
79
- <SettingsScreen />
80
- </TestWrapper>
81
- );
82
-
83
- // Should render the main container
84
- expect(getByTestId('settings-screen')).toBeTruthy();
85
- });
86
-
87
- it('renders with custom config', () => {
88
- const config = {
89
- appearance: true,
90
- notifications: false,
91
- about: true,
92
- };
93
-
94
- const { getByTestId } = render(
95
- <TestWrapper>
96
- <SettingsScreen config={config} />
97
- </TestWrapper>
98
- );
99
-
100
- expect(getByTestId('settings-screen')).toBeTruthy();
101
- });
102
-
103
- it('renders with user profile header', () => {
104
- const userProfile = {
105
- displayName: 'John Doe',
106
- userId: 'user123',
107
- isGuest: false,
108
- };
109
-
110
- const { getByTestId } = render(
111
- <TestWrapper>
112
- <SettingsScreen
113
- showUserProfile={true}
114
- userProfile={userProfile}
115
- />
116
- </TestWrapper>
117
- );
118
-
119
- expect(getByTestId('settings-screen')).toBeTruthy();
120
- });
121
-
122
- it('renders with custom footer text', () => {
123
- const { getByTestId } = render(
124
- <TestWrapper>
125
- <SettingsScreen
126
- footerText="Custom Footer Text"
127
- />
128
- </TestWrapper>
129
- );
130
-
131
- expect(getByTestId('settings-screen')).toBeTruthy();
132
- });
133
-
134
- it('renders with custom sections', () => {
135
- const customSections = [
136
- {
137
- title: 'Custom Section',
138
- data: [
139
- {
140
- id: 'custom-item',
141
- title: 'Custom Item',
142
- icon: 'Settings',
143
- },
144
- ],
145
- },
146
- ];
147
-
148
- const { getByTestId } = render(
149
- <TestWrapper>
150
- <SettingsScreen
151
- customSections={customSections}
152
- />
153
- </TestWrapper>
154
- );
155
-
156
- expect(getByTestId('settings-screen')).toBeTruthy();
157
- });
158
-
159
- it('renders with close button', () => {
160
- const mockOnClose = jest.fn();
161
-
162
- const { getByTestId } = render(
163
- <TestWrapper>
164
- <SettingsScreen
165
- showCloseButton={true}
166
- onClose={mockOnClose}
167
- />
168
- </TestWrapper>
169
- );
170
-
171
- expect(getByTestId('settings-screen')).toBeTruthy();
172
- });
173
-
174
- it('applies correct theme styling', () => {
175
- const { getByTestId } = render(
176
- <TestWrapper>
177
- <SettingsScreen />
178
- </TestWrapper>
179
- );
180
-
181
- const container = getByTestId('settings-screen');
182
- expect(container.props.style).toContainEqual({
183
- backgroundColor: '#ffffff',
184
- });
185
- });
186
-
187
- it('handles feature detection options', () => {
188
- const featureOptions = {
189
- notificationServiceAvailable: false,
190
- };
191
-
192
- const { getByTestId } = render(
193
- <TestWrapper>
194
- <SettingsScreen
195
- featureOptions={featureOptions}
196
- />
197
- </TestWrapper>
198
- );
199
-
200
- expect(getByTestId('settings-screen')).toBeTruthy();
201
- });
202
-
203
- it('wraps content in error boundary', () => {
204
- const { getByTestId } = render(
205
- <TestWrapper>
206
- <SettingsScreen />
207
- </TestWrapper>
208
- );
209
-
210
- expect(getByTestId('settings-screen')).toBeTruthy();
211
- });
212
-
213
- it('renders without footer when showFooter is false', () => {
214
- const { getByTestId } = render(
215
- <TestWrapper>
216
- <SettingsScreen
217
- showFooter={false}
218
- />
219
- </TestWrapper>
220
- );
221
-
222
- expect(getByTestId('settings-screen')).toBeTruthy();
223
- });
224
-
225
- it('handles guest user profile', () => {
226
- const guestProfile = {
227
- displayName: 'Guest User',
228
- userId: 'guest123',
229
- isGuest: true,
230
- guestDisplayName: 'Guest',
231
- };
232
-
233
- const { getByTestId } = render(
234
- <TestWrapper>
235
- <SettingsScreen
236
- showUserProfile={true}
237
- userProfile={guestProfile}
238
- />
239
- </TestWrapper>
240
- );
241
-
242
- expect(getByTestId('settings-screen')).toBeTruthy();
243
- });
244
-
245
- it('handles user profile with avatar', () => {
246
- const profileWithAvatar = {
247
- displayName: 'John Doe',
248
- userId: 'user123',
249
- isGuest: false,
250
- avatarUrl: 'https://example.com/avatar.jpg',
251
- };
252
-
253
- const { getByTestId } = render(
254
- <TestWrapper>
255
- <SettingsScreen
256
- showUserProfile={true}
257
- userProfile={profileWithAvatar}
258
- />
259
- </TestWrapper>
260
- );
261
-
262
- expect(getByTestId('settings-screen')).toBeTruthy();
263
- });
264
-
265
- it('handles empty config', () => {
266
- const { getByTestId } = render(
267
- <TestWrapper>
268
- <SettingsScreen config={{}} />
269
- </TestWrapper>
270
- );
271
-
272
- expect(getByTestId('settings-screen')).toBeTruthy();
273
- });
274
-
275
- it('handles missing user profile props', () => {
276
- const { getByTestId } = render(
277
- <TestWrapper>
278
- <SettingsScreen
279
- showUserProfile={true}
280
- userProfile={{}}
281
- />
282
- </TestWrapper>
283
- );
284
-
285
- expect(getByTestId('settings-screen')).toBeTruthy();
286
- });
287
-
288
- it('handles null custom sections', () => {
289
- const { getByTestId } = render(
290
- <TestWrapper>
291
- <SettingsScreen
292
- customSections={null as any}
293
- />
294
- </TestWrapper>
295
- );
296
-
297
- expect(getByTestId('settings-screen')).toBeTruthy();
298
- });
299
-
300
- it('handles undefined feature options', () => {
301
- const { getByTestId } = render(
302
- <TestWrapper>
303
- <SettingsScreen
304
- featureOptions={undefined as any}
305
- />
306
- </TestWrapper>
307
- );
308
-
309
- expect(getByTestId('settings-screen')).toBeTruthy();
310
- });
311
-
312
- it('maintains correct component structure', () => {
313
- const { getByTestId } = render(
314
- <TestWrapper>
315
- <SettingsScreen />
316
- </TestWrapper>
317
- );
318
-
319
- // Should have main container
320
- expect(getByTestId('settings-screen')).toBeTruthy();
321
- });
322
- });
@@ -1,261 +0,0 @@
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
- });