@umituz/react-native-settings 4.20.61 → 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 (78) hide show
  1. package/package.json +8 -60
  2. package/src/domains/gamification/README.md +343 -0
  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 +91 -0
  13. package/src/domains/gamification/components/GamificationSettingsItem.tsx +33 -0
  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 +70 -0
  20. package/src/domains/gamification/examples/localization.example.json +71 -0
  21. package/src/domains/gamification/hooks/useGamification.ts +91 -0
  22. package/src/domains/gamification/index.ts +65 -0
  23. package/src/domains/gamification/store/gamificationStore.ts +162 -0
  24. package/src/domains/gamification/types/index.ts +103 -0
  25. package/src/domains/gamification/types/settings.ts +28 -0
  26. package/src/domains/gamification/utils/calculations.ts +85 -0
  27. package/src/index.ts +18 -8
  28. package/src/presentation/navigation/SettingsStackNavigator.tsx +12 -0
  29. package/src/presentation/navigation/types.ts +2 -0
  30. package/src/presentation/navigation/utils/navigationScreenOptions.ts +7 -0
  31. package/src/presentation/screens/types/UserFeatureConfig.ts +2 -0
  32. package/src/presentation/utils/configCreators.ts +147 -0
  33. package/src/presentation/utils/index.ts +5 -0
  34. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -51
  35. package/.github/ISSUE_TEMPLATE/documentation.md +0 -52
  36. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -63
  37. package/.github/PULL_REQUEST_TEMPLATE.md +0 -84
  38. package/AI_AGENT_GUIDELINES.md +0 -367
  39. package/ARCHITECTURE.md +0 -246
  40. package/CHANGELOG.md +0 -67
  41. package/CODE_OF_CONDUCT.md +0 -75
  42. package/CONTRIBUTING.md +0 -107
  43. package/DOCUMENTATION_MIGRATION.md +0 -319
  44. package/DOCUMENTATION_TEMPLATE.md +0 -155
  45. package/SECURITY.md +0 -98
  46. package/SETTINGS_SCREEN_GUIDE.md +0 -185
  47. package/TESTING.md +0 -358
  48. package/src/__tests__/integration.test.tsx +0 -371
  49. package/src/__tests__/performance.test.tsx +0 -369
  50. package/src/__tests__/setup.test.tsx +0 -20
  51. package/src/__tests__/setup.ts +0 -154
  52. package/src/domains/about/__tests__/integration.test.tsx +0 -328
  53. package/src/domains/about/__tests__/types.d.ts +0 -5
  54. package/src/domains/about/domain/entities/__tests__/AppInfo.test.ts +0 -93
  55. package/src/domains/about/infrastructure/repositories/__tests__/AboutRepository.test.ts +0 -153
  56. package/src/domains/about/presentation/components/__tests__/AboutContent.simple.test.tsx +0 -178
  57. package/src/domains/about/presentation/components/__tests__/AboutContent.test.tsx +0 -293
  58. package/src/domains/about/presentation/components/__tests__/AboutHeader.test.tsx +0 -201
  59. package/src/domains/about/presentation/components/__tests__/AboutSettingItem.test.tsx +0 -71
  60. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.simple.test.tsx +0 -229
  61. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.test.tsx +0 -240
  62. package/src/domains/about/presentation/screens/__tests__/AboutScreen.simple.test.tsx +0 -199
  63. package/src/domains/about/presentation/screens/__tests__/AboutScreen.test.tsx +0 -366
  64. package/src/domains/about/utils/__tests__/index.test.ts +0 -408
  65. package/src/domains/appearance/__tests__/components/AppearanceScreen.test.tsx +0 -195
  66. package/src/domains/appearance/__tests__/hooks/index.test.tsx +0 -232
  67. package/src/domains/appearance/__tests__/integration/index.test.tsx +0 -207
  68. package/src/domains/appearance/__tests__/services/appearanceService.test.ts +0 -299
  69. package/src/domains/appearance/__tests__/setup.ts +0 -88
  70. package/src/domains/appearance/__tests__/stores/appearanceStore.test.tsx +0 -175
  71. package/src/domains/cloud-sync/presentation/components/__tests__/CloudSyncSetting.test.tsx +0 -78
  72. package/src/domains/legal/__tests__/ContentValidationService.test.ts +0 -195
  73. package/src/domains/legal/__tests__/StyleCacheService.test.ts +0 -110
  74. package/src/domains/legal/__tests__/UrlHandlerService.test.ts +0 -71
  75. package/src/domains/legal/__tests__/setup.ts +0 -82
  76. package/src/presentation/components/__tests__/SettingsErrorBoundary.test.tsx +0 -186
  77. package/src/presentation/screens/__tests__/SettingsScreen.test.tsx +0 -322
  78. package/src/presentation/screens/hooks/__tests__/useFeatureDetection.test.tsx +0 -261
