react-achievements 2.2.2 → 3.0.0

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 (77) hide show
  1. package/README.md +257 -406
  2. package/dist/index.d.ts +222 -8
  3. package/dist/index.js +631 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/stories/Button.d.ts +28 -0
  6. package/dist/stories/Button.stories.d.ts +23 -0
  7. package/dist/stories/Header.d.ts +13 -0
  8. package/dist/stories/Header.stories.d.ts +18 -0
  9. package/dist/stories/Page.d.ts +3 -0
  10. package/dist/stories/Page.stories.d.ts +12 -0
  11. package/dist/types/__mocks__/confetti-wrapper.d.ts +5 -0
  12. package/dist/types/__mocks__/react-confetti.d.ts +3 -0
  13. package/dist/types/__mocks__/react-toastify.d.ts +13 -0
  14. package/dist/types/core/components/BadgesButton.d.ts +10 -0
  15. package/dist/types/core/components/BadgesModal.d.ts +11 -0
  16. package/dist/types/core/components/ConfettiWrapper.d.ts +6 -0
  17. package/dist/types/core/context/AchievementContext.d.ts +5 -0
  18. package/dist/types/core/icons/defaultIcons.d.ts +81 -0
  19. package/dist/types/core/storage/LocalStorage.d.ts +16 -0
  20. package/dist/types/core/storage/MemoryStorage.d.ts +11 -0
  21. package/dist/types/core/styles/defaultStyles.d.ts +2 -0
  22. package/dist/types/core/types.d.ts +74 -0
  23. package/dist/types/hooks/useAchievements.d.ts +1 -0
  24. package/dist/types/index.d.ts +10 -0
  25. package/dist/types/providers/AchievementProvider.d.ts +24 -0
  26. package/dist/types/setupTests.d.ts +1 -0
  27. package/dist/types/stories/Button.d.ts +16 -0
  28. package/dist/types/stories/Button.stories.d.ts +23 -0
  29. package/dist/types/stories/Header.d.ts +13 -0
  30. package/dist/types/stories/Header.stories.d.ts +18 -0
  31. package/dist/types/stories/Page.d.ts +3 -0
  32. package/dist/types/stories/Page.stories.d.ts +12 -0
  33. package/package.json +73 -54
  34. package/.idea/jsLibraryMappings.xml +0 -6
  35. package/.idea/modules.xml +0 -8
  36. package/.idea/react-achievements.iml +0 -12
  37. package/.idea/vcs.xml +0 -6
  38. package/coverage/clover.xml +0 -131
  39. package/coverage/coverage-final.json +0 -9
  40. package/coverage/lcov-report/base.css +0 -224
  41. package/coverage/lcov-report/block-navigation.js +0 -87
  42. package/coverage/lcov-report/favicon.png +0 -0
  43. package/coverage/lcov-report/index.html +0 -146
  44. package/coverage/lcov-report/prettify.css +0 -1
  45. package/coverage/lcov-report/prettify.js +0 -2
  46. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  47. package/coverage/lcov-report/sorter.js +0 -196
  48. package/coverage/lcov-report/src/components/AchievementModal.tsx.html +0 -229
  49. package/coverage/lcov-report/src/components/BadgesButton.tsx.html +0 -169
  50. package/coverage/lcov-report/src/components/BadgesModal.tsx.html +0 -253
  51. package/coverage/lcov-report/src/components/ConfettiWrapper.tsx.html +0 -157
  52. package/coverage/lcov-report/src/components/index.html +0 -161
  53. package/coverage/lcov-report/src/context/AchievementContext.tsx.html +0 -505
  54. package/coverage/lcov-report/src/context/index.html +0 -116
  55. package/coverage/lcov-report/src/index.html +0 -146
  56. package/coverage/lcov-report/src/index.ts.html +0 -121
  57. package/coverage/lcov-report/src/react-confetti.d.ts.html +0 -139
  58. package/coverage/lcov-report/src/react-use.d.ts.html +0 -94
  59. package/coverage/lcov.info +0 -240
  60. package/demo/src/AchievementConfig.ts +0 -0
  61. package/public/badges/icon1.svg +0 -1
  62. package/rollup.config.mjs +0 -34
  63. package/src/assets/defaultIcons.ts +0 -100
  64. package/src/components/BadgesButton.tsx +0 -49
  65. package/src/components/BadgesModal.tsx +0 -47
  66. package/src/components/ConfettiWrapper.tsx +0 -17
  67. package/src/defaultStyles.ts +0 -86
  68. package/src/hooks/useAchievement.ts +0 -17
  69. package/src/index.ts +0 -25
  70. package/src/providers/AchievementProvider.tsx +0 -202
  71. package/src/react-confetti.d.ts +0 -19
  72. package/src/react-use.d.ts +0 -4
  73. package/src/redux/achievementSlice.ts +0 -116
  74. package/src/redux/notificationSlice.ts +0 -26
  75. package/src/redux/store.ts +0 -16
  76. package/src/types.ts +0 -39
  77. package/tsconfig.json +0 -113
