@umituz/react-native-gamification 1.4.2 → 1.4.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-gamification",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "Generic gamification system for React Native apps - achievements, points, levels, streaks with customizable UI components",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -35,13 +35,15 @@
35
35
  "react-native": ">=0.74.0"
36
36
  },
37
37
  "devDependencies": {
38
+ "@react-native-async-storage/async-storage": "^2.2.0",
39
+ "@types/react": "~19.1.10",
38
40
  "@umituz/react-native-design-system": "latest",
39
41
  "@umituz/react-native-localization": "latest",
40
42
  "@umituz/react-native-storage": "latest",
41
- "@types/react": "~19.1.10",
42
43
  "react": "19.1.0",
43
44
  "react-native": "0.81.5",
44
- "typescript": "~5.9.2"
45
+ "typescript": "~5.9.2",
46
+ "zustand": "^5.0.9"
45
47
  },
46
48
  "publishConfig": {
47
49
  "access": "public"
@@ -3,9 +3,7 @@
3
3
  * Zustand store with persist middleware
4
4
  */
5
5
 
6
- import { create } from "zustand";
7
- import { persist, createJSONStorage } from "zustand/middleware";
8
- import AsyncStorage from "@react-native-async-storage/async-storage";
6
+ import { createStore } from "@umituz/react-native-storage";
9
7
  import type {
10
8
  GamificationState,
11
9
  GamificationActions,
@@ -34,134 +32,131 @@ const DEFAULT_STATE: GamificationState = {
34
32
 
35
33
  let currentConfig: GamificationConfig | null = null;
36
34
 
37
- export const useGamificationStore = create<
38
- GamificationState & GamificationActions
39
- >()(
40
- persist(
41
- (set, get) => ({
42
- ...DEFAULT_STATE,
43
-
44
- initialize: async (config: GamificationConfig) => {
45
- currentConfig = config;
46
- const state = get();
47
-
48
- // Initialize achievements from config
49
- const achievements: Achievement[] = config.achievements.map((def) => ({
50
- ...def,
51
- isUnlocked: false,
52
- progress: 0,
53
- }));
54
-
55
- // Merge with existing unlocked achievements
56
- const mergedAchievements = achievements.map((ach) => {
57
- const existing = state.achievements.find((a) => a.id === ach.id);
58
- if (existing) {
59
- return { ...ach, isUnlocked: existing.isUnlocked, progress: existing.progress };
60
- }
61
- return ach;
62
- });
63
-
64
- set({ achievements: mergedAchievements, isInitialized: true });
65
- },
66
-
67
- addPoints: (amount: number) => {
68
- set((state) => ({ points: state.points + amount }));
69
- },
70
-
71
- completeTask: () => {
72
- const state = get();
73
- const pointsToAdd = currentConfig?.pointsPerAction ?? 15;
74
-
75
- set({
76
- totalTasksCompleted: state.totalTasksCompleted + 1,
77
- points: state.points + pointsToAdd,
78
- });
79
-
80
- // Update streak
81
- get().updateStreak();
82
-
83
- // Check achievements
84
- get().checkAchievements();
85
- },
86
-
87
- updateStreak: () => {
88
- const state = get();
89
- const now = new Date();
90
- const lastDate = state.streak.lastActivityDate
91
- ? new Date(state.streak.lastActivityDate)
92
- : null;
93
-
94
- let newStreak = state.streak.current;
95
-
96
- if (!lastDate || !isSameDay(lastDate, now)) {
97
- if (isStreakActive(state.streak.lastActivityDate)) {
98
- newStreak = state.streak.current + 1;
99
- } else {
100
- newStreak = 1;
101
- }
35
+ export const useGamificationStore = createStore<GamificationState, GamificationActions>({
36
+ name: "gamification-storage",
37
+ initialState: DEFAULT_STATE,
38
+ persist: true,
39
+ version: 1,
40
+ partialize: (state) => ({
41
+ points: state.points,
42
+ totalTasksCompleted: state.totalTasksCompleted,
43
+ achievements: state.achievements,
44
+ streak: state.streak,
45
+ isLoading: false,
46
+ isInitialized: false,
47
+ }),
48
+ actions: (set, get) => ({
49
+ initialize: async (config: GamificationConfig) => {
50
+ currentConfig = config;
51
+ const state = get();
52
+
53
+ // Initialize achievements from config
54
+ const achievements: Achievement[] = config.achievements.map((def) => ({
55
+ ...def,
56
+ isUnlocked: false,
57
+ progress: 0,
58
+ }));
59
+
60
+ // Merge with existing unlocked achievements
61
+ const mergedAchievements = achievements.map((ach: Achievement) => {
62
+ const existing = state.achievements.find((a: Achievement) => a.id === ach.id);
63
+ if (existing) {
64
+ return { ...ach, isUnlocked: existing.isUnlocked, progress: existing.progress };
102
65
  }
66
+ return ach;
67
+ });
68
+
69
+ set({ achievements: mergedAchievements, isInitialized: true });
70
+ },
71
+
72
+ addPoints: (amount: number) => {
73
+ const state = get();
74
+ set({ points: state.points + amount });
75
+ },
76
+
77
+ completeTask: () => {
78
+ const state = get();
79
+ const pointsToAdd = currentConfig?.pointsPerAction ?? 15;
80
+
81
+ set({
82
+ totalTasksCompleted: state.totalTasksCompleted + 1,
83
+ points: state.points + pointsToAdd,
84
+ });
85
+
86
+ // Update streak
87
+ get().updateStreak();
88
+
89
+ // Check achievements
90
+ get().checkAchievements();
91
+ },
92
+
93
+ updateStreak: () => {
94
+ const state = get();
95
+ const now = new Date();
96
+ const lastDate = state.streak.lastActivityDate
97
+ ? new Date(state.streak.lastActivityDate)
98
+ : null;
99
+
100
+ let newStreak = state.streak.current;
101
+
102
+ if (!lastDate || !isSameDay(lastDate, now)) {
103
+ if (isStreakActive(state.streak.lastActivityDate)) {
104
+ newStreak = state.streak.current + 1;
105
+ } else {
106
+ newStreak = 1;
107
+ }
108
+ }
109
+
110
+ set({
111
+ streak: {
112
+ current: newStreak,
113
+ longest: Math.max(state.streak.longest, newStreak),
114
+ lastActivityDate: now.toISOString(),
115
+ },
116
+ });
117
+ },
118
+
119
+ checkAchievements: () => {
120
+ if (!currentConfig) return [];
121
+
122
+ const state = get();
123
+ const newlyUnlocked: Achievement[] = [];
124
+
125
+ const updatedAchievements = state.achievements.map((ach: Achievement) => {
126
+ if (ach.isUnlocked) return ach;
127
+
128
+ const progress = updateAchievementProgress(
129
+ ach,
130
+ state.totalTasksCompleted,
131
+ state.streak.current
132
+ );
133
+
134
+ const shouldUnlock = checkAchievementUnlock(
135
+ ach,
136
+ state.totalTasksCompleted,
137
+ state.streak.current
138
+ );
139
+
140
+ if (shouldUnlock && !ach.isUnlocked) {
141
+ const unlocked = {
142
+ ...ach,
143
+ isUnlocked: true,
144
+ unlockedAt: new Date().toISOString(),
145
+ progress: 100,
146
+ };
147
+ newlyUnlocked.push(unlocked);
148
+ return unlocked;
149
+ }
150
+
151
+ return { ...ach, progress };
152
+ });
153
+
154
+ set({ achievements: updatedAchievements });
155
+ return newlyUnlocked;
156
+ },
103
157
 
104
- set({
105
- streak: {
106
- current: newStreak,
107
- longest: Math.max(state.streak.longest, newStreak),
108
- lastActivityDate: now.toISOString(),
109
- },
110
- });
111
- },
112
-
113
- checkAchievements: () => {
114
- if (!currentConfig) return [];
115
-
116
- const state = get();
117
- const newlyUnlocked: Achievement[] = [];
118
-
119
- const updatedAchievements = state.achievements.map((ach) => {
120
- if (ach.isUnlocked) return ach;
121
-
122
- const progress = updateAchievementProgress(
123
- ach,
124
- state.totalTasksCompleted,
125
- state.streak.current
126
- );
127
-
128
- const shouldUnlock = checkAchievementUnlock(
129
- ach,
130
- state.totalTasksCompleted,
131
- state.streak.current
132
- );
133
-
134
- if (shouldUnlock && !ach.isUnlocked) {
135
- const unlocked = {
136
- ...ach,
137
- isUnlocked: true,
138
- unlockedAt: new Date().toISOString(),
139
- progress: 100,
140
- };
141
- newlyUnlocked.push(unlocked);
142
- return unlocked;
143
- }
144
-
145
- return { ...ach, progress };
146
- });
147
-
148
- set({ achievements: updatedAchievements });
149
- return newlyUnlocked;
150
- },
151
-
152
- reset: async () => {
153
- set(DEFAULT_STATE);
154
- },
155
- }),
156
- {
157
- name: "gamification-storage",
158
- storage: createJSONStorage(() => AsyncStorage),
159
- partialize: (state) => ({
160
- points: state.points,
161
- totalTasksCompleted: state.totalTasksCompleted,
162
- achievements: state.achievements,
163
- streak: state.streak,
164
- }),
165
- }
166
- )
167
- );
158
+ reset: async () => {
159
+ set(DEFAULT_STATE);
160
+ },
161
+ }),
162
+ });