package/package.json CHANGED
@@ -1,16 +1,14 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "4.20.61",
4
- "description": "Complete settings hub for React Native apps - consolidated package with settings, about, legal, appearance, feedback, FAQs, and rating",
3
+ "version": "4.21.1",
4
+ "description": "Complete settings hub for React Native apps - consolidated package with settings, about, legal, appearance, feedback, FAQs, rating, and gamification",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "scripts": {
8
8
  "typecheck": "tsc --noEmit",
9
9
  "lint": "eslint src",
10
10
  "lint:fix": "eslint src --fix",
11
- "version:patch": "npm version patch -m 'chore: release v%s'",
12
- "version:minor": "npm version minor -m 'chore: release v%s'",
13
- "version:major": "npm version major -m 'chore: release v%s'"
11
+ "vp": "npm version patch && npm publish && git push"
14
12
  },
15
13
  "keywords": [
16
14
  "react-native",
@@ -26,6 +24,8 @@
26
24
  "feedback",
27
25
  "faqs",
28
26
  "rating",
27
+ "gamification",
28
+ "achievements",
29
29
  "consolidated"
30
30
  ],
31
31
  "author": "Ümit UZ <umit@umituz.com>",
@@ -35,12 +35,10 @@
35
35
  "url": "https://github.com/umituz/react-native-settings"
36
36
  },
37
37
  "dependencies": {
38
- "@react-native-async-storage/async-storage": "^2.2.0",
39
38
  "@umituz/react-native-auth": "latest",
40
39
  "@umituz/react-native-design-system": "latest",
41
40
  "@umituz/react-native-localization": "latest",
42
41
  "@umituz/react-native-notifications": "latest",
43
- "@umituz/react-native-onboarding": "latest",
44
42
  "@umituz/react-native-storage": "latest",
45
43
  "@umituz/react-native-tanstack": "latest",
46
44
  "firebase": "^12.7.0"
@@ -52,79 +50,29 @@
52
50
  "@tanstack/react-query": ">=5.0.0",
53
51
  "react": ">=19.0.0",
54
52
  "react-native": ">=0.81.0",
55
- "react-native-safe-area-context": ">=4.0.0",
56
- "zustand": ">=5.0.0"
53
+ "react-native-safe-area-context": ">=4.0.0"
57
54
  },
58
55
  "devDependencies": {
59
- "@babel/plugin-transform-runtime": "^7.28.5",
60
56
  "@expo/vector-icons": "^15.0.0",
61
- "@gorhom/bottom-sheet": "^5.2.8",
62
- "@react-native-community/datetimepicker": "^8.5.1",
63
- "@react-navigation/bottom-tabs": "^7.9.0",
64
57
  "@react-navigation/native": "^7.1.26",
65
58
  "@react-navigation/stack": "^7.6.13",
66
- "@sentry/react-native": "^7.8.0",
67
- "@sentry/types": "^10.32.1",
68
59
  "@tanstack/react-query": "^5.0.0",
69
- "@types/jest": "^29.5.14",
70
60
  "@types/react": "~19.1.10",
71
61
  "@typescript-eslint/eslint-plugin": "^7.18.0",
72
62
  "@typescript-eslint/parser": "^7.18.0",
73
- "@umituz/react-native-auth": "latest",
74
- "@umituz/react-native-design-system": "latest",
75
- "@umituz/react-native-filesystem": "latest",
76
- "@umituz/react-native-firebase": "latest",
77
- "@umituz/react-native-haptics": "latest",
78
- "@umituz/react-native-localization": "latest",
79
- "@umituz/react-native-notifications": "latest",
80
- "@umituz/react-native-onboarding": "latest",
81
- "@umituz/react-native-sentry": "^1.4.3",
82
- "@umituz/react-native-storage": "latest",
83
- "@umituz/react-native-tanstack": "latest",
84
- "@umituz/react-native-uuid": "latest",
85
63
  "eslint": "^8.57.0",
86
64
  "eslint-plugin-react": "^7.37.5",
87
65
  "eslint-plugin-react-native": "^5.0.0",
88
- "expo-apple-authentication": "^8.0.8",
89
- "expo-application": "^7.0.8",
90
- "expo-clipboard": "^8.0.8",
91
- "expo-crypto": "^15.0.8",
92
- "expo-device": "^8.0.10",
93
- "expo-file-system": "^19.0.21",
94
- "expo-haptics": "^15.0.8",
95
- "expo-image": "^3.0.11",
96
- "expo-localization": "^17.0.8",
97
- "expo-notifications": "^0.32.15",
98
- "expo-sharing": "^14.0.8",
99
- "expo-video": "^3.0.15",
100
- "i18next": "^25.7.3",
101
66
  "react": "19.1.0",
102
- "react-i18next": "^16.5.0",
103
67
  "react-native": "0.81.5",
104
- "react-native-gesture-handler": "^2.30.0",
105
- "react-native-reanimated": "^4.2.1",
106
68
  "react-native-safe-area-context": "^5.6.2",
107
- "rn-emoji-keyboard": "^1.7.0",
108
- "typescript": "^5.3.0",
109
- "zustand": "^5.0.9"
69
+ "typescript": "^5.3.0"
110
70
  },
