react-achievements 1.3.7 → 2.0.5
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/README.md +282 -146
- package/coverage/clover.xml +1 -1
- package/coverage/lcov-report/src/context/AchievementContext.tsx.html +6 -6
- package/coverage/lcov-report/src/context/index.html +1 -1
- package/coverage/lcov-report/src/index.ts.html +1 -1
- package/coverage/lcov.info +1 -1
- package/dist/assets/defaultIcons.d.ts +81 -0
- package/dist/components/AchievementModal.d.ts +3 -2
- package/dist/components/BadgesButton.d.ts +6 -1
- package/dist/components/BadgesModal.d.ts +3 -2
- package/dist/hooks/useAchievement.d.ts +8 -0
- package/dist/index.cjs.js +2100 -103
- package/dist/index.d.ts +5 -3
- package/dist/index.esm.js +2097 -120
- package/dist/providers/AchievementProvider.d.ts +11 -0
- package/dist/redux/achievementSlice.d.ts +25 -0
- package/dist/redux/notificationSlice.d.ts +7 -0
- package/dist/redux/store.d.ts +15 -0
- package/dist/types.d.ts +22 -13
- package/package.json +26 -18
- package/src/assets/defaultIcons.ts +100 -0
- package/src/components/AchievementModal.tsx +37 -8
- package/src/components/BadgesButton.tsx +33 -7
- package/src/components/BadgesModal.tsx +23 -9
- package/src/hooks/useAchievement.ts +20 -0
- package/src/index.ts +11 -7
- package/src/providers/AchievementProvider.tsx +185 -0
- package/src/redux/achievementSlice.ts +71 -0
- package/src/redux/notificationSlice.ts +26 -0
- package/src/redux/store.ts +20 -0
- package/src/types.ts +24 -13
- package/demo/src/stories/Button.jsx +0 -50
- package/demo/src/stories/Button.stories.js +0 -48
- package/demo/src/stories/Configure.mdx +0 -364
- package/demo/src/stories/Header.jsx +0 -59
- package/demo/src/stories/Header.stories.js +0 -28
- package/demo/src/stories/Page.jsx +0 -69
- package/demo/src/stories/Page.stories.js +0 -28
- package/demo/src/stories/assets/accessibility.png +0 -0
- package/demo/src/stories/assets/accessibility.svg +0 -1
- package/demo/src/stories/assets/addon-library.png +0 -0
- package/demo/src/stories/assets/assets.png +0 -0
- package/demo/src/stories/assets/avif-test-image.avif +0 -0
- package/demo/src/stories/assets/context.png +0 -0
- package/demo/src/stories/assets/discord.svg +0 -1
- package/demo/src/stories/assets/docs.png +0 -0
- package/demo/src/stories/assets/figma-plugin.png +0 -0
- package/demo/src/stories/assets/github.svg +0 -1
- package/demo/src/stories/assets/share.png +0 -0
- package/demo/src/stories/assets/styling.png +0 -0
- package/demo/src/stories/assets/testing.png +0 -0
- package/demo/src/stories/assets/theming.png +0 -0
- package/demo/src/stories/assets/tutorials.svg +0 -1
- package/demo/src/stories/assets/youtube.svg +0 -1
- package/demo/src/stories/button.css +0 -30
- package/demo/src/stories/header.css +0 -32
- package/demo/src/stories/page.css +0 -69
- package/dist/stories/Button.d.ts +0 -28
- package/dist/stories/Button.stories.d.ts +0 -23
- package/dist/stories/Header.d.ts +0 -13
- package/dist/stories/Header.stories.d.ts +0 -18
- package/dist/stories/Page.d.ts +0 -3
- package/dist/stories/Page.stories.d.ts +0 -12
- package/src/context/AchievementContext.tsx +0 -185
- package/src/stories/Button.stories.ts +0 -52
- package/src/stories/Button.tsx +0 -48
- package/src/stories/Configure.mdx +0 -364
- package/src/stories/Header.stories.ts +0 -33
- package/src/stories/Header.tsx +0 -56
- package/src/stories/Page.stories.ts +0 -32
- package/src/stories/Page.tsx +0 -73
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +0 -1
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +0 -1
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +0 -1
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +0 -1
- package/src/stories/assets/youtube.svg +0 -1
- package/src/stories/button.css +0 -30
- package/src/stories/header.css +0 -32
- package/src/stories/page.css +0 -69
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<h1 align="center">🏆 React-Achievements 🏆</h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
A flexible and customizable achievement system for React applications, perfect for adding gamification elements to your projects.
|
|
5
4
|
|
|
6
5
|

