@umituz/react-native-settings 4.20.62 → 4.21.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.
Files changed (69) hide show
  1. package/package.json +6 -61
  2. package/src/domains/gamification/components/AchievementCard.tsx +142 -0
  3. package/src/domains/gamification/components/AchievementItem.tsx +182 -0
  4. package/src/domains/gamification/components/AchievementToast.tsx +122 -0
  5. package/src/domains/gamification/components/GamificationScreen/AchievementsList.tsx +84 -0
  6. package/src/domains/gamification/components/GamificationScreen/Header.tsx +29 -0
  7. package/src/domains/gamification/components/GamificationScreen/StatsGrid.tsx +51 -0
  8. package/src/domains/gamification/components/GamificationScreen/index.tsx +111 -0
  9. package/src/domains/gamification/components/GamificationScreen/styles.ts +43 -0
  10. package/src/domains/gamification/components/GamificationScreen/types.ts +77 -0
  11. package/src/domains/gamification/components/GamificationScreenWrapper.tsx +4 -4
  12. package/src/domains/gamification/components/GamificationSettingsItem.tsx +1 -1
  13. package/src/domains/gamification/components/LevelProgress.tsx +129 -0
  14. package/src/domains/gamification/components/PointsBadge.tsx +60 -0
  15. package/src/domains/gamification/components/StatsCard.tsx +89 -0
  16. package/src/domains/gamification/components/StreakDisplay.tsx +119 -0
  17. package/src/domains/gamification/components/index.ts +13 -0
  18. package/src/domains/gamification/examples/gamification.config.example.ts +1 -1
  19. package/src/domains/gamification/hooks/useGamification.ts +91 -0
  20. package/src/domains/gamification/index.ts +46 -19
  21. package/src/domains/gamification/store/gamificationStore.ts +162 -0
  22. package/src/domains/gamification/types/index.ts +95 -23
  23. package/src/domains/gamification/types/settings.ts +28 -0
  24. package/src/domains/gamification/utils/calculations.ts +85 -0
  25. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -51
  26. package/.github/ISSUE_TEMPLATE/documentation.md +0 -52
  27. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -63
  28. package/.github/PULL_REQUEST_TEMPLATE.md +0 -84
  29. package/AI_AGENT_GUIDELINES.md +0 -367
  30. package/ARCHITECTURE.md +0 -246
  31. package/CHANGELOG.md +0 -67
  32. package/CODE_OF_CONDUCT.md +0 -75
  33. package/CONTRIBUTING.md +0 -107
  34. package/DOCUMENTATION_MIGRATION.md +0 -319
  35. package/DOCUMENTATION_TEMPLATE.md +0 -155
  36. package/SECURITY.md +0 -98
  37. package/SETTINGS_SCREEN_GUIDE.md +0 -185
  38. package/TESTING.md +0 -358
  39. package/src/__tests__/integration.test.tsx +0 -371
  40. package/src/__tests__/performance.test.tsx +0 -369
  41. package/src/__tests__/setup.test.tsx +0 -20
  42. package/src/__tests__/setup.ts +0 -154
  43. package/src/domains/about/__tests__/integration.test.tsx +0 -328
  44. package/src/domains/about/__tests__/types.d.ts +0 -5
  45. package/src/domains/about/domain/entities/__tests__/AppInfo.test.ts +0 -93
  46. package/src/domains/about/infrastructure/repositories/__tests__/AboutRepository.test.ts +0 -153
  47. package/src/domains/about/presentation/components/__tests__/AboutContent.simple.test.tsx +0 -178
  48. package/src/domains/about/presentation/components/__tests__/AboutContent.test.tsx +0 -293
  49. package/src/domains/about/presentation/components/__tests__/AboutHeader.test.tsx +0 -201
  50. package/src/domains/about/presentation/components/__tests__/AboutSettingItem.test.tsx +0 -71
  51. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.simple.test.tsx +0 -229
  52. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.test.tsx +0 -240
  53. package/src/domains/about/presentation/screens/__tests__/AboutScreen.simple.test.tsx +0 -199
  54. package/src/domains/about/presentation/screens/__tests__/AboutScreen.test.tsx +0 -366
  55. package/src/domains/about/utils/__tests__/index.test.ts +0 -408
  56. package/src/domains/appearance/__tests__/components/AppearanceScreen.test.tsx +0 -195
  57. package/src/domains/appearance/__tests__/hooks/index.test.tsx +0 -232
  58. package/src/domains/appearance/__tests__/integration/index.test.tsx +0 -207
  59. package/src/domains/appearance/__tests__/services/appearanceService.test.ts +0 -299
  60. package/src/domains/appearance/__tests__/setup.ts +0 -88
  61. package/src/domains/appearance/__tests__/stores/appearanceStore.test.tsx +0 -175
  62. package/src/domains/cloud-sync/presentation/components/__tests__/CloudSyncSetting.test.tsx +0 -78
  63. package/src/domains/legal/__tests__/ContentValidationService.test.ts +0 -195
  64. package/src/domains/legal/__tests__/StyleCacheService.test.ts +0 -110
  65. package/src/domains/legal/__tests__/UrlHandlerService.test.ts +0 -71
  66. package/src/domains/legal/__tests__/setup.ts +0 -82
  67. package/src/presentation/components/__tests__/SettingsErrorBoundary.test.tsx +0 -186
  68. package/src/presentation/screens/__tests__/SettingsScreen.test.tsx +0 -322
  69. 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
- });