react-achievements 1.0.0 → 1.0.2

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.
@@ -3,6 +3,7 @@ interface AchievementProps {
3
3
  metric: number;
4
4
  threshold: number;
5
5
  onAchieve: () => void;
6
+ message: string;
6
7
  children: React.ReactNode;
7
8
  }
8
9
  declare const Achievement: React.FC<AchievementProps>;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface AchievementModalProps {
3
+ show: boolean;
4
+ message: string;
5
+ onClose: () => void;
6
+ }
7
+ declare const AchievementModal: React.FC<AchievementModalProps>;
8
+ export default AchievementModal;
@@ -6,6 +6,8 @@ interface AchievementContextProps {
6
6
  setMetric: (value: number) => void;
7
7
  badges: BadgeConfig[];
8
8
  levels: LevelConfig[];
9
+ achievedLevels: number[];
10
+ handleAchieve: (level: number, message: string) => void;
9
11
  }
10
12
  declare const AchievementProvider: React.FC<{
11
13
  children: ReactNode;
package/dist/index.cjs.js CHANGED
@@ -115,6 +115,37 @@ const ConfettiWrapper = ({ show }) => {
115
115
  return show ? React.createElement(Confetti, { width: width, height: height }) : null;
116
116
  };
117
117
 
118
+ const AchievementModal = ({ show, message, onClose }) => {
119
+ if (!show)
120
+ return null;
121
+ const modalStyle = {
122
+ position: 'fixed',
123
+ top: '50%',
124
+ left: '50%',
125
+ transform: 'translate(-50%, -50%)',
126
+ backgroundColor: '#fff',
127
+ padding: '20px',
128
+ borderRadius: '8px',
129
+ boxShadow: '0 0 10px rgba(0,0,0,0.1)',
130
+ zIndex: 1000,
131
+ };
132
+ const overlayStyle = {
133
+ position: 'fixed',
134
+ top: 0,
135
+ left: 0,
136
+ right: 0,
137
+ bottom: 0,
138
+ backgroundColor: 'rgba(0,0,0,0.5)',
139
+ zIndex: 999,
140
+ };
141
+ return (React.createElement(React.Fragment, null,
142
+ React.createElement("div", { style: overlayStyle, onClick: onClose }),
143
+ React.createElement("div", { style: modalStyle },
144
+ React.createElement("h2", null, "Achievement Unlocked!"),
145
+ React.createElement("p", null, message),
146
+ React.createElement("button", { onClick: onClose }, "Okay"))));
147
+ };
148
+
118
149
  const Badge = ({ icon, title, description, position = 'top-right' }) => {
119
150
  const badgeStyle = {
120
151
  position: 'fixed',
@@ -140,13 +171,26 @@ const AchievementProvider = ({ children }) => {
140
171
  const [metric, setMetric] = React.useState(0);
141
172
  const [achievedLevels, setAchievedLevels] = React.useState([]);
142
173
  const [showConfetti, setShowConfetti] = React.useState(false);
143
- return (React.createElement(AchievementContext.Provider, { value: { metric, setMetric, badges: defaultBadges, levels } },
174
+ const [modalMessage, setModalMessage] = React.useState('');
175
+ const handleAchieve = (level, message) => {
176
+ if (!achievedLevels.includes(level)) {
177
+ setAchievedLevels([...achievedLevels, level]);
178
+ setShowConfetti(true);
179
+ setModalMessage(message);
180
+ }
181
+ };
182
+ const handleCloseModal = () => {
183
+ setShowConfetti(false);
184
+ setModalMessage('');
185
+ };
186
+ return (React.createElement(AchievementContext.Provider, { value: { metric, setMetric, badges: defaultBadges, levels, achievedLevels, handleAchieve } },
144
187
  children,
145
188
  levels.map(levelConfig => {
146
189
  var _a, _b, _c;
147
190
  return achievedLevels.includes(levelConfig.level) ? (React.createElement(Badge, { key: levelConfig.level, icon: ((_a = defaultBadges.find(badge => badge.id === levelConfig.badgeId)) === null || _a === void 0 ? void 0 : _a.icon) || '', title: ((_b = defaultBadges.find(badge => badge.id === levelConfig.badgeId)) === null || _b === void 0 ? void 0 : _b.title) || '', description: ((_c = defaultBadges.find(badge => badge.id === levelConfig.badgeId)) === null || _c === void 0 ? void 0 : _c.description) || '' })) : null;
148
191
  }),
149
- React.createElement(ConfettiWrapper, { show: showConfetti })));
192
+ React.createElement(ConfettiWrapper, { show: showConfetti }),
193
+ React.createElement(AchievementModal, { show: !!modalMessage, message: modalMessage, onClose: handleCloseModal })));
150
194
  };
151
195
  const useAchievement = () => {
152
196
  const context = React.useContext(AchievementContext);
@@ -156,12 +200,18 @@ const useAchievement = () => {
156
200
  return context;
157
201
  };
158
202
 
159
- const Achievement = ({ metric, threshold, onAchieve, children }) => {
203
+ const Achievement = ({ metric, threshold, onAchieve, message, children }) => {
204
+ const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
160
205
  React.useEffect(() => {
161
- if (metric >= threshold) {
206
+ if (metric >= threshold && !achievedLevels.includes(threshold)) {
162
207
  onAchieve();
208
+ const levelConfig = levels.find(level => level.threshold === threshold);
209
+ if (levelConfig) {
210
+ setMetric(metric);
211
+ handleAchieve(levelConfig.level, message);
212
+ }
163
213
  }
164
- }, [metric, threshold, onAchieve]);
214
+ }, [metric, threshold, onAchieve, setMetric, achievedLevels, levels, message, handleAchieve]);
165
215
  return React.createElement("div", null, children);
166
216
  };
167
217
 
package/dist/index.esm.js CHANGED
@@ -113,6 +113,37 @@ const ConfettiWrapper = ({ show }) => {
113
113
  return show ? React.createElement(Confetti, { width: width, height: height }) : null;
114
114
  };
115
115
 
116
+ const AchievementModal = ({ show, message, onClose }) => {
117
+ if (!show)
118
+ return null;
119
+ const modalStyle = {
120
+ position: 'fixed',
121
+ top: '50%',
122
+ left: '50%',
123
+ transform: 'translate(-50%, -50%)',
124
+ backgroundColor: '#fff',
125
+ padding: '20px',
126
+ borderRadius: '8px',
127
+ boxShadow: '0 0 10px rgba(0,0,0,0.1)',
128
+ zIndex: 1000,
129
+ };
130
+ const overlayStyle = {
131
+ position: 'fixed',
132
+ top: 0,
133
+ left: 0,
134
+ right: 0,
135
+ bottom: 0,
136
+ backgroundColor: 'rgba(0,0,0,0.5)',
137
+ zIndex: 999,
138
+ };
139
+ return (React.createElement(React.Fragment, null,
140
+ React.createElement("div", { style: overlayStyle, onClick: onClose }),
141
+ React.createElement("div", { style: modalStyle },
142
+ React.createElement("h2", null, "Achievement Unlocked!"),
143
+ React.createElement("p", null, message),
144
+ React.createElement("button", { onClick: onClose }, "Okay"))));
145
+ };
146
+
116
147
  const Badge = ({ icon, title, description, position = 'top-right' }) => {
117
148
  const badgeStyle = {
118
149
  position: 'fixed',
@@ -138,13 +169,26 @@ const AchievementProvider = ({ children }) => {
138
169
  const [metric, setMetric] = useState(0);
139
170
  const [achievedLevels, setAchievedLevels] = useState([]);
140
171
  const [showConfetti, setShowConfetti] = useState(false);
141
- return (React.createElement(AchievementContext.Provider, { value: { metric, setMetric, badges: defaultBadges, levels } },
172
+ const [modalMessage, setModalMessage] = useState('');
173
+ const handleAchieve = (level, message) => {
174
+ if (!achievedLevels.includes(level)) {
175
+ setAchievedLevels([...achievedLevels, level]);
176
+ setShowConfetti(true);
177
+ setModalMessage(message);
178
+ }
179
+ };
180
+ const handleCloseModal = () => {
181
+ setShowConfetti(false);
182
+ setModalMessage('');
183
+ };
184
+ return (React.createElement(AchievementContext.Provider, { value: { metric, setMetric, badges: defaultBadges, levels, achievedLevels, handleAchieve } },
142
185
  children,
143
186
  levels.map(levelConfig => {
144
187
  var _a, _b, _c;
145
188
  return achievedLevels.includes(levelConfig.level) ? (React.createElement(Badge, { key: levelConfig.level, icon: ((_a = defaultBadges.find(badge => badge.id === levelConfig.badgeId)) === null || _a === void 0 ? void 0 : _a.icon) || '', title: ((_b = defaultBadges.find(badge => badge.id === levelConfig.badgeId)) === null || _b === void 0 ? void 0 : _b.title) || '', description: ((_c = defaultBadges.find(badge => badge.id === levelConfig.badgeId)) === null || _c === void 0 ? void 0 : _c.description) || '' })) : null;
146
189
  }),
147
- React.createElement(ConfettiWrapper, { show: showConfetti })));
190
+ React.createElement(ConfettiWrapper, { show: showConfetti }),
191
+ React.createElement(AchievementModal, { show: !!modalMessage, message: modalMessage, onClose: handleCloseModal })));
148
192
  };
149
193
  const useAchievement = () => {
150
194
  const context = useContext(AchievementContext);
@@ -154,12 +198,18 @@ const useAchievement = () => {
154
198
  return context;
155
199
  };
156
200
 
157
- const Achievement = ({ metric, threshold, onAchieve, children }) => {
201
+ const Achievement = ({ metric, threshold, onAchieve, message, children }) => {
202
+ const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
158
203
  React.useEffect(() => {
159
- if (metric >= threshold) {
204
+ if (metric >= threshold && !achievedLevels.includes(threshold)) {
160
205
  onAchieve();
206
+ const levelConfig = levels.find(level => level.threshold === threshold);
207
+ if (levelConfig) {
208
+ setMetric(metric);
209
+ handleAchieve(levelConfig.level, message);
210
+ }
161
211
  }
162
- }, [metric, threshold, onAchieve]);
212
+ }, [metric, threshold, onAchieve, setMetric, achievedLevels, levels, message, handleAchieve]);
163
213
  return React.createElement("div", null, children);
164
214
  };
165
215
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-achievements",
3
- "version": "1.0.0",
4
- "description": "This package allows users to transpose a React game engine over their React apps",
3
+ "version": "1.0.2",
4
+ "description": "This package allows users to transpose a React achievements engine over their React apps",
5
5
  "keywords": [
6
6
  "react",
7
7
  "badge",
@@ -1,18 +1,27 @@
1
1
  import React from 'react';
2
+ import { useAchievement } from '../context/AchievementContext';
2
3
 
3
4
  interface AchievementProps {
4
5
  metric: number;
5
6
  threshold: number;
6
7
  onAchieve: () => void;
8
+ message: string;
7
9
  children: React.ReactNode;
8
10
  }
9
11
 
10
- const Achievement: React.FC<AchievementProps> = ({ metric, threshold, onAchieve, children }) => {
12
+ const Achievement: React.FC<AchievementProps> = ({ metric, threshold, onAchieve, message, children }) => {
13
+ const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
14
+
11
15
  React.useEffect(() => {
12
- if (metric >= threshold) {
16
+ if (metric >= threshold && !achievedLevels.includes(threshold)) {
13
17
  onAchieve();
18
+ const levelConfig = levels.find(level => level.threshold === threshold);
19
+ if (levelConfig) {
20
+ setMetric(metric);
21
+ handleAchieve(levelConfig.level, message);
22
+ }
14
23
  }
15
- }, [metric, threshold, onAchieve]);
24
+ }, [metric, threshold, onAchieve, setMetric, achievedLevels, levels, message, handleAchieve]);
16
25
 
17
26
  return <div>{children}</div>;
18
27
  };
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+
3
+ interface AchievementModalProps {
4
+ show: boolean;
5
+ message: string;
6
+ onClose: () => void;
7
+ }
8
+
9
+ const AchievementModal: React.FC<AchievementModalProps> = ({ show, message, onClose }) => {
10
+ if (!show) return null;
11
+
12
+ const modalStyle: React.CSSProperties = {
13
+ position: 'fixed',
14
+ top: '50%',
15
+ left: '50%',
16
+ transform: 'translate(-50%, -50%)',
17
+ backgroundColor: '#fff',
18
+ padding: '20px',
19
+ borderRadius: '8px',
20
+ boxShadow: '0 0 10px rgba(0,0,0,0.1)',
21
+ zIndex: 1000,
22
+ };
23
+
24
+ const overlayStyle: React.CSSProperties = {
25
+ position: 'fixed',
26
+ top: 0,
27
+ left: 0,
28
+ right: 0,
29
+ bottom: 0,
30
+ backgroundColor: 'rgba(0,0,0,0.5)',
31
+ zIndex: 999,
32
+ };
33
+
34
+ return (
35
+ <>
36
+ <div style={overlayStyle} onClick={onClose} />
37
+ <div style={modalStyle}>
38
+ <h2>Achievement Unlocked!</h2>
39
+ <p>{message}</p>
40
+ <button onClick={onClose}>Okay</button>
41
+ </div>
42
+ </>
43
+ );
44
+ };
45
+
46
+ export default AchievementModal;
@@ -2,6 +2,7 @@ import React, { createContext, useContext, useState, ReactNode } from 'react';
2
2
  import { defaultBadges, BadgeConfig } from '../badges';
3
3
  import { levels, LevelConfig } from '../levels';
4
4
  import ConfettiWrapper from '../components/ConfettiWrapper';
5
+ import AchievementModal from '../components/AchievementModal';
5
6
  import Badge from '../components/Badge';
6
7
 
7
8
  interface AchievementContextProps {
@@ -9,6 +10,8 @@ interface AchievementContextProps {
9
10
  setMetric: (value: number) => void;
10
11
  badges: BadgeConfig[];
11
12
  levels: LevelConfig[];
13
+ achievedLevels: number[];
14
+ handleAchieve: (level: number, message: string) => void;
12
15
  }
13
16
 
14
17
  const AchievementContext = createContext<AchievementContextProps | undefined>(undefined);
@@ -17,17 +20,23 @@ const AchievementProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
17
20
  const [metric, setMetric] = useState(0);
18
21
  const [achievedLevels, setAchievedLevels] = useState<number[]>([]);
19
22
  const [showConfetti, setShowConfetti] = useState(false);
23
+ const [modalMessage, setModalMessage] = useState('');
20
24
 
21
- const handleAchieve = (level: number) => {
25
+ const handleAchieve = (level: number, message: string) => {
22
26
  if (!achievedLevels.includes(level)) {
23
27
  setAchievedLevels([...achievedLevels, level]);
24
28
  setShowConfetti(true);
25
- setTimeout(() => setShowConfetti(false), 5000); // Confetti for 5 seconds
29
+ setModalMessage(message);
26
30
  }
27
31
  };
28
32
 
33
+ const handleCloseModal = () => {
34
+ setShowConfetti(false);
35
+ setModalMessage('');
36
+ };
37
+
29
38
  return (
30
- <AchievementContext.Provider value={{ metric, setMetric, badges: defaultBadges, levels }}>
39
+ <AchievementContext.Provider value={{ metric, setMetric, badges: defaultBadges, levels, achievedLevels, handleAchieve }}>
31
40
  {children}
32
41
  {levels.map(levelConfig =>
33
42
  achievedLevels.includes(levelConfig.level) ? (
@@ -40,6 +49,7 @@ const AchievementProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
40
49
  ) : null
41
50
  )}
42
51
  <ConfettiWrapper show={showConfetti} />
52
+ <AchievementModal show={!!modalMessage} message={modalMessage} onClose={handleCloseModal} />
43
53
  </AchievementContext.Provider>
44
54
  );
45
55
  };