111
71
  "publishConfig": {
112
72
  "access": "public"
113
73
  },
114
74
  "files": [
115
75
  "src",
116
- "README.md",
117
- "LICENSE",
118
- "CONTRIBUTING.md",
119
- "CHANGELOG.md",
120
- "CODE_OF_CONDUCT.md",
121
- "SECURITY.md",
122
- "ARCHITECTURE.md",
123
- "TESTING.md",
124
- "AI_AGENT_GUIDELINES.md",
125
- "SETTINGS_SCREEN_GUIDE.md",
126
- "DOCUMENTATION_TEMPLATE.md",
127
- "DOCUMENTATION_MIGRATION.md",
128
- ".github"
76
+ "README.md"
129
77
  ]
130
78
  }
@@ -0,0 +1,343 @@
1
+ # Gamification Domain
2
+
3
+ Complete gamification integration for React Native Settings package.
4
+
5
+ ## Overview
6
+
7
+ The gamification domain provides a seamless integration of achievements, levels, streaks, and points into your settings screen. It wraps `@umituz/react-native-gamification` with settings-specific functionality.
8
+
9
+ ## Features
10
+
11
+ - ✅ **Achievements System** - Track and display user achievements
12
+ - ✅ **Level Progression** - Visual level progress with points
13
+ - ✅ **Streak Tracking** - Daily streak monitoring
14
+ - ✅ **Statistics Display** - Comprehensive stats cards
15
+ - ✅ **Localized** - Full i18n support via `@umituz/react-native-localization`
16
+ - ✅ **Theme Support** - Automatic dark/light mode integration
17
+ - ✅ **Navigation Ready** - Pre-configured navigation integration
18
+
19
+ ## Architecture
20
+
21
+ ```
22
+ src/domains/gamification/
23
+ ├── types/
24
+ │ └── index.ts # Type definitions
25
+ ├── components/
26
+ │ ├── GamificationScreenWrapper.tsx # Main screen wrapper
27
+ │ └── GamificationSettingsItem.tsx # Menu item component
28
+ └── index.ts # Public API
29
+ ```
30
+
31
+ ## Installation
32
+
33
+ The gamification domain is included in `@umituz/react-native-settings`. Ensure you have the peer dependency:
34
+
35
+ ```bash
36
+ npm install @umituz/react-native-gamification
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### 1. Configure Gamification in Settings
42
+
43
+ ```typescript
44
+ // src/domains/settings/config/gamification.config.ts
45
+ import type { GamificationSettingsConfig } from "@umituz/react-native-settings";
46
+
47
+ export const createGamificationConfig = ({ t }): GamificationSettingsConfig => ({
48
+ enabled: true,
49
+ config: {
50
+ storageKey: "app_gamification",
51
+ achievements: [
52
+ { id: "first_task", threshold: 1, type: "count" },
53
+ { id: "ten_tasks", threshold: 10, type: "count" },
54
+ { id: "week_streak", threshold: 7, type: "streak" },
55
+ ],
56
+ levels: [
57
+ { level: 1, minPoints: 0, maxPoints: 50 },
58
+ { level: 2, minPoints: 50, maxPoints: 150 },
59
+ { level: 3, minPoints: 150, maxPoints: 300 },
60
+ ],
61
+ pointsPerAction: 10,
62
+ streakBonusMultiplier: 1.5,
63
+ },
64
+ screenProps: {
65
+ title: t("gamification.title"),
66
+ statsTitle: t("gamification.stats.title"),
67
+ achievementsTitle: t("gamification.achievements.title"),
68
+ streakTitle: t("gamification.streak.title"),
69
+ },
70
+ });
71
+ ```
72
+
73
+ ### 2. Add to Settings Config
74
+
75
+ ```typescript
76
+ // src/domains/settings/config/settings.config.ts
77
+ import { createGamificationConfig } from "./gamification.config";
78
+
79
+ export const createSettingsConfig = ({ t, user, isPremium }) => ({
80
+ // ... other configs
81
+ gamification: createGamificationConfig({ t }),
82
+ });
83
+ ```
84
+
85
+ ### 3. Pass to SettingsStackNavigator
86
+
87
+ ```typescript
88
+ // src/domains/settings/presentation/SettingsTab.tsx
89
+ import { SettingsStackNavigator } from "@umituz/react-native-settings";
90
+
91
+ export const SettingsTab = () => {
92
+ const { t } = useLocalization();
93
+ const config = useMemo(() => createSettingsConfig({ t }), [t]);
94
+
95
+ return (
96
+ <SettingsStackNavigator
97
+ appInfo={APP_INFO}
98
+ legalUrls={LEGAL_URLS}
99
+ gamificationConfig={config.gamification}
100
+ />
101
+ );
102
+ };
103
+ ```
104
+
105
+ ### 4. Add Menu Item (Optional)
106
+
107
+ ```typescript
108
+ // In your custom settings sections
109
+ import { GamificationSettingsItem } from "@umituz/react-native-settings";
110
+
111
+ const customSections = [
112
+ {
113
+ title: t("settings.sections.engagement"),
114
+ items: [
115
+ <GamificationSettingsItem
116
+ config={{
117
+ enabled: true,
118
+ title: t("settings.gamification.menuTitle"),
119
+ subtitle: t("settings.gamification.menuSubtitle"),
120
+ icon: "trophy",
121
+ onPress: () => navigation.navigate("Gamification"),
122
+ }}
123
+ />,
124
+ ],
125
+ },
126
+ ];
127
+ ```
128
+
129
+ ## Localization
130
+
131
+ Add these keys to your localization files:
132
+
133
+ ```json
134
+ {
135
+ "settings": {
136
+ "gamification": {
137
+ "title": "Achievements",
138
+ "menuTitle": "Achievements & Progress",
139
+ "menuSubtitle": "View your achievements and stats"
140
+ }
141
+ },
142
+ "gamification": {
143
+ "title": "Your Progress",
144
+ "level": {
145
+ "title": "Level {{level}}"
146
+ },
147
+ "stats": {
148
+ "title": "Statistics",
149
+ "totalPoints": "Total Points",
150
+ "tasksCompleted": "Tasks Completed",
151
+ "achievementsUnlocked": "Achievements"
152
+ },
153
+ "achievements": {
154
+ "title": "Achievements",
155
+ "empty": "No achievements yet. Keep going!",
156
+ "first_task": {
157
+ "title": "First Steps",
158
+ "description": "Complete your first task"
159
+ },
160
+ "ten_tasks": {
161
+ "title": "Getting Started",
162
+ "description": "Complete 10 tasks"
163
+ },
164
+ "week_streak": {
165
+ "title": "Week Warrior",
166
+ "description": "Maintain a 7-day streak"
167
+ }
168
+ },
169
+ "streak": {
170
+ "title": "Streak",
171
+ "current": "Current Streak",
172
+ "best": "Best Streak"
173
+ }
174
+ }
175
+ }
176
+ ```
177
+
178
+ ## API Reference
179
+
180
+ ### Types
181
+
182
+ #### `GamificationSettingsConfig`
183
+
184
+ ```typescript
185
+ interface GamificationSettingsConfig {
186
+ enabled: boolean;
187
+ config: GamificationConfig;
188
+ screenProps: Omit<GamificationScreenProps, "levelProps" | "stats" | "achievements">;
189
+ onNavigate?: () => void;
190
+ }
191
+ ```
192
+
193
+ #### `GamificationMenuConfig`
194
+
195
+ ```typescript
196
+ interface GamificationMenuConfig {
197
+ enabled: boolean;
198
+ title: string;
199
+ subtitle?: string;
200
+ icon?: string;
201
+ onPress?: () => void;
202
+ }
203
+ ```
204
+
205
+ ### Components
206
+
207
+ #### `GamificationScreenWrapper`
208
+
209
+ Main screen component that displays gamification data.
210
+
211
+ **Props:**
212
+ - `config: GamificationSettingsConfig` - Configuration object
213
+
214
+ #### `GamificationSettingsItem`
215
+
216
+ Menu item component for settings list.
217
+
218
+ **Props:**
219
+ - `config: GamificationMenuConfig` - Menu configuration
220
+
221
+ ## Re-exported Components
222
+
223
+ All components from `@umituz/react-native-gamification` are re-exported for convenience:
224
+
225
+ ```typescript
226
+ import {
227
+ LevelProgress,
228
+ PointsBadge,
229
+ AchievementCard,
230
+ AchievementToast,
231
+ StreakDisplay,
232
+ StatsCard,
233
+ AchievementItem,
234
+ useGamification,
235
+ useGamificationStore,
236
+ } from "@umituz/react-native-settings";
237
+ ```
238
+
239
+ ## Example: Complete Integration
240
+
241
+ ```typescript
242
+ // 1. Create config
243
+ const gamificationConfig: GamificationSettingsConfig = {
244
+ enabled: true,
245
+ config: {
246
+ storageKey: "my_app_gamification",
247
+ achievements: [
248
+ { id: "first_login", threshold: 1, type: "milestone" },
249
+ { id: "power_user", threshold: 100, type: "count" },
250
+ ],
251
+ levels: [
252
+ { level: 1, minPoints: 0, maxPoints: 100 },
253
+ { level: 2, minPoints: 100, maxPoints: 250 },
254
+ ],
255
+ pointsPerAction: 5,
256
+ },
257
+ screenProps: {
258
+ title: "Your Achievements",
259
+ statsTitle: "Your Stats",
260
+ achievementsTitle: "Unlocked Achievements",
261
+ streakTitle: "Daily Streak",
262
+ },
263
+ };
264
+
265
+ // 2. Use in navigator
266
+ <SettingsStackNavigator
267
+ appInfo={APP_INFO}
268
+ legalUrls={LEGAL_URLS}
269
+ gamificationConfig={gamificationConfig}
270
+ />
271
+
272
+ // 3. Track actions in your app
273
+ import { useGamification } from "@umituz/react-native-settings";
274
+
275
+ const MyComponent = () => {
276
+ const { completeTask, addPoints } = useGamification();
277
+
278
+ const handleTaskComplete = () => {
279
+ completeTask(); // Adds points, updates streak, checks achievements
280
+ };
281
+
282
+ return <Button onPress={handleTaskComplete} title="Complete Task" />;
283
+ };
284
+ ```
285
+
286
+ ## Best Practices
287
+
288
+ 1. **Config Files ≤ 80 lines** - Keep gamification config in separate file
289
+ 2. **Use i18n** - Never hardcode strings, always use translation keys
290
+ 3. **Initialize Early** - Initialize gamification in app startup
291
+ 4. **Track Meaningfully** - Only track actions that matter to users
292
+ 5. **Test Achievements** - Ensure thresholds are achievable and rewarding
293
+
294
+ ## Testing
295
+
296
+ ```typescript
297
+ import { useGamification } from "@umituz/react-native-settings";
298
+
299
+ describe("Gamification", () => {
300
+ it("should track task completion", () => {
301
+ const { completeTask, totalTasksCompleted } = useGamification();
302
+ completeTask();
303
+ expect(totalTasksCompleted).toBe(1);
304
+ });
305
+ });
306
+ ```
307
+
308
+ ## Troubleshooting
309
+
310
+ ### Gamification screen not showing
311
+ - Ensure `gamificationConfig.enabled` is `true`
312
+ - Check that config is passed to `SettingsStackNavigator`
313
+
314
+ ### Achievements not unlocking
315
+ - Verify achievement IDs match between config and localization
316
+ - Check threshold values are correct
317
+ - Ensure `completeTask()` or `addPoints()` is being called
318
+
319
+ ### Localization missing
320
+ - Add all required translation keys
321
+ - Check language files are properly loaded
322
+
323
+ ## Migration Guide
324
+
325
+ If migrating from standalone gamification package:
326
+
327
+ ```typescript
328
+ // Before
329
+ import { GamificationScreen } from "@umituz/react-native-gamification";
330
+
331
+ // After
332
+ import { GamificationScreenWrapper } from "@umituz/react-native-settings";
333
+ ```
334
+
335
+ ## Related Documentation
336
+
337
+ - [@umituz/react-native-gamification](../../../react-native-gamification/README.md)
338
+ - [Settings Architecture](../../ARCHITECTURE.md)
339
+ - [Settings Screen Guide](../../SETTINGS_SCREEN_GUIDE.md)
340
+
341
+ ## License
342
+
343
+ MIT © Ümit UZ
@@ -0,0 +1,142 @@
1
+ /**
2
+ * AchievementCard Component
3
+ * Displays achievement - all text via props
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, Text, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
8
+
9
+ export interface AchievementCardProps {
10
+ title: string;
11
+ description: string;
12
+ icon: React.ReactNode;
13
+ isUnlocked: boolean;
14
+ progress: number;
15
+ // Customization
16
+ containerStyle?: ViewStyle;
17
+ titleStyle?: TextStyle;
18
+ descriptionStyle?: TextStyle;
19
+ progressBarStyle?: ViewStyle;
20
+ // Colors
21
+ unlockedColor?: string;
22
+ lockedColor?: string;
23
+ backgroundColor?: string;
24
+ textColor?: string;
25
+ subtextColor?: string;
26
+ }
27
+
28
+ export const AchievementCard: React.FC<AchievementCardProps> = ({
29
+ title,
30
+ description,
31
+ icon,
32
+ isUnlocked,
33
+ progress,
34
+ containerStyle,
35
+ titleStyle,
36
+ descriptionStyle,
37
+ progressBarStyle,
38
+ unlockedColor = "#4CAF50",
39
+ lockedColor = "#666666",
40
+ backgroundColor = "#1A1A1A",
41
+ textColor = "#FFFFFF",
42
+ subtextColor = "#888888",
43
+ }) => {
44
+ const accentColor = isUnlocked ? unlockedColor : lockedColor;
45
+
46
+ return (
47
+ <View
48
+ style={[
49
+ styles.container,
50
+ { backgroundColor, borderColor: `${accentColor}40` },
51
+ containerStyle,
52
+ ]}
53
+ >
54
+ <View style={[styles.iconContainer, { backgroundColor: `${accentColor}20` }]}>
55
+ {icon}
56
+ </View>
57
+
58
+ <View style={styles.content}>
59
+ <Text
60
+ style={[
61
+ styles.title,
62
+ { color: isUnlocked ? textColor : subtextColor },
63
+ titleStyle,
64
+ ]}
65
+ >
66
+ {title}
67
+ </Text>
68
+ <Text style={[styles.description, { color: subtextColor }, descriptionStyle]}>
69
+ {description}
70
+ </Text>
71
+
72
+ {!isUnlocked && (
73
+ <View style={[styles.progressBar, { backgroundColor: `${lockedColor}40` }, progressBarStyle]}>
74
+ <View
75
+ style={[
76
+ styles.progressFill,
77
+ { width: `${progress}%`, backgroundColor: accentColor },
78
+ ]}
79
+ />
80
+ </View>
81
+ )}
82
+ </View>
83
+
84
+ {isUnlocked && (
85
+ <View style={[styles.checkmark, { backgroundColor: unlockedColor }]}>
86
+ <Text style={styles.checkmarkText}>✓</Text>
87
+ </View>
88
+ )}
89
+ </View>
90
+ );
91
+ };
92
+
93
+ const styles = StyleSheet.create({
94
+ container: {
95
+ flexDirection: "row",
96
+ alignItems: "center",
97
+ padding: 12,
98
+ borderRadius: 12,
99
+ borderWidth: 1,
100
+ gap: 12,
101
+ },
102
+ iconContainer: {
103
+ width: 48,
104
+ height: 48,
105
+ borderRadius: 24,
106
+ justifyContent: "center",
107
+ alignItems: "center",
108
+ },
109
+ content: {
110
+ flex: 1,
111
+ },
112
+ title: {
113
+ fontSize: 16,
114
+ fontWeight: "600",
115
+ },
116
+ description: {
117
+ fontSize: 13,
118
+ marginTop: 2,
119
+ },
120
+ progressBar: {
121
+ height: 4,
122
+ borderRadius: 2,
123
+ marginTop: 8,
124
+ overflow: "hidden",
125
+ },
126
+ progressFill: {
127
+ height: "100%",
128
+ borderRadius: 2,
129
+ },
130
+ checkmark: {
131
+ width: 24,
132
+ height: 24,
133
+ borderRadius: 12,
134
+ justifyContent: "center",
135
+ alignItems: "center",
136
+ },
137
+ checkmarkText: {
138
+ color: "#FFFFFF",
139
+ fontSize: 14,
140
+ fontWeight: "bold",
141
+ },
142
+ });