@umituz/react-native-settings 4.20.61 → 4.20.62
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.
- package/package.json +4 -1
- package/src/domains/gamification/README.md +343 -0
- package/src/domains/gamification/components/GamificationScreenWrapper.tsx +91 -0
- package/src/domains/gamification/components/GamificationSettingsItem.tsx +33 -0
- package/src/domains/gamification/examples/gamification.config.example.ts +70 -0
- package/src/domains/gamification/examples/localization.example.json +71 -0
- package/src/domains/gamification/index.ts +38 -0
- package/src/domains/gamification/types/index.ts +31 -0
- package/src/index.ts +18 -8
- package/src/presentation/navigation/SettingsStackNavigator.tsx +12 -0
- package/src/presentation/navigation/types.ts +2 -0
- package/src/presentation/navigation/utils/navigationScreenOptions.ts +7 -0
- package/src/presentation/screens/types/UserFeatureConfig.ts +2 -0
- package/src/presentation/utils/configCreators.ts +147 -0
- package/src/presentation/utils/index.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-settings",
|
|
3
|
-
"version": "4.20.
|
|
3
|
+
"version": "4.20.62",
|
|
4
4
|
"description": "Complete settings hub for React Native apps - consolidated package with settings, about, legal, appearance, feedback, FAQs, and rating",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"feedback",
|
|
27
27
|
"faqs",
|
|
28
28
|
"rating",
|
|
29
|
+
"gamification",
|
|
30
|
+
"achievements",
|
|
29
31
|
"consolidated"
|
|
30
32
|
],
|
|
31
33
|
"author": "Ümit UZ <umit@umituz.com>",
|
|
@@ -38,6 +40,7 @@
|
|
|
38
40
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
39
41
|
"@umituz/react-native-auth": "latest",
|
|
40
42
|
"@umituz/react-native-design-system": "latest",
|
|
43
|
+
"@umituz/react-native-gamification": "latest",
|
|
41
44
|
"@umituz/react-native-localization": "latest",
|
|
42
45
|
"@umituz/react-native-notifications": "latest",
|
|
43
46
|
"@umituz/react-native-onboarding": "latest",
|
|
@@ -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,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gamification Screen Component
|
|
3
|
+
* Wrapper for @umituz/react-native-gamification screen
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useMemo } from "react";
|
|
7
|
+
import { GamificationScreen as BaseGamificationScreen } from "@umituz/react-native-gamification";
|
|
8
|
+
import { useGamification } from "@umituz/react-native-gamification";
|
|
9
|
+
import { useLocalization } from "@umituz/react-native-localization";
|
|
10
|
+
import type { GamificationSettingsConfig } from "../types";
|
|
11
|
+
|
|
12
|
+
export interface GamificationScreenWrapperProps {
|
|
13
|
+
config: GamificationSettingsConfig;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Gamification Screen for Settings
|
|
18
|
+
* Displays achievements, levels, streaks, and stats
|
|
19
|
+
*/
|
|
20
|
+
export const GamificationScreenWrapper: React.FC<GamificationScreenWrapperProps> = ({
|
|
21
|
+
config,
|
|
22
|
+
}) => {
|
|
23
|
+
const { t } = useLocalization();
|
|
24
|
+
const gamification = useGamification(config.config);
|
|
25
|
+
|
|
26
|
+
const screenProps = useMemo(() => {
|
|
27
|
+
// Map achievements to screen format
|
|
28
|
+
const achievements = gamification.achievements.map((achievement) => ({
|
|
29
|
+
id: achievement.id,
|
|
30
|
+
title: t(`gamification.achievements.${achievement.id}.title`),
|
|
31
|
+
description: t(`gamification.achievements.${achievement.id}.description`),
|
|
32
|
+
icon: "trophy",
|
|
33
|
+
isUnlocked: achievement.isUnlocked,
|
|
34
|
+
progress: achievement.progress,
|
|
35
|
+
threshold: achievement.threshold,
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
// Map stats
|
|
39
|
+
const stats = [
|
|
40
|
+
{
|
|
41
|
+
icon: "star",
|
|
42
|
+
value: gamification.points,
|
|
43
|
+
label: t("gamification.stats.totalPoints"),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
icon: "check-circle",
|
|
47
|
+
value: gamification.totalTasksCompleted,
|
|
48
|
+
label: t("gamification.stats.tasksCompleted"),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
icon: "award",
|
|
52
|
+
value: gamification.achievements.filter((a) => a.isUnlocked).length,
|
|
53
|
+
label: t("gamification.stats.achievementsUnlocked"),
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
// Level props
|
|
58
|
+
const levelProps = {
|
|
59
|
+
level: gamification.level.currentLevel,
|
|
60
|
+
points: gamification.level.currentPoints,
|
|
61
|
+
levelTitle: t("gamification.level.title", {
|
|
62
|
+
level: gamification.level.currentLevel,
|
|
63
|
+
}),
|
|
64
|
+
pointsToNext: gamification.level.pointsToNext,
|
|
65
|
+
progress: gamification.level.progress,
|
|
66
|
+
showPoints: true,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Streak props
|
|
70
|
+
const streakProps = gamification.streak.current > 0
|
|
71
|
+
? {
|
|
72
|
+
current: gamification.streak.current,
|
|
73
|
+
longest: gamification.streak.longest,
|
|
74
|
+
currentLabel: t("gamification.streak.current"),
|
|
75
|
+
bestLabel: t("gamification.streak.best"),
|
|
76
|
+
daysLabel: t("gamification.streak.days"),
|
|
77
|
+
}
|
|
78
|
+
: undefined;
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
...config.screenProps,
|
|
82
|
+
levelProps,
|
|
83
|
+
stats,
|
|
84
|
+
achievements,
|
|
85
|
+
streakProps,
|
|
86
|
+
emptyAchievementsText: t("gamification.achievements.empty"),
|
|
87
|
+
};
|
|
88
|
+
}, [gamification, config.screenProps, t]);
|
|
89
|
+
|
|
90
|
+
return <BaseGamificationScreen {...screenProps} />;
|
|
91
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gamification Settings Item Component
|
|
3
|
+
* Menu item to navigate to gamification screen
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { SettingsItemCard } from "../../../presentation/components/SettingsItemCard";
|
|
8
|
+
import type { GamificationMenuConfig } from "../types";
|
|
9
|
+
|
|
10
|
+
export interface GamificationSettingsItemProps {
|
|
11
|
+
config: GamificationMenuConfig;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Gamification menu item for settings screen
|
|
16
|
+
*/
|
|
17
|
+
export const GamificationSettingsItem: React.FC<GamificationSettingsItemProps> = ({
|
|
18
|
+
config,
|
|
19
|
+
}) => {
|
|
20
|
+
if (!config.enabled) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<SettingsItemCard
|
|
26
|
+
title={config.title}
|
|
27
|
+
description={config.subtitle}
|
|
28
|
+
icon={config.icon || "trophy"}
|
|
29
|
+
onPress={config.onPress}
|
|
30
|
+
showChevron
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gamification Configuration Example
|
|
3
|
+
*
|
|
4
|
+
* Copy this file to your app's settings config directory:
|
|
5
|
+
* src/domains/settings/config/gamification.config.ts
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { GamificationSettingsConfig } from "../types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates gamification configuration for settings
|
|
12
|
+
*
|
|
13
|
+
* @param t - Translation function from useLocalization
|
|
14
|
+
* @returns Gamification settings configuration
|
|
15
|
+
*/
|
|
16
|
+
export const createGamificationConfig = ({ t }): GamificationSettingsConfig => ({
|
|
17
|
+
enabled: true,
|
|
18
|
+
|
|
19
|
+
// Gamification system configuration
|
|
20
|
+
config: {
|
|
21
|
+
storageKey: "app_gamification_data",
|
|
22
|
+
|
|
23
|
+
// Define achievements
|
|
24
|
+
achievements: [
|
|
25
|
+
// Count-based achievements
|
|
26
|
+
{ id: "first_task", threshold: 1, type: "count" },
|
|
27
|
+
{ id: "five_tasks", threshold: 5, type: "count" },
|
|
28
|
+
{ id: "ten_tasks", threshold: 10, type: "count" },
|
|
29
|
+
{ id: "fifty_tasks", threshold: 50, type: "count" },
|
|
30
|
+
{ id: "hundred_tasks", threshold: 100, type: "count" },
|
|
31
|
+
|
|
32
|
+
// Streak-based achievements
|
|
33
|
+
{ id: "three_day_streak", threshold: 3, type: "streak" },
|
|
34
|
+
{ id: "week_streak", threshold: 7, type: "streak" },
|
|
35
|
+
{ id: "month_streak", threshold: 30, type: "streak" },
|
|
36
|
+
|
|
37
|
+
// Milestone achievements
|
|
38
|
+
{ id: "first_login", threshold: 1, type: "milestone" },
|
|
39
|
+
{ id: "power_user", threshold: 1, type: "milestone" },
|
|
40
|
+
],
|
|
41
|
+
|
|
42
|
+
// Define level progression
|
|
43
|
+
levels: [
|
|
44
|
+
{ level: 1, minPoints: 0, maxPoints: 50 },
|
|
45
|
+
{ level: 2, minPoints: 50, maxPoints: 150 },
|
|
46
|
+
{ level: 3, minPoints: 150, maxPoints: 300 },
|
|
47
|
+
{ level: 4, minPoints: 300, maxPoints: 500 },
|
|
48
|
+
{ level: 5, minPoints: 500, maxPoints: 800 },
|
|
49
|
+
{ level: 6, minPoints: 800, maxPoints: 1200 },
|
|
50
|
+
{ level: 7, minPoints: 1200, maxPoints: 1700 },
|
|
51
|
+
{ level: 8, minPoints: 1700, maxPoints: 2300 },
|
|
52
|
+
{ level: 9, minPoints: 2300, maxPoints: 3000 },
|
|
53
|
+
{ level: 10, minPoints: 3000, maxPoints: 999999 },
|
|
54
|
+
],
|
|
55
|
+
|
|
56
|
+
// Points awarded per action
|
|
57
|
+
pointsPerAction: 10,
|
|
58
|
+
|
|
59
|
+
// Streak bonus multiplier (1.5 = 50% bonus)
|
|
60
|
+
streakBonusMultiplier: 1.5,
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// Screen display configuration
|
|
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
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"settings": {
|
|
3
|
+
"gamification": {
|
|
4
|
+
"title": "Achievements",
|
|
5
|
+
"menuTitle": "Achievements & Progress",
|
|
6
|
+
"menuSubtitle": "View your achievements and stats"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"gamification": {
|
|
10
|
+
"title": "Your Progress",
|
|
11
|
+
"level": {
|
|
12
|
+
"title": "Level {{level}}"
|
|
13
|
+
},
|
|
14
|
+
"stats": {
|
|
15
|
+
"title": "Statistics",
|
|
16
|
+
"totalPoints": "Total Points",
|
|
17
|
+
"tasksCompleted": "Tasks Completed",
|
|
18
|
+
"achievementsUnlocked": "Achievements Unlocked"
|
|
19
|
+
},
|
|
20
|
+
"achievements": {
|
|
21
|
+
"title": "Achievements",
|
|
22
|
+
"empty": "No achievements yet. Keep going!",
|
|
23
|
+
"first_task": {
|
|
24
|
+
"title": "First Steps",
|
|
25
|
+
"description": "Complete your first task"
|
|
26
|
+
},
|
|
27
|
+
"five_tasks": {
|
|
28
|
+
"title": "Getting Started",
|
|
29
|
+
"description": "Complete 5 tasks"
|
|
30
|
+
},
|
|
31
|
+
"ten_tasks": {
|
|
32
|
+
"title": "On a Roll",
|
|
33
|
+
"description": "Complete 10 tasks"
|
|
34
|
+
},
|
|
35
|
+
"fifty_tasks": {
|
|
36
|
+
"title": "Dedicated",
|
|
37
|
+
"description": "Complete 50 tasks"
|
|
38
|
+
},
|
|
39
|
+
"hundred_tasks": {
|
|
40
|
+
"title": "Century Club",
|
|
41
|
+
"description": "Complete 100 tasks"
|
|
42
|
+
},
|
|
43
|
+
"three_day_streak": {
|
|
44
|
+
"title": "Consistent",
|
|
45
|
+
"description": "Maintain a 3-day streak"
|
|
46
|
+
},
|
|
47
|
+
"week_streak": {
|
|
48
|
+
"title": "Week Warrior",
|
|
49
|
+
"description": "Maintain a 7-day streak"
|
|
50
|
+
},
|
|
51
|
+
"month_streak": {
|
|
52
|
+
"title": "Monthly Master",
|
|
53
|
+
"description": "Maintain a 30-day streak"
|
|
54
|
+
},
|
|
55
|
+
"first_login": {
|
|
56
|
+
"title": "Welcome!",
|
|
57
|
+
"description": "Join the community"
|
|
58
|
+
},
|
|
59
|
+
"power_user": {
|
|
60
|
+
"title": "Power User",
|
|
61
|
+
"description": "Unlock all features"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"streak": {
|
|
65
|
+
"title": "Daily Streak",
|
|
66
|
+
"current": "Current Streak",
|
|
67
|
+
"best": "Best Streak",
|
|
68
|
+
"days": "days"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gamification Domain - Public API
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Types
|
|
6
|
+
export type {
|
|
7
|
+
GamificationSettingsConfig,
|
|
8
|
+
GamificationMenuConfig,
|
|
9
|
+
} from "./types";
|
|
10
|
+
|
|
11
|
+
// Components
|
|
12
|
+
export { GamificationScreenWrapper } from "./components/GamificationScreenWrapper";
|
|
13
|
+
export type { GamificationScreenWrapperProps } from "./components/GamificationScreenWrapper";
|
|
14
|
+
|
|
15
|
+
export { GamificationSettingsItem } from "./components/GamificationSettingsItem";
|
|
16
|
+
export type { GamificationSettingsItemProps } from "./components/GamificationSettingsItem";
|
|
17
|
+
|
|
18
|
+
// Re-export from gamification package for convenience
|
|
19
|
+
export {
|
|
20
|
+
useGamification,
|
|
21
|
+
useGamificationStore,
|
|
22
|
+
LevelProgress,
|
|
23
|
+
PointsBadge,
|
|
24
|
+
AchievementCard,
|
|
25
|
+
AchievementToast,
|
|
26
|
+
StreakDisplay,
|
|
27
|
+
StatsCard,
|
|
28
|
+
AchievementItem,
|
|
29
|
+
} from "@umituz/react-native-gamification";
|
|
30
|
+
|
|
31
|
+
export type {
|
|
32
|
+
GamificationConfig,
|
|
33
|
+
GamificationState,
|
|
34
|
+
Achievement,
|
|
35
|
+
LevelState,
|
|
36
|
+
StreakState,
|
|
37
|
+
UseGamificationReturn,
|
|
38
|
+
} from "@umituz/react-native-gamification";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gamification Domain - Types
|
|
3
|
+
* Settings package integration for gamification
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
GamificationConfig,
|
|
8
|
+
GamificationScreenProps,
|
|
9
|
+
} from "@umituz/react-native-gamification";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Gamification settings configuration
|
|
13
|
+
* Passed from app to settings package
|
|
14
|
+
*/
|
|
15
|
+
export interface GamificationSettingsConfig {
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
config: GamificationConfig;
|
|
18
|
+
screenProps: Omit<GamificationScreenProps, "levelProps" | "stats" | "achievements">;
|
|
19
|
+
onNavigate?: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Gamification menu item configuration
|
|
24
|
+
*/
|
|
25
|
+
export interface GamificationMenuConfig {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
title: string;
|
|
28
|
+
subtitle?: string;
|
|
29
|
+
icon?: string;
|
|
30
|
+
onPress?: () => void;
|
|
31
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -120,14 +120,24 @@ export * from "./domains/cloud-sync";
|
|
|
120
120
|
// Dev Domain - Development-only settings (DEV mode)
|
|
121
121
|
export * from "./domains/dev";
|
|
122
122
|
|
|
123
|
+
// Gamification Domain - Achievements, levels, streaks
|
|
124
|
+
export * from "./domains/gamification";
|
|
125
|
+
|
|
126
|
+
|
|
123
127
|
// =============================================================================
|
|
124
|
-
// PRESENTATION LAYER -
|
|
128
|
+
// PRESENTATION LAYER - Config Creator Utilities
|
|
125
129
|
// =============================================================================
|
|
126
130
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
export {
|
|
132
|
+
createAppearanceConfig,
|
|
133
|
+
createLanguageConfig,
|
|
134
|
+
createNotificationsConfig,
|
|
135
|
+
createAboutConfig,
|
|
136
|
+
createLegalConfig,
|
|
137
|
+
createFeedbackConfig,
|
|
138
|
+
createRatingConfig,
|
|
139
|
+
createFAQConfig,
|
|
140
|
+
createSubscriptionConfig,
|
|
141
|
+
type TranslationFunction,
|
|
142
|
+
type FeedbackFormData,
|
|
143
|
+
} from './presentation/utils';
|
|
@@ -29,8 +29,10 @@ import {
|
|
|
29
29
|
createNotificationsScreenOptions,
|
|
30
30
|
createFAQScreenOptions,
|
|
31
31
|
createLanguageSelectionScreenOptions,
|
|
32
|
+
createGamificationScreenOptions,
|
|
32
33
|
} from "./utils";
|
|
33
34
|
import type { SettingsStackParamList, SettingsStackNavigatorProps } from "./types";
|
|
35
|
+
import { GamificationScreenWrapper } from "../../domains/gamification";
|
|
34
36
|
|
|
35
37
|
const Stack = createStackNavigator<SettingsStackParamList>();
|
|
36
38
|
|
|
@@ -45,6 +47,7 @@ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
|
|
|
45
47
|
devSettings,
|
|
46
48
|
customSections = [],
|
|
47
49
|
showHeader = true,
|
|
50
|
+
gamificationConfig,
|
|
48
51
|
}) => {
|
|
49
52
|
const tokens = useAppDesignTokens();
|
|
50
53
|
const { t } = useLocalization();
|
|
@@ -143,6 +146,15 @@ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
|
|
|
143
146
|
) : null
|
|
144
147
|
)}
|
|
145
148
|
|
|
149
|
+
{gamificationConfig?.enabled && (
|
|
150
|
+
<Stack.Screen
|
|
151
|
+
name="Gamification"
|
|
152
|
+
options={createGamificationScreenOptions(t)}
|
|
153
|
+
>
|
|
154
|
+
{() => <GamificationScreenWrapper config={gamificationConfig} />}
|
|
155
|
+
</Stack.Screen>
|
|
156
|
+
)}
|
|
157
|
+
|
|
146
158
|
<Stack.Screen
|
|
147
159
|
name="LanguageSelection"
|
|
148
160
|
options={createLanguageSelectionScreenOptions(t)}
|
|
@@ -42,6 +42,7 @@ export type SettingsStackParamList = {
|
|
|
42
42
|
Notifications: undefined;
|
|
43
43
|
FAQ: undefined;
|
|
44
44
|
LanguageSelection: undefined;
|
|
45
|
+
Gamification: undefined;
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
/**
|
|
@@ -89,4 +90,5 @@ export interface SettingsStackNavigatorProps {
|
|
|
89
90
|
devSettings?: DevSettingsProps;
|
|
90
91
|
customSections?: CustomSettingsSection[];
|
|
91
92
|
showHeader?: boolean;
|
|
93
|
+
gamificationConfig?: import("../../domains/gamification").GamificationSettingsConfig;
|
|
92
94
|
}
|
|
@@ -54,3 +54,10 @@ export const createLanguageSelectionScreenOptions = (t: any) => ({
|
|
|
54
54
|
headerTitle: t("settings.language.title"),
|
|
55
55
|
headerTitleAlign: "center" as const,
|
|
56
56
|
});
|
|
57
|
+
|
|
58
|
+
export const createGamificationScreenOptions = (t: any) => ({
|
|
59
|
+
headerShown: true,
|
|
60
|
+
headerTitle: t("settings.gamification.title"),
|
|
61
|
+
headerTitleAlign: "center" as const,
|
|
62
|
+
});
|
|
63
|
+
|
|
@@ -12,6 +12,8 @@ import type { FeedbackType } from "../../../domains/feedback/domain/entities/Fee
|
|
|
12
12
|
export interface UserProfileConfig {
|
|
13
13
|
/** Show user profile header */
|
|
14
14
|
enabled?: boolean;
|
|
15
|
+
/** Custom section title for grouping */
|
|
16
|
+
sectionTitle?: string;
|
|
15
17
|
/** Custom display name for anonymous users */
|
|
16
18
|
anonymousDisplayName?: string;
|
|
17
19
|
/** Custom avatar service URL */
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Config Creators
|
|
3
|
+
* Utility functions to create standard settings configurations
|
|
4
|
+
* Used across 100+ apps - keep generic and flexible
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
AppearanceConfig,
|
|
9
|
+
LanguageConfig,
|
|
10
|
+
NotificationsConfig,
|
|
11
|
+
AboutConfig,
|
|
12
|
+
LegalConfig,
|
|
13
|
+
FeedbackConfig,
|
|
14
|
+
UserProfileConfig,
|
|
15
|
+
RatingConfig,
|
|
16
|
+
FAQConfig,
|
|
17
|
+
SubscriptionConfig,
|
|
18
|
+
} from "../screens/types";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Translation function type
|
|
22
|
+
*/
|
|
23
|
+
export type TranslationFunction = (key: string) => string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create appearance configuration
|
|
27
|
+
*/
|
|
28
|
+
export const createAppearanceConfig = (t: TranslationFunction): AppearanceConfig => ({
|
|
29
|
+
enabled: true,
|
|
30
|
+
title: t("settings.appearance.title"),
|
|
31
|
+
description: t("settings.appearance.description"),
|
|
32
|
+
icon: "color-palette-outline",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create language configuration
|
|
37
|
+
*/
|
|
38
|
+
export const createLanguageConfig = (t: TranslationFunction): LanguageConfig => ({
|
|
39
|
+
enabled: true,
|
|
40
|
+
title: t("settings.language.title"),
|
|
41
|
+
description: t("settings.language.description"),
|
|
42
|
+
icon: "globe-outline",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create notifications configuration
|
|
47
|
+
*/
|
|
48
|
+
export const createNotificationsConfig = (t: TranslationFunction): NotificationsConfig => ({
|
|
49
|
+
enabled: true,
|
|
50
|
+
showToggle: false,
|
|
51
|
+
route: "Notifications",
|
|
52
|
+
title: t("settings.notifications.title"),
|
|
53
|
+
description: t("settings.notifications.description"),
|
|
54
|
+
icon: "notifications-outline",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create about configuration
|
|
59
|
+
*/
|
|
60
|
+
export const createAboutConfig = (t: TranslationFunction): AboutConfig => ({
|
|
61
|
+
enabled: true,
|
|
62
|
+
title: t("settings.about.title"),
|
|
63
|
+
description: t("settings.about.description"),
|
|
64
|
+
icon: "information-circle-outline",
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Create legal configuration
|
|
69
|
+
*/
|
|
70
|
+
export const createLegalConfig = (t: TranslationFunction): LegalConfig => ({
|
|
71
|
+
enabled: true,
|
|
72
|
+
title: t("settings.legal.title"),
|
|
73
|
+
description: t("settings.legal.description"),
|
|
74
|
+
icon: "document-text-outline",
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Feedback form data interface
|
|
79
|
+
*/
|
|
80
|
+
export interface FeedbackFormData {
|
|
81
|
+
type: string;
|
|
82
|
+
rating: number;
|
|
83
|
+
description: string;
|
|
84
|
+
title: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Create feedback configuration
|
|
89
|
+
*/
|
|
90
|
+
export const createFeedbackConfig = (
|
|
91
|
+
t: TranslationFunction,
|
|
92
|
+
onSubmit: (data: FeedbackFormData) => Promise<void>,
|
|
93
|
+
): FeedbackConfig => ({
|
|
94
|
+
enabled: true,
|
|
95
|
+
title: t("settings.feedback.title"),
|
|
96
|
+
description: t("settings.feedback.description"),
|
|
97
|
+
icon: "chatbubble-outline",
|
|
98
|
+
sectionTitle: t("settings.sections.support"),
|
|
99
|
+
onSubmit,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Create rating configuration
|
|
104
|
+
*/
|
|
105
|
+
export const createRatingConfig = (
|
|
106
|
+
t: TranslationFunction,
|
|
107
|
+
onRate: () => void,
|
|
108
|
+
storeUrl?: string,
|
|
109
|
+
): RatingConfig => ({
|
|
110
|
+
enabled: true,
|
|
111
|
+
onRate,
|
|
112
|
+
storeUrl,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create FAQ configuration
|
|
117
|
+
*/
|
|
118
|
+
export const createFAQConfig = (
|
|
119
|
+
t: TranslationFunction,
|
|
120
|
+
onPress: () => void,
|
|
121
|
+
): FAQConfig => ({
|
|
122
|
+
enabled: true,
|
|
123
|
+
title: t("settings.faqs.title"),
|
|
124
|
+
description: t("settings.faqs.description"),
|
|
125
|
+
icon: "help-circle-outline",
|
|
126
|
+
sectionTitle: t("settings.sections.support").toUpperCase(),
|
|
127
|
+
onPress,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Create subscription configuration
|
|
132
|
+
*/
|
|
133
|
+
export const createSubscriptionConfig = (
|
|
134
|
+
t: TranslationFunction,
|
|
135
|
+
isPremium: boolean,
|
|
136
|
+
onPress: () => void,
|
|
137
|
+
): SubscriptionConfig => ({
|
|
138
|
+
enabled: true,
|
|
139
|
+
title: t("settings.subscription.title"),
|
|
140
|
+
description: isPremium
|
|
141
|
+
? t("subscription.premiumDetails.statusActive")
|
|
142
|
+
: t("settings.subscription.description"),
|
|
143
|
+
icon: "diamond",
|
|
144
|
+
sectionTitle: t("settings.sections.subscription").toUpperCase(),
|
|
145
|
+
onPress,
|
|
146
|
+
isPremium,
|
|
147
|
+
});
|