|
|
@@ -9,19 +8,18 @@ If you want to test the package, you can try it out here:
|
|
|
9
8
|
|
|
10
9
|
https://stackblitz.com/edit/vitejs-vite-sccdux
|
|
11
10
|
|
|
12
|
-
|
|
13
11
|
<h2 align="center">🚀 Installation</h2>
|
|
14
12
|
|
|
15
13
|
Install `react-achievements` using npm or yarn:
|
|
16
14
|
|
|
17
15
|
```bash
|
|
18
|
-
npm install react-achievements
|
|
16
|
+
npm install react react-dom @reduxjs/toolkit react-achievements
|
|
19
17
|
```
|
|
20
18
|
|
|
21
19
|
or
|
|
22
20
|
|
|
23
21
|
```bash
|
|
24
|
-
yarn add react-achievements
|
|
22
|
+
yarn add react react-dom @reduxjs/toolkit react-achievements
|
|
25
23
|
```
|
|
26
24
|
|
|
27
25
|
<h2 align="center">🎮 Usage</h2>
|
|
@@ -34,89 +32,129 @@ First, wrap your app or a part of your app with the AchievementProvider:
|
|
|
34
32
|
|
|
35
33
|
```jsx
|
|
36
34
|
import React from 'react';
|
|
35
|
+
import { Provider } from 'react-redux';
|
|
36
|
+
import store from './store'; // Import the Redux store you will create
|
|
37
37
|
import { AchievementProvider } from 'react-achievements';
|
|
38
|
-
import
|
|
39
|
-
import
|
|
38
|
+
import Game from './Game'; // Your main game component
|
|
39
|
+
import achievementConfig from './achievementConfig'; // Your achievement configuration
|
|
40
40
|
|
|
41
41
|
const initialState = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
level: 1,
|
|
43
|
+
experience: 0,
|
|
44
|
+
monstersDefeated: 0,
|
|
45
|
+
questsCompleted: 0,
|
|
46
|
+
// Add any other initial metrics here
|
|
46
47
|
};
|
|
47
48
|
|
|
48
49
|
function App() {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
return (
|
|
51
|
+
<Provider store={store}>
|
|
52
|
+
<AchievementProvider
|
|
53
|
+
config={achievementConfig} // Required: your achievement configuration
|
|
54
|
+
initialState={initialState} // Required: initial game metrics. 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
|
+
);
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
export default App;
|
|
61
66
|
```
|
|
62
67
|
|
|
68
|
+
<h3 align="center">🛠 Set up the Store</h3>
|
|
69
|
+
|
|
70
|
+
You need to create a store for you state
|
|
71
|
+
|
|
72
|
+
```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';
|
|
79
|
+
|
|
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;
|
|
90
|
+
|
|
91
|
+
export default store;
|
|
92
|
+
```
|
|
93
|
+
|
|
63
94
|
<h3 align="center">📝 Create an achievement configuration</h3>
|
|
64
95
|
|
|
65
96
|
Create a file (e.g., achievementConfig.js) to define your achievements:
|
|
66
97
|
|
|
67
98
|
```javascript
|
|
99
|
+
// achievementConfig.js
|
|
68
100
|
import levelUpIcon from './icons/level-up.png';
|
|
69
101
|
import monsterSlayerIcon from './icons/monster-slayer.png';
|
|
70
102
|
import questMasterIcon from './icons/quest-master.png';
|
|
71
103
|
|
|
72
104
|
const achievementConfig = {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
+
],
|
|
115
147
|
};
|
|
116
148
|
|
|
117
149
|
export default achievementConfig;
|
|
118
150
|
```
|
|
119
151
|
|
|
152
|
+
Key points:
|
|
153
|
+
|
|
154
|
+
- `isConditionMet`: A function that determines if an achievement should be unlocked.
|
|
155
|
+
- `achievementDetails`: An object containing the details of the achievement.
|
|
156
|
+
- `achievementIconKey`: A string used to reference the icon in the `AchievementProvider`'s icons prop. A list of icons are already provided by the library.
|
|
157
|
+
|
|
120
158
|
<h3 align="center">🎣 Use the useAchievement hook</h3>
|
|
121
159
|
|
|
122
160
|
In your game components, use the useAchievement hook to update metrics and trigger achievement checks:
|
|
@@ -125,66 +163,58 @@ import React, { useState } from 'react';
|
|
|
125
163
|
import { useAchievement } from 'react-achievements';
|
|
126
164
|
|
|
127
165
|
function Game() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<button onClick={completeQuest}>Complete Quest</button>
|
|
181
|
-
</>
|
|
182
|
-
) : (
|
|
183
|
-
<button onClick={startQuest}>Start a New Quest</button>
|
|
184
|
-
)}
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
);
|
|
166
|
+
const { setMetrics, metrics } = useAchievement();
|
|
167
|
+
const [currentQuest, setCurrentQuest] = useState(null);
|
|
168
|
+
|
|
169
|
+
const defeatMonster = () => {
|
|
170
|
+
setMetrics((prevMetrics) => ({
|
|
171
|
+
...prevMetrics,
|
|
172
|
+
monstersDefeated: prevMetrics.monstersDefeated + 1,
|
|
173
|
+
experience: prevMetrics.experience + 10,
|
|
174
|
+
level: Math.floor((prevMetrics.experience + 10) / 100) + 1, // Calculate new level
|
|
175
|
+
}));
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const completeQuest = () => {
|
|
179
|
+
setMetrics((prevMetrics) => ({
|
|
180
|
+
...prevMetrics,
|
|
181
|
+
questsCompleted: prevMetrics.questsCompleted + 1,
|
|
182
|
+
experience: prevMetrics.experience + 50,
|
|
183
|
+
level: Math.floor((prevMetrics.experience + 50) / 100) + 1, // Calculate new level
|
|
184
|
+
}));
|
|
185
|
+
setCurrentQuest(null);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const startQuest = () => {
|
|
189
|
+
setCurrentQuest("Defeat the Dragon");
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<div>
|
|
194
|
+
<h1>My RPG Game</h1>
|
|
195
|
+
<p>Level: {metrics.level}</p>
|
|
196
|
+
<p>Experience: {metrics.experience}</p>
|
|
197
|
+
<p>Monsters Defeated: {metrics.monstersDefeated}</p>
|
|
198
|
+
<p>Quests Completed: {metrics.questsCompleted}</p>
|
|
199
|
+
|
|
200
|
+
<div>
|
|
201
|
+
<h2>Battle Arena</h2>
|
|
202
|
+
<button onClick={defeatMonster}>Fight a Monster</button>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<div>
|
|
206
|
+
<h2>Quest Board</h2>
|
|
207
|
+
{currentQuest ? (
|
|
208
|
+
<>
|
|
209
|
+
<p>Current Quest: {currentQuest}</p>
|
|
210
|
+
<button onClick={completeQuest}>Complete Quest</button>
|
|
211
|
+
</>
|
|
212
|
+
) : (
|
|
213
|
+
<button onClick={startQuest}>Start a New Quest</button>
|
|
214
|
+
)}
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
);
|
|
188
218
|
}
|
|
189
219
|
|
|
190
220
|
export default Game;
|
|
@@ -193,12 +223,15 @@ export default Game;
|
|
|
193
223
|
<h2 align="center">✨ Features</h2>
|
|
194
224
|
|
|
195
225
|
- Flexible Achievement System: Define custom metrics and achievement conditions for your game or app.
|
|
226
|
+
- Built with TypeScript: Provides strong typing and improved developer experience.
|
|
227
|
+
- Redux-Powered State Management: Leverages Redux for predictable and scalable state management of achievements and metrics.
|
|
196
228
|
- Automatic Achievement Tracking: Achievements are automatically checked and unlocked when metrics change.
|
|
197
229
|
- Achievement Notifications: A modal pops up when an achievement is unlocked, perfect for rewarding players.
|
|
198
230
|
- Persistent Achievements: Unlocked achievements and metrics are stored in local storage, allowing players to keep their progress.
|
|
199
231
|
- Achievement Gallery: Players can view all their unlocked achievements, encouraging completionism.
|
|
200
232
|
- Confetti Effect: A celebratory confetti effect is displayed when an achievement is unlocked, adding to the excitement.
|
|
201
|
-
- Local Storage: Achievements are stored locally on the device
|
|
233
|
+
- Local Storage: Achievements are stored locally on the device.
|
|
234
|
+
- **Programmatic Reset:** Includes a `resetStorage` function accessible via the `useAchievementContext` hook to easily reset all achievement data.
|
|
202
235
|
|
|
203
236
|
<h2 align="center">🔧 API</h2>
|
|
204
237
|
|
|
@@ -216,10 +249,9 @@ export default Game;
|
|
|
216
249
|
|
|
217
250
|
#### Returns an object with:
|
|
218
251
|
|
|
219
|
-
- `
|
|
220
|
-
- `
|
|
221
|
-
- `
|
|
222
|
-
- `showBadgesModal`: Function to manually show the badges modal.
|
|
252
|
+
- `updateMetrics`: Function to update the metrics. Accepts either a new metrics object or a function that receives the previous metrics and returns the new metrics.
|
|
253
|
+
- `unlockedAchievements`: Array of unlocked achievement IDs. (Note: Access the actual Redux state using `useSelector`).
|
|
254
|
+
- `resetStorage`: Function to clear all achievement data from local storage and reset the Redux state.
|
|
223
255
|
|
|
224
256
|
<h2 align="center">🎨 Customization</h2>
|
|
225
257
|
|
|
@@ -228,25 +260,13 @@ React-Achievements allows for extensive customization of its appearance. You can
|
|
|
228
260
|
```jsx
|
|
229
261
|
const customStyles = {
|
|
230
262
|
achievementModal: {
|
|
231
|
-
|
|
232
|
-
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
233
|
-
},
|
|
234
|
-
content: {
|
|
235
|
-
backgroundColor: '#2a2a2a',
|
|
236
|
-
color: '#ffffff',
|
|
237
|
-
},
|
|
238
|
-
title: {
|
|
239
|
-
color: '#ffd700',
|
|
240
|
-
},
|
|
241
|
-
button: {
|
|
242
|
-
backgroundColor: '#4CAF50',
|
|
243
|
-
},
|
|
263
|
+
// Custom styles for the achievement modal below
|
|
244
264
|
},
|
|
245
265
|
badgesModal: {
|
|
246
|
-
// Custom styles for the badges modal
|
|
266
|
+
// Custom styles for the badges modal below
|
|
247
267
|
},
|
|
248
268
|
badgesButton: {
|
|
249
|
-
// Custom styles for the badges button
|
|
269
|
+
// Custom styles for the badges button below
|
|
250
270
|
},
|
|
251
271
|
};
|
|
252
272
|
|
|
@@ -263,7 +283,7 @@ function App() {
|
|
|
263
283
|
}
|
|
264
284
|
```
|
|
265
285
|
|
|
266
|
-
### achievementModal
|
|
286
|
+
### achievementModal (to be passed in as a customStyle above)
|
|
267
287
|
|
|
268
288
|
Customizes the modal that appears when an achievement is unlocked.
|
|
269
289
|
|
|
@@ -311,7 +331,7 @@ achievementModal: {
|
|
|
311
331
|
}
|
|
312
332
|
```
|
|
313
333
|
|
|
314
|
-
### badgesModal
|
|
334
|
+
### badgesModal (to be passed in as a customStyle above)
|
|
315
335
|
|
|
316
336
|
```
|
|
317
337
|
badgesModal: {
|
|
@@ -352,7 +372,7 @@ badgesModal: {
|
|
|
352
372
|
```
|
|
353
373
|
|
|
354
374
|
|
|
355
|
-
### badgesButton
|
|
375
|
+
### badgesButton (to be passed in as a customStyle above)
|
|
356
376
|
|
|
357
377
|
```
|
|
358
378
|
badgesButton: {
|
|
@@ -372,10 +392,126 @@ badgesButton: {
|
|
|
372
392
|
|
|
373
393
|
<h2 align="center">Resetting React Achievements</h2>
|
|
374
394
|
|
|
375
|
-
The achievements
|
|
395
|
+
The achievements and metrics are managed by Redux and persisted in local storage. You have two primary ways to reset the achievement system:
|
|
396
|
+
|
|
397
|
+
1. **Programmatic Reset:** Use the `resetStorage` function provided by the `useAchievementContext` hook within your components:
|
|
376
398
|
|
|
377
|
-
|
|
399
|
+
```jsx
|
|
400
|
+
import React from 'react';
|
|
401
|
+
import { useAchievementContext } from 'react-achievements';
|
|
402
|
+
|
|
403
|
+
function ResetButton() {
|
|
404
|
+
const { resetStorage } = useAchievementContext();
|
|
405
|
+
|
|
406
|
+
const handleReset = () => {
|
|
407
|
+
resetStorage();
|
|
408
|
+
console.log('Achievements and progress reset!');
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
return <button onClick={handleReset}>Reset Achievements</button>;
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
<h2 align="center">🏆Available Icons🏆</h2>
|
|
378
416
|
|
|
417
|
+
```
|
|
418
|
+
// General Progress & Milestones
|
|
419
|
+
levelUp: '🏆',
|
|
420
|
+
questComplete: '📜',
|
|
421
|
+
monsterDefeated: '⚔️',
|
|
422
|
+
itemCollected: '📦',
|
|
423
|
+
challengeCompleted: '🏁',
|
|
424
|
+
milestoneReached: '🏅',
|
|
425
|
+
firstStep: '👣',
|
|
426
|
+
newBeginnings: '🌱',
|
|
427
|
+
breakthrough: '💡',
|
|
428
|
+
growth: '📈',
|
|
429
|
+
|
|
430
|
+
// Social & Engagement
|
|
431
|
+
shared: '🔗',
|
|
432
|
+
liked: '❤️',
|
|
433
|
+
commented: '💬',
|
|
434
|
+
followed: '👥',
|
|
435
|
+
invited: '🤝',
|
|
436
|
+
communityMember: '🏘️',
|
|
437
|
+
supporter: '🌟',
|
|
438
|
+
connected: '🌐',
|
|
439
|
+
participant: '🙋',
|
|
440
|
+
influencer: '📣',
|
|
441
|
+
|
|
442
|
+
// Time & Activity
|
|
443
|
+
activeDay: '☀️',
|
|
444
|
+
activeWeek: '📅',
|
|
445
|
+
activeMonth: '🗓️',
|
|
446
|
+
earlyBird: '⏰',
|
|
447
|
+
nightOwl: '🌙',
|
|
448
|
+
streak: '🔥',
|
|
449
|
+
dedicated: '⏳',
|
|
450
|
+
punctual: '⏱️',
|
|
451
|
+
consistent: '🔄',
|
|
452
|
+
marathon: '🏃',
|
|
453
|
+
|
|
454
|
+
// Creativity & Skill
|
|
455
|
+
artist: '🎨',
|
|
456
|
+
writer: '✍️',
|
|
457
|
+
innovator: '🔬',
|
|
458
|
+
creator: '🛠️',
|
|
459
|
+
expert: '🎓',
|
|
460
|
+
master: '👑',
|
|
461
|
+
pioneer: '🚀',
|
|
462
|
+
performer: '🎭',
|
|
463
|
+
thinker: '🧠',
|
|
464
|
+
explorer: '🗺️',
|
|
465
|
+
|
|
466
|
+
// Achievement Types
|
|
467
|
+
bronze: '🥉',
|
|
468
|
+
silver: '🥈',
|
|
469
|
+
gold: '🥇',
|
|
470
|
+
diamond: '💎',
|
|
471
|
+
legendary: '✨',
|
|
472
|
+
epic: '💥',
|
|
473
|
+
rare: '🔮',
|
|
474
|
+
common: '🔘',
|
|
475
|
+
special: '🎁',
|
|
476
|
+
hidden: '❓',
|
|
477
|
+
|
|
478
|
+
// Numbers & Counters
|
|
479
|
+
one: '1️⃣',
|
|
480
|
+
ten: '🔟',
|
|
481
|
+
hundred: '💯',
|
|
482
|
+
thousand: '🔢',
|
|
483
|
+
|
|
484
|
+
// Actions & Interactions
|
|
485
|
+
clicked: '🖱️',
|
|
486
|
+
used: '🔑',
|
|
487
|
+
found: '🔍',
|
|
488
|
+
built: '🧱',
|
|
489
|
+
solved: '🧩',
|
|
490
|
+
discovered: '🔭',
|
|
491
|
+
unlocked: '🔓',
|
|
492
|
+
upgraded: '⬆️',
|
|
493
|
+
repaired: '🔧',
|
|
494
|
+
defended: '🛡️',
|
|
495
|
+
|
|
496
|
+
// Placeholders
|
|
497
|
+
default: '⭐', // A fallback icon
|
|
498
|
+
loading: '⏳',
|
|
499
|
+
error: '⚠️',
|
|
500
|
+
success: '✅',
|
|
501
|
+
failure: '❌',
|
|
502
|
+
|
|
503
|
+
// Miscellaneous
|
|
504
|
+
trophy: '🏆',
|
|
505
|
+
star: '⭐',
|
|
506
|
+
flag: '🚩',
|
|
507
|
+
puzzle: '🧩',
|
|
508
|
+
gem: '💎',
|
|
509
|
+
crown: '👑',
|
|
510
|
+
medal: '🏅',
|
|
511
|
+
ribbon: '🎗️',
|
|
512
|
+
badge: '🎖️',
|
|
513
|
+
shield: '🛡️',
|
|
514
|
+
```
|
|
379
515
|
|
|
380
516
|
<h2 align="center">📄 License</h2>
|
|
381
517
|
MIT
|
package/coverage/clover.xml
CHANGED
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
</package>
|
|
65
65
|
<package name="src.context">
|
|
66
66
|
<metrics statements="59" coveredstatements="0" conditionals="15" coveredconditionals="0" methods="21" coveredmethods="0"/>
|
|
67
|
-
<file name="
|
|
67
|
+
<file name="AchievementProvider.tsx" path="/Users/daves-mbp/Projects/react-achievements/src/context/AchievementProvider.tsx">
|
|
68
68
|
<metrics statements="59" coveredstatements="0" conditionals="15" coveredconditionals="0" methods="21" coveredmethods="0"/>
|
|
69
69
|
<line num="1" count="0" type="stmt"/>
|
|
70
70
|
<line num="3" count="0" type="stmt"/>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<html lang="en">
|
|
4
4
|
|
|
5
5
|
<head>
|
|
6
|
-
<title>Code coverage report for src/context/
|
|
6
|
+
<title>Code coverage report for src/context/AchievementProvider.tsx</title>
|
|
7
7
|
<meta charset="utf-8" />
|
|
8
8
|
<link rel="stylesheet" href="../../prettify.css" />
|
|
9
9
|
<link rel="stylesheet" href="../../base.css" />
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
<body>
|
|
20
20
|
<div class='wrapper'>
|
|
21
21
|
<div class='pad1'>
|
|
22
|
-
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/context</a>
|
|
22
|
+
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/context</a> AchievementProvider.tsx</h1>
|
|
23
23
|
<div class='clearfix'>
|
|
24
24
|
|
|
25
25
|
<div class='fl pad1y space-right2'>
|
|
@@ -366,7 +366,7 @@ interface AchievementProviderProps {
|
|
|
366
366
|
badgesButtonPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
const
|
|
369
|
+
const AchievementProvider = <span class="cstat-no" title="statement not covered" >createContext<AchievementContextProps | undefined>(undefined);</span>
|
|
370
370
|
|
|
371
371
|
export const <span class="cstat-no" title="statement not covered" >AchievementProvider: React.FC<AchievementProviderProps> = <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >(</span>{</span></span>
|
|
372
372
|
children,
|
|
@@ -456,7 +456,7 @@ export const <span class="cstat-no" title="statement not covered" >AchievementPr
|
|
|
456
456
|
};
|
|
457
457
|
|
|
458
458
|
<span class="cstat-no" title="statement not covered" > return (</span>
|
|
459
|
-
<
|
|
459
|
+
<AchievementProvider.Provider value={contextValue}>
|
|
460
460
|
{children}
|
|
461
461
|
<AchievementModal
|
|
462
462
|
show={!!newAchievement}
|
|
@@ -473,12 +473,12 @@ export const <span class="cstat-no" title="statement not covered" >AchievementPr
|
|
|
473
473
|
/>
|
|
474
474
|
<BadgesButton onClick={showBadgesModal} position={badgesButtonPosition} />
|
|
475
475
|
<ConfettiWrapper show={showConfetti} />
|
|
476
|
-
</
|
|
476
|
+
</AchievementProvider.Provider>
|
|
477
477
|
);
|
|
478
478
|
};
|
|
479
479
|
|
|
480
480
|
export const <span class="cstat-no" title="statement not covered" >useAchievement = <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >(</span>) =</span>> {</span>
|
|
481
|
-
const context = <span class="cstat-no" title="statement not covered" >useContext(
|
|
481
|
+
const context = <span class="cstat-no" title="statement not covered" >useContext(AchievementProvider);</span>
|
|
482
482
|
<span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="if path not taken" >I</span>if (context === undefined) {</span>
|
|
483
483
|
<span class="cstat-no" title="statement not covered" > throw new Error('useAchievement must be used within an AchievementProvider');</span>
|
|
484
484
|
}
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
</tr>
|
|
80
80
|
</thead>
|
|
81
81
|
<tbody><tr>
|
|
82
|
-
<td class="file low" data-value="
|
|
82
|
+
<td class="file low" data-value="AchievementProvider.tsx"><a href="AchievementProvider.tsx.html">AchievementProvider.tsx</a></td>
|
|
83
83
|
<td data-value="0" class="pic low">
|
|
84
84
|
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
|
|
85
85
|
</td>
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
<span class="cline-any cline-neutral"> </span>
|
|
88
88
|
<span class="cline-any cline-neutral"> </span>
|
|
89
89
|
<span class="cline-any cline-no"> </span>
|
|
90
|
-
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" >import { A</span>chievementProvider, useAchievement } from './context/
|
|
90
|
+
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" >import { A</span>chievementProvider, useAchievement } from './context/AchievementProvider';
|
|
91
91
|
import { Metrics, AchievementConfig, AchievementData, AchievementCondition } from './types';
|
|
92
92
|
<span class="cstat-no" title="statement not covered" >import C</span>onfettiWrapper from './components/ConfettiWrapper';
|
|
93
93
|
|