package/README.md CHANGED
@@ -1,463 +1,314 @@
1
- <h1 align="center">🏆 React-Achievements 🏆</h1>
1
+ # React Achievements
2
2
 
3
- <p align="center">A flexible and customizable achievement system for React applications, perfect for adding gamification elements to your projects.</p>
3
+ A flexible and extensible achievement system for React applications. This package provides the foundation for implementing achievements in React applications with support for multiple state management solutions including Redux, Zustand, and Context API. Check the `stories/examples` directory for implementation examples with different state management solutions.
4
4
 
5
- ![React Achievements Demo](https://media.giphy.com/media/5sXoITml136LmyBPEc/giphy.gif)
5
+ ## State Management Options
6
6
 
7
- <p align="center">If you want to test the package, you can try it out here:</p>
7
+ This package includes example implementations for different state management solutions in the `stories/examples` directory:
8
8
 
9
- <p align="center">https://stackblitz.com/edit/vitejs-vite-sccdux</p>
9
+ - **Redux**: For large applications with complex state management needs
10
+ - **Zustand**: For applications needing a lightweight, modern state solution
11
+ - **Context API**: For applications preferring React's built-in solutions
10
12
 
11
- <h2 align="center">🚀 Installation</h2>
13
+ See the [examples directory](./stories/examples) for detailed implementations and instructions for each state management solution.
12
14
 
13
- Install `react-achievements` and its peer dependencies using npm or yarn:
15
+ ## Features
14
16
 
15
- ```bash
16
- npm install react-achievements @reduxjs/toolkit react-redux react-toastify react-confetti react-use
17
- ```
17
+ - Framework-agnostic achievement system
18
+ - Customizable storage implementations
19
+ - Built-in local storage support
20
+ - Customizable UI components
21
+ - Toast notifications
22
+ - Confetti animations
23
+ - TypeScript support
18
24
 
19
- or
25
+ ## Installation
20
26
 
21
27
  ```bash
22
- yarn add react-achievements @reduxjs/toolkit react-redux react-toastify react-confetti react-use
28
+ npm install react-achievements
23
29
  ```
24
30
 
25
- <h2 align="center">🎮 Usage</h2>
31
+ ## Basic Usage
26
32
 
27
- Let's walk through setting up a simple RPG-style game with achievements.
33
+ ```tsx
34
+ import { AchievementProvider, useAchievements } from 'react-achievements';
35
+ // For specific state management implementations:
36
+ // import { AchievementProvider, useAchievements } from 'react-achievements/redux';
37
+ // import { AchievementProvider, useAchievements } from 'react-achievements/zustand';
38
+ // import { AchievementProvider, useAchievements } from 'react-achievements/context';
39
+
40
+ // Define your achievements with various data types and conditions
41
+ const achievements = {
42
+ // Numeric achievements with thresholds
43
+ score: {
44
+ 100: {
45
+ title: 'Century!',
46
+ description: 'Score 100 points',
47
+ icon: 'trophy'
48
+ },
49
+ 500: {
50
+ title: 'Half a Thousand!',
51
+ description: 'Score 500 points',
52
+ icon: 'gold',
53
+ condition: (value) => value >= 500
54
+ }
55
+ },
28
56
 
29
- <h3 align="center">🛠 Set up the AchievementProvider</h3>
57
+ // Boolean achievements
58
+ completedTutorial: {
59
+ true: {
60
+ title: 'Tutorial Master',
61
+ description: 'Complete the tutorial',
62
+ icon: 'book'
63
+ }
64
+ },
30
65
 
31
- First, wrap your app or a part of your app with the AchievementProvider:
66
+ // String-based achievements
67
+ characterClass: {
68
+ 'wizard': {
69
+ title: 'Arcane Scholar',
70
+ description: 'Choose the wizard class',
71
+ icon: 'wand'
72
+ },
73
+ 'warrior': {
74
+ title: 'Battle Hardened',
75
+ description: 'Choose the warrior class',
76
+ icon: 'sword'
77
+ }
78
+ },
79
+
80
+ // Array-based achievements
81
+ collectedItems: {
82
+ ['sword', 'shield', 'potion']: {
83
+ title: 'Fully Equipped',
84
+ description: 'Collect all essential items',
85
+ icon: 'backpack',
86
+ condition: (items) => ['sword', 'shield', 'potion'].every(item => items.includes(item))
87
+ }
88
+ },
32
89
 
33
- ```jsx
34
- import React from 'react';
35
- import { Provider } from 'react-redux';
36
- import store from './store';
37
- import { AchievementProvider } from 'react-achievements';
38
- import Game from './Game';
39
- import achievementConfig from './achievementConfig';
90
+ // Object-based achievements
91
+ playerStats: {
92
+ { strength: 10, intelligence: 10 }: {
93
+ title: 'Balanced Warrior',
94
+ description: 'Achieve balanced stats',
95
+ icon: 'scale',
96
+ condition: (stats) => stats.strength === 10 && stats.intelligence === 10
97
+ }
98
+ },
99
+
100
+ // Time-based achievements
101
+ playTime: {
102
+ 3600: {
103
+ title: 'Dedicated Player',
104
+ description: 'Play for 1 hour',
105
+ icon: 'clock',
106
+ condition: (seconds) => seconds >= 3600
107
+ }
108
+ },
40
109
 
41
- const initialState = {
42
- level: 1,
43
- experience: 0,
44
- monstersDefeated: 0,
45
- questsCompleted: 0,
46
- previouslyAwardedAchievements: ['first_step'], // Optional: Load previously awarded achievements
110
+ // Combination achievements
111
+ combo: {
112
+ { score: 1000, level: 5 }: {
113
+ title: 'Rising Star',
114
+ description: 'Reach level 5 with 1000 points',
115
+ icon: 'star',
116
+ condition: (metrics) => metrics.score >= 1000 && metrics.level >= 5
117
+ }
118
+ }
47
119
  };
48
120
 
49
- function App() {
50
- return (
51
- <Provider store={store}>
52
- <AchievementProvider
53
- config={achievementConfig} // Required: your achievement configuration
54
- initialState={initialState} // Required: initial game metrics and optionally previously awarded achievements. This can be loaded from your server
55
- storageKey="my-game-achievements" // Optional: customize local storage key
56
- badgesButtonPosition="top-right" // Optional: customize badges button position
57
- // Optional: add custom styles and icons here
58
- >
59
- <Game />
60
- </AchievementProvider>
61
- </Provider>
62
- );
63
- }
121
+ // Create your app component
122
+ const App = () => {
123
+ return (
124
+ <AchievementProvider
125
+ achievements={achievements}
126
+ storage="local" // or "memory" or custom storage
127
+ >
128
+ <Game />
129
+ </AchievementProvider>
130
+ );
131
+ };
64
132
 
65
- export default App;
133
+ // Use achievements in your components
134
+ const Game = () => {
135
+ const { update, achievements } = useAchievements();
136
+
137
+ const handleScoreUpdate = (newScore: number) => {
138
+ update({ score: newScore });
139
+ };
140
+
141
+ return (
142
+ <div>
143
+ <h1>Game</h1>
144
+ <p>Unlocked Achievements: {achievements.unlocked.length}</p>
145
+ <button onClick={() => handleScoreUpdate(100)}>
146
+ Score 100 points
147
+ </button>
148
+ </div>
149
+ );
150
+ };
66
151
  ```
67
152
 
68
- <h3 align="center">🛠 Set up the Store</h3>
153
+ ## Default Icons
69
154
 
70
- You need to create a store for you state
155
+ The package comes with a comprehensive set of default icons that you can use in your achievements. These are available through the `defaultAchievementIcons` export:
71
156
 
72
157
  ```tsx
73
- // src/store.ts
74
- // src/store.js
75
-
76
- import { configureStore } from '@reduxjs/toolkit';
77
- import achievementReducer from 'react-achievements/redux/achievementSlice';
78
- import notificationReducer from 'react-achievements/redux/notificationSlice';
158
+ import { AchievementProvider, defaultAchievementIcons } from 'react-achievements-core';
79
159
 
80
- const store = configureStore({
81
- reducer: {
82
- achievements: achievementReducer,
83
- notifications: notificationReducer,
84
- },
85
- });
86
-
87
- // If you are using JavaScript, you don't need to explicitly export RootState and AppDispatch types.
88
- export type RootState = ReturnType<typeof store.getState>;
89
- export type AppDispatch = typeof store.dispatch;
160
+ // Example achievement configuration using default icons
161
+ const achievementConfig = {
162
+ pageViews: [
163
+ {
164
+ isConditionMet: (value) => value >= 5,
165
+ achievementDetails: {
166
+ achievementId: 'views-5',
167
+ achievementTitle: 'Getting Started',
168
+ achievementDescription: 'Viewed 5 pages',
169
+ achievementIconKey: 'firstStep' // This will use the 👣 emoji from defaultAchievementIcons
170
+ }
171
+ }
172
+ ]
173
+ };
90
174
 
91
- export default store;
175
+ // Create your app component
176
+ const App = () => {
177
+ return (
178
+ <AchievementProvider
179
+ achievements={achievementConfig}
180
+ // The provider automatically uses defaultAchievementIcons
181
+ >
182
+ <Game />
183
+ </AchievementProvider>
184
+ );
185
+ };
92
186
  ```
93
187
 
94
- <h3 align="center">📝 Create an achievement configuration</h3>
188
+ ### Custom Icons
95
189
 
96
- Create a file (e.g., achievementConfig.js) to define your achievements:
190
+ You can also provide your own custom icons that will override or extend the default ones:
97
191
 
98
- ```javascript
99
- // achievementConfig.js
100
- import levelUpIcon from './icons/level-up.png';
101
- import monsterSlayerIcon from './icons/monster-slayer.png';
102
- import questMasterIcon from './icons/quest-master.png';
192
+ ```tsx
193
+ import { AchievementProvider, defaultAchievementIcons } from 'react-achievements-core';
103
194
 
104
- const achievementConfig = {
105
- level: [
106
- {
107
- isConditionMet: (value) => value >= 1,
108
- achievementDetails: {
109
- achievementId: 'level_1',
110
- achievementTitle: 'Novice Adventurer',
111
- achievementDescription: 'Reached level 1',
112
- achievementIconKey: 'levelUpIcon',
113
- },
114
- },
115
- {
116
- isConditionMet: (value) => value >= 5,
117
- achievementDetails: {
118
- achievementId: 'level_5',
119
- achievementTitle: 'Seasoned Warrior',
120
- achievementDescription: 'Reached level 5',
121
- achievementIconKey: 'levelUpIcon',
122
- },
123
- },
124
- ],
125
- monstersDefeated: [
126
- {
127
- isConditionMet: (value) => value >= 10,
128
- achievementDetails: {
129
- achievementId: 'monster_slayer',
130
- achievementTitle: 'Monster Slayer',
131
- achievementDescription: 'Defeated 10 monsters',
132
- achievementIconKey: 'monsterSlayerIcon',
133
- },
134
- },
135
- ],
136
- questsCompleted: [
137
- {
138
- isConditionMet: (value) => value >= 1,
139
- achievementDetails: {
140
- achievementId: 'quest_master',
141
- achievementTitle: 'Quest Master',
142
- achievementDescription: 'Completed 1 quest',
143
- achievementIconKey: 'questMasterIcon',
144
- },
145
- },
146
- ],
195
+ // Create custom icons by extending the defaults
196
+ const customIcons = {
197
+ ...defaultAchievementIcons, // Include all default icons
198
+ levelUp: '🚀', // Override the default for 'levelUp'
199
+ myCustomIcon: '💻' // Add a new icon not in the defaults
147
200
  };
148
201
 
149
- export default achievementConfig;
202
+ const App = () => {
203
+ return (
204
+ <AchievementProvider
205
+ achievements={achievementConfig}
206
+ icons={customIcons} // Pass your custom icons to the provider
207
+ >
208
+ <Game />
209
+ </AchievementProvider>
210
+ );
211
+ };
150
212
  ```
151
213
 
152
- <h3 align="center">🎣 Use the useAchievement hook</h3>
153
-
154
- In your game components, use the useAchievement hook to update metrics and trigger achievement checks:
155
- ```jsx
156
- import React, { useState } from 'react';
157
- import { useAchievement } from 'react-achievements';
158
-
159
- function Game() {
160
- const { updateMetrics, metrics } = useAchievement();
161
- const [currentQuest, setCurrentQuest] = useState(null);
162
-
163
- const defeatMonster = () => {
164
- updateMetrics({
165
- monstersDefeated: [(metrics.monstersDefeated?.[0] || 0) + 1],
166
- experience: [(metrics.experience?.[0] || 0) + 10],
167
- level: [Math.floor(((metrics.experience?.[0] || 0) + 10) / 100) + 1], // Calculate new level
168
- });
169
- };
170
-
171
- const completeQuest = () => {
172
- updateMetrics({
173
- questsCompleted: [(metrics.questsCompleted?.[0] || 0) + 1],
174
- experience: [(metrics.experience?.[0] || 0) + 50],
175
- level: [Math.floor(((metrics.experience?.[0] || 0) + 50) / 100) + 1], // Calculate new level
176
- });
177
- setCurrentQuest(null);
178
- };
179
-
180
- const startQuest = () => {
181
- setCurrentQuest("Defeat the Dragon");
182
- };
183
-
184
- return (
185
- <div>
186
- <h1>My RPG Game</h1>
187
- <p>Level: {metrics.level?.[0] || 1}</p>
188
- <p>Experience: {metrics.experience?.[0] || 0}</p>
189
- <p>Monsters Defeated: {metrics.monstersDefeated?.[0] || 0}</p>
190
- <p>Quests Completed: {metrics.questsCompleted?.[0] || 0}</p>
191
-
192
- <div>
193
- <h2>Battle Arena</h2>
194
- <button onClick={defeatMonster}>Fight a Monster</button>
195
- </div>
196
-
197
- <div>
198
- <h2>Quest Board</h2>
199
- {currentQuest ? (
200
- <>
201
- <p>Current Quest: {currentQuest}</p>
202
- <button onClick={completeQuest}>Complete Quest</button>
203
- </>
204
- ) : (
205
- <button onClick={startQuest}>Start a New Quest</button>
206
- )}
207
- </div>
208
- </div>
209
- );
210
- }
214
+ ### Available Icons
211
215
 
212
- export default Game;
213
- ```
216
+ The `defaultAchievementIcons` includes icons in these categories:
214
217
 
215
- <h2 align="center">✨ Features</h2>
216
-
217
- - Flexible Achievement System: Define custom metrics and achievement conditions for your game or app.
218
- - Built with TypeScript: Provides strong typing and improved developer experience.
219
- - Redux-Powered State Management: Leverages Redux for predictable and scalable state management of achievements and metrics.
220
- - Automatic Achievement Tracking: Achievements are automatically checked and unlocked when metrics change.
221
- - Achievement Notifications: Uses react-toastify to display notifications when an achievement is unlocked
222
- - Persistent Achievements: Unlocked achievements and metrics are stored in local storage, allowing players to keep their progress
223
- - Achievement Gallery: Players can view all their unlocked achievements, encouraging completionism
224
- - Confetti Effect: A celebratory confetti effect is displayed when an achievement is unlocked, adding to the excitement
225
- - Local Storage: Achievements are stored locally on the device
226
- - **Loading Previous Awards:** The AchievementProvider accepts an optional previouslyAwardedAchievements array in its initialState prop, allowing you to load achievements that the user has already earned
227
- - **Programmatic Reset:** Includes a `resetStorage` function accessible via the `useAchievementContext` hook to easily reset all achievement data
228
-
229
- <h2 align="center">🔧 API</h2>
230
-
231
- <h3 align="center">🏗 AchievementProvider</h3>
232
-
233
- #### Props:
234
-
235
- - `config` (required): An object defining your metrics and achievements
236
- - `initialState` (optional): The initial state of your metrics. Can also include an optional previouslyAwardedAchievements array of achievement IDs
237
- - `storageKey` (optional): A string to use as the key for localStorage. Default: 'react-achievements'
238
- - `badgesButtonPosition` (optional): Position of the badges button. One of: 'top-left', 'top-right', 'bottom-left', 'bottom-right'. Default: 'top-right'
239
- - `styles` (optional): Custom styles for the badges components (see Customization section below)
240
- - `icons` (optional): Custom icons to use for achievements. You can use the default icons provided by the library (see Available Icons section) or provide your own. Icons should be a Record<string, string> where the key is the iconKey referenced in your achievement config and the value is the icon string/element.
241
-
242
- ### Available Default Icons
243
-
244
- ```javascript
245
- {
246
- // Time & Activity
247
- activeDay: '☀️',
248
- activeWeek: '📅',
249
- activeMonth: '🗓️',
250
- earlyBird: '⏰',
251
- nightOwl: '🌙',
252
- streak: '🔥',
253
- dedicated: '⏳',
254
- punctual: '⏱️',
255
- consistent: '🔄',
256
- marathon: '🏃',
257
-
258
- // Creativity & Skill
259
- artist: '🎨',
260
- writer: '✍️',
261
- innovator: '🔬',
262
- creator: '🛠️',
263
- expert: '🎓',
264
- master: '👑',
265
- pioneer: '🚀',
266
- performer: '🎭',
267
- thinker: '🧠',
268
- explorer: '🗺️',
269
-
270
- // Achievement Types
271
- bronze: '🥉',
272
- silver: '🥈',
273
- gold: '🥇',
274
- diamond: '💎',
275
- legendary: '✨',
276
- epic: '💥',
277
- rare: '🔮',
278
- common: '🔘',
279
- special: '🎁',
280
- hidden: '❓',
281
-
282
- // Numbers & Counters
283
- one: '1️⃣',
284
- ten: '🔟',
285
- hundred: '💯',
286
- thousand: '🔢',
287
-
288
- // Actions & Interactions
289
- clicked: '🖱️',
290
- used: '🔑',
291
- found: '🔍',
292
- built: '🧱',
293
- solved: '🧩',
294
- discovered: '🔭',
295
- unlocked: '🔓',
296
- upgraded: '⬆️',
297
- repaired: '🔧',
298
- defended: '🛡️',
299
-
300
- // Placeholders
301
- default: '⭐', // A fallback icon
302
- loading: '⏳',
303
- error: '⚠️',
304
- success: '✅',
305
- failure: '❌',
306
-
307
- // Miscellaneous
308
- trophy: '🏆',
309
- star: '⭐',
310
- flag: '🚩',
311
- puzzle: '🧩',
312
- gem: '💎',
313
- crown: '👑',
314
- medal: '🏅',
315
- ribbon: '🎗️',
316
- badge: '🎖️',
317
- shield: '🛡️',
318
- }
319
- ```
218
+ - General Progress & Milestones (levelUp, questComplete, etc.)
219
+ - Social & Engagement (shared, liked, etc.)
220
+ - Time & Activity (activeDay, streak, etc.)
221
+ - Creativity & Skill (artist, expert, etc.)
222
+ - Achievement Types (bronze, silver, gold, etc.)
223
+ - Numbers & Counters (one, ten, hundred, etc.)
224
+ - Actions & Interactions (clicked, discovered, etc.)
225
+ - Placeholders (default, loading, error, etc.)
226
+ - Miscellaneous (trophy, star, gem, etc.)
320
227
 
321
- <h2 align="center">🎨 Customization</h2>
228
+ ## Custom Storage
322
229
 
323
- You can customize the look of the achievement badges by overriding the default styles. Pass a `styles` prop to the `AchievementProvider`:
230
+ You can implement your own storage solution by implementing the `AchievementStorage` interface:
324
231
 
325
- ```javascript
326
- const customStyles = {
327
- badge: {
328
- // Your custom styles here
329
- },
330
- // ...other styles
331
- };
232
+ ```typescript
233
+ import { AchievementStorage } from 'react-achievements-core';
332
234
 
333
- <AchievementProvider
334
- config={achievementConfig}
335
- initialState={initialState}
336
- styles={customStyles}
337
- >
338
- <Game />
339
- </AchievementProvider>
340
- ```
235
+ class CustomStorage implements AchievementStorage {
236
+ getMetrics() {
237
+ // Your implementation
238
+ }
341
239
 
342
- <h2 align="center">🔄 Complex Achievement Conditions</h2>
240
+ setMetrics(metrics) {
241
+ // Your implementation
242
+ }
343
243
 
344
- <h3 align="center">Achievement Dependencies</h3>
244
+ getUnlockedAchievements() {
245
+ // Your implementation
246
+ }
345
247
 
346
- You can create achievements that depend on other achievements being unlocked first:
248
+ setUnlockedAchievements(achievements) {
249
+ // Your implementation
250
+ }
347
251
 
348
- ```javascript
349
- const achievementConfig = {
350
- prerequisite: [
351
- {
352
- isConditionMet: (value) => value === true,
353
- achievementDetails: {
354
- achievementId: 'prerequisite',
355
- achievementTitle: 'Prerequisites Met',
356
- achievementDescription: 'Unlocked advanced achievements',
357
- achievementIconKey: 'unlock'
358
- }
359
- }
360
- ],
361
- dependent: [
362
- {
363
- isConditionMet: (value, state) => {
364
- const prereqMet = state.unlockedAchievements.includes('prerequisite');
365
- return prereqMet && typeof value === 'number' && value >= 100;
366
- },
367
- achievementDetails: {
368
- achievementId: 'dependent',
369
- achievementTitle: 'Advanced Achievement',
370
- achievementDescription: 'Completed an advanced challenge',
371
- achievementIconKey: 'star'
372
- }
373
- }
374
- ]
252
+ clear() {
253
+ // Your implementation
254
+ }
255
+ }
256
+
257
+ // Use your custom storage
258
+ const App = () => {
259
+ return (
260
+ <AchievementProvider
261
+ achievements={achievements}
262
+ storage={new CustomStorage()}
263
+ >
264
+ <Game />
265
+ </AchievementProvider>
266
+ );
375
267
  };
376
268
  ```
377
269
 
378
- <h3 align="center">Time-Based Achievements</h3>
270
+ ## Styling
379
271
 
380
- You can create achievements based on specific times or dates:
272
+ You can customize the appearance of the achievement components:
381
273
 
382
- ```javascript
383
- const achievementConfig = {
384
- loginTime: [
385
- {
386
- isConditionMet: (value) => {
387
- if (!(value instanceof Date)) return false;
388
- const hour = value.getHours();
389
- return hour >= 22 || hour < 6;
390
- },
391
- achievementDetails: {
392
- achievementId: 'night_owl',
393
- achievementTitle: 'Night Owl',
394
- achievementDescription: 'Logged in during night hours',
395
- achievementIconKey: 'moon'
396
- }
397
- }
398
- ]
274
+ ```tsx
275
+ const App = () => {
276
+ return (
277
+ <AchievementProvider
278
+ achievements={achievements}
279
+ theme={{
280
+ colors: {
281
+ primary: '#ff0000',
282
+ background: '#f0f0f0'
283
+ },
284
+ position: 'top-right'
285
+ }}
286
+ >
287
+ <Game />
288
+ </AchievementProvider>
289
+ );
399
290
  };
400
291
  ```
401
292
 
402
- <h3 align="center">Progressive Achievements</h3>
293
+ ## API Reference
403
294
 
404
- You can create achievement chains that unlock in sequence:
295
+ ### AchievementProvider Props
405
296
 
406
- ```javascript
407
- const achievementConfig = {
408
- skillLevel: [
409
- {
410
- isConditionMet: (value) => typeof value === 'number' && value >= 1,
411
- achievementDetails: {
412
- achievementId: 'skill_novice',
413
- achievementTitle: 'Novice',
414
- achievementDescription: 'Reached skill level 1',
415
- achievementIconKey: 'bronze'
416
- }
417
- },
418
- {
419
- isConditionMet: (value) => typeof value === 'number' && value >= 5,
420
- achievementDetails: {
421
- achievementId: 'skill_master',
422
- achievementTitle: 'Master',
423
- achievementDescription: 'Reached skill level 5',
424
- achievementIconKey: 'gold'
425
- }
426
- }
427
- ]
428
- };
429
- ```
297
+ | Prop | Type | Description |
298
+ |------|------|-------------|
299
+ | achievements | AchievementConfig | Achievement configuration object |
300
+ | storage | 'local' \| 'memory' \| AchievementStorage | Storage implementation |
301
+ | theme | ThemeConfig | Custom theme configuration |
302
+ | onUnlock | (achievement: Achievement) => void | Callback when achievement is unlocked |
430
303
 
431
- <h2 align="center">💾 Saving and Loading Progress</h2>
432
-
433
- To persist user achievement progress across sessions or devices, you can save the metrics and previouslyAwardedAchievements from your Redux store:
434
-
435
- ```jsx
436
- import React from 'react';
437
- import { useAchievementState } from 'react-achievements/hooks/useAchievementState';
438
-
439
- const LogoutButtonWithSave = ({ onLogout }) => {
440
- const { metrics, previouslyAwardedAchievements } = useAchievementState();
441
-
442
- const handleLogoutAndSave = async () => {
443
- const achievementData = {
444
- metrics,
445
- previouslyAwardedAchievements,
446
- };
447
- try {
448
- await fetch('/api/save-achievements', {
449
- method: 'POST',
450
- headers: {
451
- 'Content-Type': 'application/json',
452
- },
453
- body: JSON.stringify(achievementData),
454
- });
455
- onLogout();
456
- } catch (error) {
457
- console.error('Failed to save achievements:', error);
458
- }
459
- };
460
-
461
- return <button onClick={handleLogoutAndSave}>Logout</button>;
462
- };
463
- ```
304
+ ### useAchievements Hook
305
+
306
+ Returns an object with:
307
+
308
+ - `update`: Function to update achievement metrics
309
+ - `achievements`: Object containing unlocked and locked achievements
310
+ - `reset`: Function to reset achievement storage
311
+
312
+ ## License
313
+
314
+ MIT