@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,199 +0,0 @@
1
- /**
2
- * Simple test for AboutScreen component
3
- */
4
- import React from 'react';
5
- import { AboutScreen } from '../AboutScreen';
6
- import { AppInfo, AboutConfig } from '../../domain/entities/AppInfo';
7
-
8
- describe('AboutScreen', () => {
9
- const mockAppInfo: AppInfo = {
10
- name: 'Test App',
11
- version: '1.0.0',
12
- description: 'Test Description',
13
- developer: 'Test Developer',
14
- contactEmail: 'test@example.com',
15
- websiteUrl: 'https://example.com',
16
- websiteDisplay: 'example.com',
17
- moreAppsUrl: 'https://apps.example.com',
18
- privacyPolicyUrl: 'https://example.com/privacy',
19
- termsOfServiceUrl: 'https://example.com/terms',
20
- };
21
-
22
- const mockConfig: AboutConfig = {
23
- appInfo: mockAppInfo,
24
- actions: {
25
- onEmailPress: jest.fn(),
26
- onWebsitePress: jest.fn(),
27
- onPrivacyPress: jest.fn(),
28
- onTermsPress: jest.fn(),
29
- onMoreAppsPress: jest.fn(),
30
- },
31
- };
32
-
33
- it('should render without crashing', () => {
34
- const element = React.createElement(AboutScreen, { config: mockConfig });
35
- expect(element).toBeTruthy();
36
- });
37
-
38
- it('should render app info after loading', () => {
39
- const element = React.createElement(AboutScreen, { config: mockConfig });
40
- expect(element).toBeTruthy();
41
- expect(mockConfig.appInfo.name).toBe('Test App');
42
- });
43
-
44
- it('should render error state when initialization fails', () => {
45
- const invalidConfig = null as unknown;
46
-
47
- const element = React.createElement(AboutScreen, { config: invalidConfig });
48
- expect(element).toBeTruthy();
49
- });
50
-
51
- it('should render no app info message when app info is null', () => {
52
- const emptyConfig: AboutConfig = {
53
- appInfo: null as unknown,
54
- actions: {},
55
- };
56
-
57
- const element = React.createElement(AboutScreen, { config: emptyConfig });
58
- expect(element).toBeTruthy();
59
- });
60
-
61
- it('should not render header when showHeader is false', () => {
62
- const element = React.createElement(AboutScreen, { config: mockConfig, showHeader: false });
63
- expect(element).toBeTruthy();
64
- });
65
-
66
- it('should render custom header component when provided', () => {
67
- const CustomHeader = () => React.createElement('div', { testID: 'custom-header' }, 'Custom Header');
68
-
69
- const element = React.createElement(AboutScreen, {
70
- config: mockConfig,
71
- headerComponent: React.createElement(CustomHeader)
72
- });
73
- expect(element).toBeTruthy();
74
- });
75
-
76
- it('should render custom footer component when provided', () => {
77
- const CustomFooter = () => React.createElement('div', { testID: 'custom-footer' }, 'Custom Footer');
78
-
79
- const element = React.createElement(AboutScreen, {
80
- config: mockConfig,
81
- footerComponent: React.createElement(CustomFooter)
82
- });
83
- expect(element).toBeTruthy();
84
- });
85
-
86
- it('should apply custom container style', () => {
87
- const customStyle = { backgroundColor: 'red' };
88
-
89
- const element = React.createElement(AboutScreen, {
90
- config: mockConfig,
91
- containerStyle: customStyle,
92
- testID: 'screen'
93
- });
94
- expect(element).toBeTruthy();
95
- });
96
-
97
- it('should apply custom header style', () => {
98
- const customStyle = { backgroundColor: 'blue' };
99
-
100
- const element = React.createElement(AboutScreen, {
101
- config: mockConfig,
102
- headerStyle: customStyle
103
- });
104
- expect(element).toBeTruthy();
105
- });
106
-
107
- it('should apply custom title style', () => {
108
- const customStyle = { color: 'green' } as React.CSSProperties;
109
-
110
- const element = React.createElement(AboutScreen, {
111
- config: mockConfig,
112
- titleStyle: customStyle
113
- });
114
- expect(element).toBeTruthy();
115
- });
116
-
117
- it('should apply custom version style', () => {
118
- const customStyle = { color: 'purple' };
119
-
120
- const element = React.createElement(AboutScreen, {
121
- config: mockConfig,
122
- versionStyle: customStyle
123
- });
124
- expect(element).toBeTruthy();
125
- });
126
-
127
- it('should handle empty config', () => {
128
- const emptyConfig: AboutConfig = {
129
- appInfo: {
130
- name: '',
131
- version: '',
132
- description: '',
133
- developer: '',
134
- contactEmail: '',
135
- websiteUrl: '',
136
- websiteDisplay: '',
137
- moreAppsUrl: '',
138
- privacyPolicyUrl: '',
139
- termsOfServiceUrl: '',
140
- },
141
- actions: {},
142
- };
143
-
144
- const element = React.createElement(AboutScreen, { config: emptyConfig });
145
- expect(element).toBeTruthy();
146
- });
147
-
148
- it('should handle config with only required fields', () => {
149
- const minimalConfig: AboutConfig = {
150
- appInfo: {
151
- name: 'Minimal App',
152
- version: '1.0.0',
153
- description: '',
154
- developer: '',
155
- contactEmail: '',
156
- websiteUrl: '',
157
- websiteDisplay: '',
158
- moreAppsUrl: '',
159
- privacyPolicyUrl: '',
160
- termsOfServiceUrl: '',
161
- },
162
- actions: {},
163
- };
164
-
165
- const element = React.createElement(AboutScreen, { config: minimalConfig });
166
- expect(element).toBeTruthy();
167
- expect(minimalConfig.appInfo.name).toBe('Minimal App');
168
- });
169
-
170
- it('should handle special characters in text', () => {
171
- const configWithSpecialChars: AboutConfig = {
172
- appInfo: {
173
- ...mockAppInfo,
174
- name: 'App & Special <Chars>',
175
- description: 'Description with "quotes" and \'apostrophes\'',
176
- },
177
- actions: {},
178
- };
179
-
180
- const element = React.createElement(AboutScreen, { config: configWithSpecialChars });
181
- expect(element).toBeTruthy();
182
- expect(configWithSpecialChars.appInfo.name).toBe('App & Special <Chars>');
183
- });
184
-
185
- it('should handle very long text', () => {
186
- const configWithLongText: AboutConfig = {
187
- appInfo: {
188
- ...mockAppInfo,
189
- name: 'A'.repeat(100),
190
- description: 'B'.repeat(500),
191
- },
192
- actions: {},
193
- };
194
-
195
- const element = React.createElement(AboutScreen, { config: configWithLongText });
196
- expect(element).toBeTruthy();
197
- expect(configWithLongText.appInfo.name.length).toBe(100);
198
- });
199
- });
@@ -1,366 +0,0 @@
1
- /**
2
- * Tests for AboutScreen component
3
- */
4
- import React from 'react';
5
- import { View, Text, TextStyle } from 'react-native';
6
- import { render, waitFor, fireEvent } from '@testing-library/react';
7
- import { AboutScreen } from '../AboutScreen';
8
- import { AboutConfig } from '../../../domain/entities/AppInfo';
9
-
10
- // Mock console methods
11
- const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation();
12
- const mockConsoleError = jest.spyOn(console, 'error').mockImplementation();
13
-
14
- describe('AboutScreen', () => {
15
- const mockConfig: AboutConfig = {
16
- appInfo: {
17
- name: 'Test App',
18
- version: '1.0.0',
19
- description: 'Test Description',
20
- developer: 'Test Developer',
21
- contactEmail: 'test@example.com',
22
- websiteUrl: 'https://example.com',
23
- websiteDisplay: 'example.com',
24
- moreAppsUrl: 'https://apps.example.com',
25
- },
26
- actions: {
27
- onEmailPress: jest.fn(),
28
- onWebsitePress: jest.fn(),
29
- onMoreAppsPress: jest.fn(),
30
- },
31
- };
32
-
33
- beforeEach(() => {
34
- jest.clearAllMocks();
35
- });
36
-
37
- afterEach(() => {
38
- mockConsoleLog.mockClear();
39
- mockConsoleError.mockClear();
40
- });
41
-
42
- describe('Rendering', () => {
43
- it('should render loading state initially', () => {
44
- const { getByText } = render(
45
- <AboutScreen config={mockConfig} />
46
- );
47
-
48
- expect(getByText('Loading...')).toBeTruthy();
49
- });
50
-
51
- it('should render app info after loading', async () => {
52
- const { getByText, queryByText } = render(
53
- <AboutScreen config={mockConfig} />
54
- );
55
-
56
- // Wait for loading to complete
57
- await waitFor(() => {
58
- expect(queryByText('Loading...')).toBeFalsy();
59
- });
60
-
61
- // Check for app info
62
- expect(getByText('Test App')).toBeTruthy();
63
- expect(getByText('Version 1.0.0')).toBeTruthy();
64
- expect(getByText('Test Description')).toBeTruthy();
65
- expect(getByText('Test Developer')).toBeTruthy();
66
- expect(getByText('test@example.com')).toBeTruthy();
67
- expect(getByText('example.com')).toBeTruthy();
68
- });
69
-
70
- it('should render error state when initialization fails', async () => {
71
- const invalidConfig = null as unknown;
72
-
73
- const { getByText, queryByText } = render(
74
- <AboutScreen config={invalidConfig} />
75
- );
76
-
77
- await waitFor(() => {
78
- expect(queryByText('Loading...')).toBeFalsy();
79
- });
80
-
81
- expect(getByText('No app information available')).toBeTruthy();
82
- });
83
-
84
- it('should render no app info message when app info is null', async () => {
85
- const emptyConfig: AboutConfig = {
86
- appInfo: {},
87
- };
88
-
89
- const { getByText, queryByText } = render(
90
- <AboutScreen config={emptyConfig} />
91
- );
92
-
93
- await waitFor(() => {
94
- expect(queryByText('Loading...')).toBeFalsy();
95
- });
96
-
97
- // With empty appInfo, it should show empty name and default version
98
- expect(getByText('Version 1.0.0')).toBeTruthy();
99
- });
100
-
101
- it('should not render header when showHeader is false', async () => {
102
- const { queryByText } = render(
103
- <AboutScreen config={mockConfig} showHeader={false} />
104
- );
105
-
106
- await waitFor(() => {
107
- expect(queryByText('Loading...')).toBeFalsy();
108
- });
109
-
110
- expect(queryByText('Test App')).toBeFalsy();
111
- expect(queryByText('Version 1.0.0')).toBeFalsy();
112
- expect(queryByText('Test Description')).toBeFalsy();
113
- });
114
-
115
- it('should render custom header component when provided', async () => {
116
- const CustomHeader = () => <View testID="custom-header"><Text>Custom Header</Text></View>;
117
-
118
- const { getByTestId, queryByText } = render(
119
- <AboutScreen config={mockConfig} headerComponent={<CustomHeader />} />
120
- );
121
-
122
- await waitFor(() => {
123
- expect(queryByText('Loading...')).toBeFalsy();
124
- });
125
-
126
- expect(getByTestId('custom-header')).toBeTruthy();
127
- expect(queryByText('Test App')).toBeFalsy(); // Default header should not render
128
- });
129
-
130
- it('should render custom footer component when provided', async () => {
131
- const CustomFooter = () => <View testID="custom-footer"><Text>Custom Footer</Text></View>;
132
-
133
- const { getByTestId } = render(
134
- <AboutScreen config={mockConfig} footerComponent={<CustomFooter />} />
135
- );
136
-
137
- await waitFor(() => {
138
- expect(getByTestId('custom-footer')).toBeTruthy();
139
- });
140
- });
141
- });
142
-
143
- describe('Custom Styles', () => {
144
- it('should apply custom container style', async () => {
145
- const customStyle = { backgroundColor: 'red' };
146
-
147
- const { queryByText, container } = render(
148
- <AboutScreen config={mockConfig} containerStyle={customStyle} testID="screen" />
149
- );
150
-
151
- await waitFor(() => {
152
- expect(queryByText('Loading...')).toBeFalsy();
153
- });
154
-
155
- // Test that custom container style is applied (component renders without error)
156
- expect(container).toBeTruthy();
157
- });
158
-
159
- it('should apply custom header style', async () => {
160
- const customStyle = { backgroundColor: 'blue' };
161
-
162
- const { getByText, queryByText } = render(
163
- <AboutScreen config={mockConfig} headerStyle={customStyle} />
164
- );
165
-
166
- await waitFor(() => {
167
- expect(queryByText('Loading...')).toBeFalsy();
168
- });
169
-
170
- const header = getByText('Test App');
171
- // Check that header renders with custom style (component renders without error)
172
- expect(header).toBeTruthy();
173
- });
174
-
175
- it('should apply custom title style', async () => {
176
- const customStyle: TextStyle = { color: 'green' };
177
-
178
- const { getByText, queryByText } = render(
179
- <AboutScreen config={mockConfig} titleStyle={customStyle} />
180
- );
181
-
182
- await waitFor(() => {
183
- expect(queryByText('Loading...')).toBeFalsy();
184
- });
185
-
186
- const title = getByText('Test App');
187
- // Check that title renders with custom style (component renders without error)
188
- expect(title).toBeTruthy();
189
- });
190
-
191
- it('should apply custom version style', async () => {
192
- const customStyle = { color: 'purple' };
193
-
194
- const { getByText, queryByText } = render(
195
- <AboutScreen config={mockConfig} versionStyle={customStyle} />
196
- );
197
-
198
- await waitFor(() => {
199
- expect(queryByText('Loading...')).toBeFalsy();
200
- });
201
-
202
- const version = getByText('Version 1.0.0');
203
- // Check that version renders with custom style (component renders without error)
204
- expect(version).toBeTruthy();
205
- });
206
- });
207
-
208
- describe('Interactions', () => {
209
- it('should call action handlers when items are pressed', async () => {
210
- const { getByTestId } = render(
211
- <AboutScreen config={mockConfig} />
212
- );
213
-
214
- await waitFor(() => {
215
- expect(getByTestId('email-item')).toBeTruthy();
216
- expect(getByTestId('website-item')).toBeTruthy();
217
- expect(getByTestId('more-apps-item')).toBeTruthy();
218
- });
219
-
220
- // Test interactions
221
- fireEvent.click(getByTestId('email-item'));
222
- fireEvent.click(getByTestId('website-item'));
223
- fireEvent.click(getByTestId('more-apps-item'));
224
-
225
- expect(mockConfig.actions!.onEmailPress).toHaveBeenCalledTimes(1);
226
- expect(mockConfig.actions!.onWebsitePress).toHaveBeenCalledTimes(1);
227
- expect(mockConfig.actions!.onMoreAppsPress).toHaveBeenCalledTimes(1);
228
- });
229
- });
230
-
231
- describe('Performance', () => {
232
- it('should memoize render functions', async () => {
233
- const { rerender } = render(
234
- <AboutScreen config={mockConfig} />
235
- );
236
-
237
- // Wait for initial render
238
- await waitFor(() => {
239
- expect(() => { }).not.toThrow();
240
- });
241
-
242
- // Re-render with same props
243
- rerender(
244
- <AboutScreen config={mockConfig} />
245
- );
246
-
247
- // Should not throw and should render correctly
248
- await waitFor(() => {
249
- expect(() => {
250
- rerender(
251
- <AboutScreen config={mockConfig} />
252
- );
253
- }).not.toThrow();
254
- });
255
- });
256
-
257
- it('should handle rapid prop changes', async () => {
258
- const { rerender } = render(
259
- <AboutScreen config={mockConfig} />
260
- );
261
-
262
- // Rapid prop changes
263
- for (let i = 0; i < 5; i++) {
264
- const newConfig = {
265
- ...mockConfig,
266
- appInfo: { ...mockConfig.appInfo, name: `App ${i}` }
267
- };
268
- rerender(<AboutScreen config={newConfig} />);
269
-
270
- await waitFor(() => {
271
- expect(() => { }).not.toThrow();
272
- });
273
- }
274
-
275
- expect(() => {
276
- rerender(
277
- <AboutScreen config={{ ...mockConfig, appInfo: { ...mockConfig.appInfo, name: 'Final App' } }} />
278
- );
279
- }).not.toThrow();
280
- });
281
- });
282
-
283
- describe('Edge Cases', () => {
284
- it('should handle empty config', async () => {
285
- const emptyConfig: AboutConfig = {
286
- appInfo: {},
287
- };
288
-
289
- const { getByText, queryByText } = render(
290
- <AboutScreen config={emptyConfig} />
291
- );
292
-
293
- await waitFor(() => {
294
- expect(queryByText('Loading...')).toBeFalsy();
295
- });
296
-
297
- // With empty appInfo, it should show empty name and default version
298
- expect(getByText('Version 1.0.0')).toBeTruthy();
299
- });
300
-
301
- it('should handle config with only required fields', async () => {
302
- const minimalConfig: AboutConfig = {
303
- appInfo: {
304
- name: 'Minimal App',
305
- version: '1.0.0',
306
- },
307
- };
308
-
309
- const { getByText, queryByText } = render(
310
- <AboutScreen config={minimalConfig} />
311
- );
312
-
313
- await waitFor(() => {
314
- expect(queryByText('Loading...')).toBeFalsy();
315
- });
316
-
317
- expect(getByText('Minimal App')).toBeTruthy();
318
- expect(getByText('Version 1.0.0')).toBeTruthy();
319
- expect(queryByText('Test Developer')).toBeFalsy();
320
- expect(queryByText('test@example.com')).toBeFalsy();
321
- });
322
-
323
- it('should handle special characters in text', async () => {
324
- const configWithSpecialChars: AboutConfig = {
325
- appInfo: {
326
- name: 'Test & App <script>',
327
- version: '1.0.0',
328
- description: 'Description with émojis 🎉 and ñ',
329
- developer: 'Developer & Co.',
330
- },
331
- };
332
-
333
- const { getByText } = render(
334
- <AboutScreen config={configWithSpecialChars} />
335
- );
336
-
337
- await waitFor(() => {
338
- expect(getByText('Test & App <script>')).toBeTruthy();
339
- expect(getByText('Description with émojis 🎉 and ñ')).toBeTruthy();
340
- expect(getByText('Developer & Co.')).toBeTruthy();
341
- });
342
- });
343
-
344
- it('should handle very long text', async () => {
345
- const longName = 'A'.repeat(100);
346
- const longDescription = 'B'.repeat(200);
347
-
348
- const configWithLongText: AboutConfig = {
349
- appInfo: {
350
- name: longName,
351
- version: '1.0.0',
352
- description: longDescription,
353
- },
354
- };
355
-
356
- const { getByText } = render(
357
- <AboutScreen config={configWithLongText} />
358
- );
359
-
360
- await waitFor(() => {
361
- expect(getByText(longName)).toBeTruthy();
362
- expect(getByText(longDescription)).toBeTruthy();
363
- });
364
- });
365
- });
366
- });