react-achievements 1.0.3 → 1.0.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/dist/components/AchievementModal.d.ts +2 -1
- package/dist/components/BadgesModal.d.ts +2 -2
- package/dist/components/ConfettiWrapper.d.ts +2 -0
- package/dist/context/AchievementContext.d.ts +6 -11
- package/dist/index.cjs.js +144 -83
- package/dist/index.d.ts +3 -4
- package/dist/index.esm.js +146 -85
- package/dist/types.d.ts +17 -0
- package/package.json +1 -1
- package/public/badges/icon1.svg +1 -0
- package/src/components/AchievementModal.tsx +7 -4
- package/src/components/BadgesModal.tsx +8 -8
- package/src/components/ConfettiWrapper.tsx +13 -3
- package/src/context/AchievementContext.tsx +53 -51
- package/src/index.ts +11 -4
- package/src/{custom.d.ts → react-confetti.d.ts} +2 -4
- package/src/react-use.d.ts +4 -0
- package/src/types.ts +21 -0
- package/tsconfig.json +3 -1
- package/src/badges.ts +0 -24
- package/src/components/Achievement.tsx +0 -29
- package/src/components/Progress.tsx +0 -37
- package/src/levels.ts +0 -13
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { AchievementData } from '../types';
|
|
2
3
|
interface AchievementModalProps {
|
|
3
4
|
show: boolean;
|
|
4
|
-
|
|
5
|
+
achievement: AchievementData | null;
|
|
5
6
|
onClose: () => void;
|
|
6
7
|
}
|
|
7
8
|
declare const _default: React.NamedExoticComponent<AchievementModalProps>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { AchievementData } from '../types';
|
|
3
3
|
interface BadgesModalProps {
|
|
4
4
|
show: boolean;
|
|
5
|
-
|
|
5
|
+
achievements: AchievementData[];
|
|
6
6
|
onClose: () => void;
|
|
7
7
|
}
|
|
8
8
|
declare const _default: React.NamedExoticComponent<BadgesModalProps>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { ConfettiProps } from 'react-confetti';
|
|
2
3
|
interface ConfettiWrapperProps {
|
|
3
4
|
show: boolean;
|
|
5
|
+
confettiProps?: Partial<ConfettiProps>;
|
|
4
6
|
}
|
|
5
7
|
declare const ConfettiWrapper: React.FC<ConfettiWrapperProps>;
|
|
6
8
|
export default ConfettiWrapper;
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { LevelConfig } from '../levels';
|
|
2
|
+
import { Metrics, AchievementConfig } from '../types';
|
|
4
3
|
interface AchievementContextProps {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
achievedLevels: number[];
|
|
10
|
-
handleAchieve: (level: number, message: string) => void;
|
|
11
|
-
showAchievementModal: (message: string) => void;
|
|
4
|
+
metrics: Metrics;
|
|
5
|
+
setMetrics: (metrics: Metrics) => void;
|
|
6
|
+
achievedAchievements: string[];
|
|
7
|
+
checkAchievements: () => void;
|
|
12
8
|
showBadgesModal: () => void;
|
|
13
9
|
}
|
|
14
10
|
interface AchievementProviderProps {
|
|
15
11
|
children: ReactNode;
|
|
16
|
-
|
|
17
|
-
initialLevels?: LevelConfig[];
|
|
12
|
+
config: AchievementConfig;
|
|
18
13
|
storageKey?: string;
|
|
19
14
|
badgesButtonPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
20
15
|
}
|
package/dist/index.cjs.js
CHANGED
|
@@ -2,30 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
id: 'beginner',
|
|
8
|
-
icon: '/path/to/beginner-icon.png',
|
|
9
|
-
title: 'Beginner',
|
|
10
|
-
description: 'Achieved beginner level',
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
id: 'intermediate',
|
|
14
|
-
icon: '/path/to/intermediate-icon.png',
|
|
15
|
-
title: 'Intermediate',
|
|
16
|
-
description: 'Achieved intermediate level',
|
|
17
|
-
},
|
|
18
|
-
// Add more badges as needed
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
const defaultLevels = [
|
|
22
|
-
{ level: 1, threshold: 10, badgeId: 'beginner' },
|
|
23
|
-
{ level: 2, threshold: 50, badgeId: 'intermediate' },
|
|
24
|
-
// Add more levels as needed
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
const AchievementModal = ({ show, message, onClose }) => {
|
|
28
|
-
if (!show)
|
|
5
|
+
const AchievementModal = ({ show, achievement, onClose }) => {
|
|
6
|
+
if (!show || !achievement)
|
|
29
7
|
return null;
|
|
30
8
|
const modalStyle = {
|
|
31
9
|
position: 'fixed',
|
|
@@ -51,12 +29,14 @@ const AchievementModal = ({ show, message, onClose }) => {
|
|
|
51
29
|
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
52
30
|
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "achievement-title" },
|
|
53
31
|
React.createElement("h2", { id: "achievement-title" }, "Achievement Unlocked!"),
|
|
54
|
-
React.createElement("
|
|
32
|
+
React.createElement("img", { src: achievement.icon, alt: achievement.title, style: { width: '50px', height: '50px' } }),
|
|
33
|
+
React.createElement("h3", null, achievement.title),
|
|
34
|
+
React.createElement("p", null, achievement.description),
|
|
55
35
|
React.createElement("button", { onClick: onClose }, "Okay"))));
|
|
56
36
|
};
|
|
57
37
|
var AchievementModal$1 = React.memo(AchievementModal);
|
|
58
38
|
|
|
59
|
-
const BadgesModal = ({ show,
|
|
39
|
+
const BadgesModal = ({ show, achievements, onClose }) => {
|
|
60
40
|
if (!show)
|
|
61
41
|
return null;
|
|
62
42
|
const modalStyle = {
|
|
@@ -86,10 +66,10 @@ const BadgesModal = ({ show, badges, onClose }) => {
|
|
|
86
66
|
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
87
67
|
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "badges-title" },
|
|
88
68
|
React.createElement("h2", { id: "badges-title" }, "Your Achievements"),
|
|
89
|
-
React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'center' } },
|
|
90
|
-
React.createElement("img", { src:
|
|
91
|
-
React.createElement("h4", null,
|
|
92
|
-
React.createElement("p", null,
|
|
69
|
+
React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'center' } }, achievements.map(achievement => (React.createElement("div", { key: achievement.id, style: { margin: '10px', textAlign: 'center' } },
|
|
70
|
+
React.createElement("img", { src: achievement.icon, alt: achievement.title, style: { width: '50px', height: '50px' } }),
|
|
71
|
+
React.createElement("h4", null, achievement.title),
|
|
72
|
+
React.createElement("p", null, achievement.description))))),
|
|
93
73
|
React.createElement("button", { onClick: onClose, style: { marginTop: '20px' } }, "Close"))));
|
|
94
74
|
};
|
|
95
75
|
var BadgesModal$1 = React.memo(BadgesModal);
|
|
@@ -111,52 +91,149 @@ const BadgesButton = ({ onClick, position }) => {
|
|
|
111
91
|
};
|
|
112
92
|
var BadgesButton$1 = React.memo(BadgesButton);
|
|
113
93
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
94
|
+
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
95
|
+
|
|
96
|
+
function getDefaultExportFromCjs (x) {
|
|
97
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
var reactConfetti_min = {exports: {}};
|
|
101
|
+
|
|
102
|
+
(function (module, exports) {
|
|
103
|
+
!function(t,e){module.exports=e(React);}("undefined"!=typeof self?self:commonjsGlobal,(function(t){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r});},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0});},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(r,i,function(e){return t[e]}.bind(null,i));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=2)}([function(e,n){e.exports=t;},function(t,e,n){var r={linear:function(t,e,n,r){return (n-e)*t/r+e},easeInQuad:function(t,e,n,r){return (n-e)*(t/=r)*t+e},easeOutQuad:function(t,e,n,r){return -(n-e)*(t/=r)*(t-2)+e},easeInOutQuad:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t+e:-i/2*(--t*(t-2)-1)+e},easeInCubic:function(t,e,n,r){return (n-e)*(t/=r)*t*t+e},easeOutCubic:function(t,e,n,r){return (n-e)*((t=t/r-1)*t*t+1)+e},easeInOutCubic:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t*t+e:i/2*((t-=2)*t*t+2)+e},easeInQuart:function(t,e,n,r){return (n-e)*(t/=r)*t*t*t+e},easeOutQuart:function(t,e,n,r){return -(n-e)*((t=t/r-1)*t*t*t-1)+e},easeInOutQuart:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t*t*t+e:-i/2*((t-=2)*t*t*t-2)+e},easeInQuint:function(t,e,n,r){return (n-e)*(t/=r)*t*t*t*t+e},easeOutQuint:function(t,e,n,r){return (n-e)*((t=t/r-1)*t*t*t*t+1)+e},easeInOutQuint:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t*t*t*t+e:i/2*((t-=2)*t*t*t*t+2)+e},easeInSine:function(t,e,n,r){var i=n-e;return -i*Math.cos(t/r*(Math.PI/2))+i+e},easeOutSine:function(t,e,n,r){return (n-e)*Math.sin(t/r*(Math.PI/2))+e},easeInOutSine:function(t,e,n,r){return -(n-e)/2*(Math.cos(Math.PI*t/r)-1)+e},easeInExpo:function(t,e,n,r){return 0==t?e:(n-e)*Math.pow(2,10*(t/r-1))+e},easeOutExpo:function(t,e,n,r){var i=n-e;return t==r?e+i:i*(1-Math.pow(2,-10*t/r))+e},easeInOutExpo:function(t,e,n,r){var i=n-e;return 0===t?e:t===r?e+i:(t/=r/2)<1?i/2*Math.pow(2,10*(t-1))+e:i/2*(2-Math.pow(2,-10*--t))+e},easeInCirc:function(t,e,n,r){return -(n-e)*(Math.sqrt(1-(t/=r)*t)-1)+e},easeOutCirc:function(t,e,n,r){return (n-e)*Math.sqrt(1-(t=t/r-1)*t)+e},easeInOutCirc:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?-i/2*(Math.sqrt(1-t*t)-1)+e:i/2*(Math.sqrt(1-(t-=2)*t)+1)+e},easeInElastic:function(t,e,n,r){var i,o,a,c=n-e;return a=1.70158,0===t?e:1==(t/=r)?e+c:((o=0)||(o=.3*r),(i=c)<Math.abs(c)?(i=c,a=o/4):a=o/(2*Math.PI)*Math.asin(c/i),-i*Math.pow(2,10*(t-=1))*Math.sin((t*r-a)*(2*Math.PI)/o)+e)},easeOutElastic:function(t,e,n,r){var i,o,a,c=n-e;return a=1.70158,0===t?e:1==(t/=r)?e+c:((o=0)||(o=.3*r),(i=c)<Math.abs(c)?(i=c,a=o/4):a=o/(2*Math.PI)*Math.asin(c/i),i*Math.pow(2,-10*t)*Math.sin((t*r-a)*(2*Math.PI)/o)+c+e)},easeInOutElastic:function(t,e,n,r){var i,o,a,c=n-e;return a=1.70158,0===t?e:2==(t/=r/2)?e+c:((o=0)||(o=r*(.3*1.5)),(i=c)<Math.abs(c)?(i=c,a=o/4):a=o/(2*Math.PI)*Math.asin(c/i),t<1?i*Math.pow(2,10*(t-=1))*Math.sin((t*r-a)*(2*Math.PI)/o)*-.5+e:i*Math.pow(2,-10*(t-=1))*Math.sin((t*r-a)*(2*Math.PI)/o)*.5+c+e)},easeInBack:function(t,e,n,r,i){return void 0===i&&(i=1.70158),(n-e)*(t/=r)*t*((i+1)*t-i)+e},easeOutBack:function(t,e,n,r,i){return void 0===i&&(i=1.70158),(n-e)*((t=t/r-1)*t*((i+1)*t+i)+1)+e},easeInOutBack:function(t,e,n,r,i){var o=n-e;return void 0===i&&(i=1.70158),(t/=r/2)<1?o/2*(t*t*((1+(i*=1.525))*t-i))+e:o/2*((t-=2)*t*((1+(i*=1.525))*t+i)+2)+e},easeInBounce:function(t,e,n,i){var o=n-e;return o-r.easeOutBounce(i-t,0,o,i)+e},easeOutBounce:function(t,e,n,r){var i=n-e;return (t/=r)<1/2.75?i*(7.5625*t*t)+e:t<2/2.75?i*(7.5625*(t-=1.5/2.75)*t+.75)+e:t<2.5/2.75?i*(7.5625*(t-=2.25/2.75)*t+.9375)+e:i*(7.5625*(t-=2.625/2.75)*t+.984375)+e},easeInOutBounce:function(t,e,n,i){var o=n-e;return t<i/2?.5*r.easeInBounce(2*t,0,o,i)+e:.5*r.easeOutBounce(2*t-i,0,o,i)+.5*o+e}};t.exports=r;},function(t,e,n){t.exports=n(3);},function(t,e,n){n.r(e),n.d(e,"ReactConfetti",(function(){return Q}));var r,i,o=n(0),a=n.n(o),c=n(1),s=n.n(c);function u(t,e){return t+Math.random()*(e-t)}function f(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r);}}function h(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}!function(t){t[t.Circle=0]="Circle",t[t.Square=1]="Square",t[t.Strip=2]="Strip";}(r||(r={})),function(t){t[t.Positive=1]="Positive",t[t.Negative=-1]="Negative";}(i||(i={}));var l=function(){function t(e,n,r,o){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),h(this,"context",void 0),h(this,"radius",void 0),h(this,"x",void 0),h(this,"y",void 0),h(this,"w",void 0),h(this,"h",void 0),h(this,"vx",void 0),h(this,"vy",void 0),h(this,"shape",void 0),h(this,"angle",void 0),h(this,"angularSpin",void 0),h(this,"color",void 0),h(this,"rotateY",void 0),h(this,"rotationDirection",void 0),h(this,"getOptions",void 0),this.getOptions=n;var a,c,s=this.getOptions(),f=s.colors,l=s.initialVelocityX,p=s.initialVelocityY;this.context=e,this.x=r,this.y=o,this.w=u(5,20),this.h=u(5,20),this.radius=u(5,10),this.vx="number"==typeof l?u(-l,l):u(l.min,l.max),this.vy="number"==typeof p?u(-p,0):u(p.min,p.max),this.shape=(a=0,c=2,Math.floor(a+Math.random()*(c-a+1))),this.angle=u(0,360)*Math.PI/180,this.angularSpin=u(-.2,.2),this.color=f[Math.floor(Math.random()*f.length)],this.rotateY=u(0,1),this.rotationDirection=u(0,1)?i.Positive:i.Negative;}var e,n;return e=t,(n=[{key:"update",value:function(){var t=this.getOptions(),e=t.gravity,n=t.wind,o=t.friction,a=t.opacity,c=t.drawShape;this.x+=this.vx,this.y+=this.vy,this.vy+=e,this.vx+=n,this.vx*=o,this.vy*=o,this.rotateY>=1&&this.rotationDirection===i.Positive?this.rotationDirection=i.Negative:this.rotateY<=-1&&this.rotationDirection===i.Negative&&(this.rotationDirection=i.Positive);var s=.1*this.rotationDirection;if(this.rotateY+=s,this.angle+=this.angularSpin,this.context.save(),this.context.translate(this.x,this.y),this.context.rotate(this.angle),this.context.scale(1,this.rotateY),this.context.rotate(this.angle),this.context.beginPath(),this.context.fillStyle=this.color,this.context.strokeStyle=this.color,this.context.globalAlpha=a,this.context.lineCap="round",this.context.lineWidth=2,c&&"function"==typeof c)c.call(this,this.context);else switch(this.shape){case r.Circle:this.context.beginPath(),this.context.arc(0,0,this.radius,0,2*Math.PI),this.context.fill();break;case r.Square:this.context.fillRect(-this.w/2,-this.h/2,this.w,this.h);break;case r.Strip:this.context.fillRect(-this.w/6,-this.h/2,this.w/3,this.h);}this.context.closePath(),this.context.restore();}}])&&f(e.prototype,n),t}();function p(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var v=function t(e,n){var r=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),p(this,"canvas",void 0),p(this,"context",void 0),p(this,"getOptions",void 0),p(this,"x",0),p(this,"y",0),p(this,"w",0),p(this,"h",0),p(this,"lastNumberOfPieces",0),p(this,"tweenInitTime",Date.now()),p(this,"particles",[]),p(this,"particlesGenerated",0),p(this,"removeParticleAt",(function(t){r.particles.splice(t,1);})),p(this,"getParticle",(function(){var t=u(r.x,r.w+r.x),e=u(r.y,r.h+r.y);return new l(r.context,r.getOptions,t,e)})),p(this,"animate",(function(){var t=r.canvas,e=r.context,n=r.particlesGenerated,i=r.lastNumberOfPieces,o=r.getOptions(),a=o.run,c=o.recycle,s=o.numberOfPieces,u=o.debug,f=o.tweenFunction,h=o.tweenDuration;if(!a)return !1;var l=r.particles.length,p=c?l:n,v=Date.now();if(p<s){i!==s&&(r.tweenInitTime=v,r.lastNumberOfPieces=s);for(var y=r.tweenInitTime,d=f(v-y>h?h:Math.max(0,v-y),p,s,h),b=Math.round(d-p),g=0;g<b;g++)r.particles.push(r.getParticle());r.particlesGenerated+=b;}return u&&(e.font="12px sans-serif",e.fillStyle="#333",e.textAlign="right",e.fillText("Particles: ".concat(l),t.width-10,t.height-20)),r.particles.forEach((function(e,n){e.update(),(e.y>t.height||e.y<-100||e.x>t.width+100||e.x<-100)&&(c&&p<=s?r.particles[n]=r.getParticle():r.removeParticleAt(n));})),l>0||p<s})),this.canvas=e;var i=this.canvas.getContext("2d");if(!i)throw new Error("Could not get canvas context");this.context=i,this.getOptions=n;};function y(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r);}return n}function d(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?y(Object(n),!0).forEach((function(e){g(t,e,n[e]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):y(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e));}));}return t}function b(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r);}}function g(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var O={width:"undefined"!=typeof window?window.innerWidth:300,height:"undefined"!=typeof window?window.innerHeight:200,numberOfPieces:200,friction:.99,wind:0,gravity:.1,initialVelocityX:4,initialVelocityY:10,colors:["#f44336","#e91e63","#9c27b0","#673ab7","#3f51b5","#2196f3","#03a9f4","#00bcd4","#009688","#4CAF50","#8BC34A","#CDDC39","#FFEB3B","#FFC107","#FF9800","#FF5722","#795548"],opacity:1,debug:!1,tweenFunction:s.a.easeInOutQuad,tweenDuration:5e3,recycle:!0,run:!0},w=function(){function t(e,n){var r=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),g(this,"canvas",void 0),g(this,"context",void 0),g(this,"_options",void 0),g(this,"generator",void 0),g(this,"rafId",void 0),g(this,"setOptionsWithDefaults",(function(t){var e={confettiSource:{x:0,y:0,w:r.canvas.width,h:0}};r._options=d(d(d({},e),O),t),Object.assign(r,t.confettiSource);})),g(this,"update",(function(){var t=r.options,e=t.run,n=t.onConfettiComplete,i=r.canvas,o=r.context;e&&(o.fillStyle="white",o.clearRect(0,0,i.width,i.height)),r.generator.animate()?r.rafId=requestAnimationFrame(r.update):(n&&"function"==typeof n&&r.generator.particlesGenerated>0&&n.call(r,r),r._options.run=!1);})),g(this,"reset",(function(){r.generator&&r.generator.particlesGenerated>0&&(r.generator.particlesGenerated=0,r.generator.particles=[],r.generator.lastNumberOfPieces=0);})),g(this,"stop",(function(){r.options={run:!1},r.rafId&&(cancelAnimationFrame(r.rafId),r.rafId=void 0);})),this.canvas=e;var i=this.canvas.getContext("2d");if(!i)throw new Error("Could not get canvas context");this.context=i,this.generator=new v(this.canvas,(function(){return r.options})),this.options=n,this.update();}var e,n;return e=t,(n=[{key:"options",get:function(){return this._options},set:function(t){var e=this._options&&this._options.run,n=this._options&&this._options.recycle;this.setOptionsWithDefaults(t),this.generator&&(Object.assign(this.generator,this.options.confettiSource),"boolean"==typeof t.recycle&&t.recycle&&!1===n&&(this.generator.lastNumberOfPieces=this.generator.particles.length)),"boolean"==typeof t.run&&t.run&&!1===e&&this.update();}}])&&b(e.prototype,n),t}();function m(t){return function(t){if(Array.isArray(t))return C(t)}(t)||function(t){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(t))return Array.from(t)}(t)||S(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function x(t){return (x="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function P(){return (P=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r]);}return t}).apply(this,arguments)}function j(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r);}return n}function M(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?j(Object(n),!0).forEach((function(e){T(t,e,n[e]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):j(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e));}));}return t}function I(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(t)))return;var n=[],r=!0,i=!1,o=void 0;try{for(var a,c=t[Symbol.iterator]();!(r=(a=c.next()).done)&&(n.push(a.value),!e||n.length!==e);r=!0);}catch(t){i=!0,o=t;}finally{try{r||null==c.return||c.return();}finally{if(i)throw o}}return n}(t,e)||S(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function S(t,e){if(t){if("string"==typeof t)return C(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return "Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?C(t,e):void 0}}function C(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n<e;n++)r[n]=t[n];return r}function D(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function E(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r);}}function _(t,e){return (_=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function R(t){var e=function(){if("undefined"==typeof Reflect||!Reflect.construct)return !1;if(Reflect.construct.sham)return !1;if("function"==typeof Proxy)return !0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],(function(){}))),!0}catch(t){return !1}}();return function(){var n,r=F(t);if(e){var i=F(this).constructor;n=Reflect.construct(r,arguments,i);}else n=r.apply(this,arguments);return k(this,n)}}function k(t,e){return !e||"object"!==x(e)&&"function"!=typeof e?A(t):e}function A(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function F(t){return (F=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function T(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var B=a.a.createRef(),N=function(t){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&_(t,e);}(o,t);var e,n,i=R(o);function o(t){var e;D(this,o);for(var n=arguments.length,r=new Array(n>1?n-1:0),c=1;c<n;c++)r[c-1]=arguments[c];return T(A(e=i.call.apply(i,[this,t].concat(r))),"canvas",a.a.createRef()),T(A(e),"confetti",void 0),e.canvas=t.canvasRef||B,e}return e=o,(n=[{key:"componentDidMount",value:function(){if(this.canvas.current){var t=q(this.props)[0];this.confetti=new w(this.canvas.current,t);}}},{key:"componentDidUpdate",value:function(){var t=q(this.props)[0];this.confetti&&(this.confetti.options=t);}},{key:"componentWillUnmount",value:function(){this.confetti&&this.confetti.stop(),this.confetti=void 0;}},{key:"render",value:function(){var t=I(q(this.props),2),e=t[0],n=t[1],r=M({zIndex:2,position:"absolute",pointerEvents:"none",top:0,left:0,bottom:0,right:0},n.style);return a.a.createElement("canvas",P({width:e.width,height:e.height,ref:this.canvas},n,{style:r}))}}])&&E(e.prototype,n),o}(o.Component);function q(t){var e={},n={},r=[].concat(m(Object.keys(O)),["confettiSource","drawShape","onConfettiComplete"]),i=["canvasRef"];for(var o in t){var a=t[o];r.includes(o)?e[o]=a:i.includes(o)?i[o]=a:n[o]=a;}return [e,n,{}]}T(N,"defaultProps",M({},O)),T(N,"displayName","ReactConfetti");var Q=a.a.forwardRef((function(t,e){return a.a.createElement(N,P({canvasRef:e},t))}));e.default=Q;}]).default}));
|
|
104
|
+
|
|
105
|
+
} (reactConfetti_min));
|
|
106
|
+
|
|
107
|
+
var reactConfetti_minExports = reactConfetti_min.exports;
|
|
108
|
+
var Confetti = /*@__PURE__*/getDefaultExportFromCjs(reactConfetti_minExports);
|
|
109
|
+
|
|
110
|
+
function on(obj) {
|
|
111
|
+
var args = [];
|
|
112
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
113
|
+
args[_i - 1] = arguments[_i];
|
|
114
|
+
}
|
|
115
|
+
if (obj && obj.addEventListener) {
|
|
116
|
+
obj.addEventListener.apply(obj, args);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function off(obj) {
|
|
120
|
+
var args = [];
|
|
121
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
122
|
+
args[_i - 1] = arguments[_i];
|
|
123
|
+
}
|
|
124
|
+
if (obj && obj.removeEventListener) {
|
|
125
|
+
obj.removeEventListener.apply(obj, args);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
var isBrowser = typeof window !== 'undefined';
|
|
129
|
+
|
|
130
|
+
var useEffectOnce = function (effect) {
|
|
131
|
+
React.useEffect(effect, []);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
var useUnmount = function (fn) {
|
|
135
|
+
var fnRef = React.useRef(fn);
|
|
136
|
+
// update the ref each render so if it change the newest callback will be invoked
|
|
137
|
+
fnRef.current = fn;
|
|
138
|
+
useEffectOnce(function () { return function () { return fnRef.current(); }; });
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
var useRafState = function (initialState) {
|
|
142
|
+
var frame = React.useRef(0);
|
|
143
|
+
var _a = React.useState(initialState), state = _a[0], setState = _a[1];
|
|
144
|
+
var setRafState = React.useCallback(function (value) {
|
|
145
|
+
cancelAnimationFrame(frame.current);
|
|
146
|
+
frame.current = requestAnimationFrame(function () {
|
|
147
|
+
setState(value);
|
|
148
|
+
});
|
|
149
|
+
}, []);
|
|
150
|
+
useUnmount(function () {
|
|
151
|
+
cancelAnimationFrame(frame.current);
|
|
119
152
|
});
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
return [state, setRafState];
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
var useWindowSize = function (initialWidth, initialHeight) {
|
|
157
|
+
if (initialWidth === void 0) { initialWidth = Infinity; }
|
|
158
|
+
if (initialHeight === void 0) { initialHeight = Infinity; }
|
|
159
|
+
var _a = useRafState({
|
|
160
|
+
width: isBrowser ? window.innerWidth : initialWidth,
|
|
161
|
+
height: isBrowser ? window.innerHeight : initialHeight,
|
|
162
|
+
}), state = _a[0], setState = _a[1];
|
|
163
|
+
React.useEffect(function () {
|
|
164
|
+
if (isBrowser) {
|
|
165
|
+
var handler_1 = function () {
|
|
166
|
+
setState({
|
|
167
|
+
width: window.innerWidth,
|
|
168
|
+
height: window.innerHeight,
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
on(window, 'resize', handler_1);
|
|
172
|
+
return function () {
|
|
173
|
+
off(window, 'resize', handler_1);
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}, []);
|
|
177
|
+
return state;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const ConfettiWrapper = ({ show, confettiProps }) => {
|
|
181
|
+
const { width, height } = useWindowSize();
|
|
182
|
+
if (!show)
|
|
183
|
+
return null;
|
|
184
|
+
return (React.createElement(Confetti, Object.assign({ width: width, height: height }, confettiProps)));
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const AchievementContext = React.createContext(undefined);
|
|
188
|
+
const AchievementProvider = ({ children, config, storageKey = 'react-achievements', badgesButtonPosition = 'top-right' }) => {
|
|
189
|
+
const [metrics, setMetrics] = React.useState({});
|
|
190
|
+
const [achievedAchievements, setAchievedAchievements] = React.useState(() => {
|
|
191
|
+
const saved = localStorage.getItem(`${storageKey}-achievements`);
|
|
122
192
|
return saved ? JSON.parse(saved) : [];
|
|
123
193
|
});
|
|
124
|
-
const [
|
|
125
|
-
const [levels] = React.useState(initialLevels);
|
|
126
|
-
const [achievementModalMessage, setAchievementModalMessage] = React.useState('');
|
|
194
|
+
const [newAchievement, setNewAchievement] = React.useState(null);
|
|
127
195
|
const [showBadges, setShowBadges] = React.useState(false);
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
196
|
+
const [showConfetti, setShowConfetti] = React.useState(false);
|
|
197
|
+
const checkAchievements = () => {
|
|
198
|
+
const newAchievements = [];
|
|
199
|
+
Object.entries(config).forEach(([metricKey, conditions]) => {
|
|
200
|
+
const metricValue = metrics[metricKey];
|
|
201
|
+
conditions.forEach(condition => {
|
|
202
|
+
if (condition.check(metricValue) && !achievedAchievements.includes(condition.data.id)) {
|
|
203
|
+
newAchievements.push(condition.data);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
if (newAchievements.length > 0) {
|
|
208
|
+
const updatedAchievements = [...achievedAchievements, ...newAchievements.map(a => a.id)];
|
|
209
|
+
setAchievedAchievements(updatedAchievements);
|
|
210
|
+
localStorage.setItem(`${storageKey}-achievements`, JSON.stringify(updatedAchievements));
|
|
211
|
+
setNewAchievement(newAchievements[0]);
|
|
212
|
+
setShowConfetti(true);
|
|
134
213
|
}
|
|
135
|
-
}
|
|
136
|
-
const
|
|
137
|
-
setAchievementModalMessage(message);
|
|
138
|
-
}, []);
|
|
139
|
-
const showBadgesModal = React.useCallback(() => {
|
|
214
|
+
};
|
|
215
|
+
const showBadgesModal = () => {
|
|
140
216
|
setShowBadges(true);
|
|
141
|
-
}
|
|
142
|
-
const contextValue =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
217
|
+
};
|
|
218
|
+
const contextValue = {
|
|
219
|
+
metrics,
|
|
220
|
+
setMetrics: (newMetrics) => {
|
|
221
|
+
setMetrics(newMetrics);
|
|
222
|
+
checkAchievements();
|
|
147
223
|
},
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
achievedLevels,
|
|
151
|
-
handleAchieve,
|
|
152
|
-
showAchievementModal,
|
|
224
|
+
achievedAchievements,
|
|
225
|
+
checkAchievements,
|
|
153
226
|
showBadgesModal
|
|
154
|
-
}
|
|
227
|
+
};
|
|
155
228
|
return (React.createElement(AchievementContext.Provider, { value: contextValue },
|
|
156
229
|
children,
|
|
157
|
-
React.createElement(AchievementModal$1, { show: !!
|
|
158
|
-
|
|
159
|
-
|
|
230
|
+
React.createElement(AchievementModal$1, { show: !!newAchievement, achievement: newAchievement, onClose: () => {
|
|
231
|
+
setNewAchievement(null);
|
|
232
|
+
setShowConfetti(false);
|
|
233
|
+
} }),
|
|
234
|
+
React.createElement(BadgesModal$1, { show: showBadges, achievements: Object.values(config).flatMap(conditions => conditions.filter(c => achievedAchievements.includes(c.data.id)).map(c => c.data)), onClose: () => setShowBadges(false) }),
|
|
235
|
+
React.createElement(BadgesButton$1, { onClick: showBadgesModal, position: badgesButtonPosition }),
|
|
236
|
+
React.createElement(ConfettiWrapper, { show: showConfetti })));
|
|
160
237
|
};
|
|
161
238
|
const useAchievement = () => {
|
|
162
239
|
const context = React.useContext(AchievementContext);
|
|
@@ -166,22 +243,6 @@ const useAchievement = () => {
|
|
|
166
243
|
return context;
|
|
167
244
|
};
|
|
168
245
|
|
|
169
|
-
const Achievement = ({ metric, threshold, onAchieve, message, children }) => {
|
|
170
|
-
const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
|
|
171
|
-
React.useEffect(() => {
|
|
172
|
-
if (metric >= threshold && !achievedLevels.includes(threshold)) {
|
|
173
|
-
onAchieve();
|
|
174
|
-
const levelConfig = levels.find(level => level.threshold === threshold);
|
|
175
|
-
if (levelConfig) {
|
|
176
|
-
setMetric(metric);
|
|
177
|
-
handleAchieve(levelConfig.level, message);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}, [metric, threshold, onAchieve, achievedLevels, levels, message, setMetric, handleAchieve]);
|
|
181
|
-
return React.createElement(React.Fragment, null, children);
|
|
182
|
-
};
|
|
183
|
-
var Achievement$1 = React.memo(Achievement);
|
|
184
|
-
|
|
185
|
-
exports.Achievement = Achievement$1;
|
|
186
246
|
exports.AchievementProvider = AchievementProvider;
|
|
247
|
+
exports.ConfettiWrapper = ConfettiWrapper;
|
|
187
248
|
exports.useAchievement = useAchievement;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AchievementProvider, useAchievement } from './context/AchievementContext';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
export { AchievementProvider, useAchievement, Achievement, BadgeConfig, LevelConfig };
|
|
2
|
+
import { Metrics, AchievementConfig, AchievementData, AchievementCondition } from './types';
|
|
3
|
+
import ConfettiWrapper from './components/ConfettiWrapper';
|
|
4
|
+
export { AchievementProvider, useAchievement, Metrics, AchievementConfig, AchievementData, AchievementCondition, ConfettiWrapper };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,29 +1,7 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
id: 'beginner',
|
|
6
|
-
icon: '/path/to/beginner-icon.png',
|
|
7
|
-
title: 'Beginner',
|
|
8
|
-
description: 'Achieved beginner level',
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
id: 'intermediate',
|
|
12
|
-
icon: '/path/to/intermediate-icon.png',
|
|
13
|
-
title: 'Intermediate',
|
|
14
|
-
description: 'Achieved intermediate level',
|
|
15
|
-
},
|
|
16
|
-
// Add more badges as needed
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
const defaultLevels = [
|
|
20
|
-
{ level: 1, threshold: 10, badgeId: 'beginner' },
|
|
21
|
-
{ level: 2, threshold: 50, badgeId: 'intermediate' },
|
|
22
|
-
// Add more levels as needed
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
const AchievementModal = ({ show, message, onClose }) => {
|
|
26
|
-
if (!show)
|
|
1
|
+
import React, { useEffect, useRef, useState, useCallback, createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
const AchievementModal = ({ show, achievement, onClose }) => {
|
|
4
|
+
if (!show || !achievement)
|
|
27
5
|
return null;
|
|
28
6
|
const modalStyle = {
|
|
29
7
|
position: 'fixed',
|
|
@@ -49,12 +27,14 @@ const AchievementModal = ({ show, message, onClose }) => {
|
|
|
49
27
|
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
50
28
|
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "achievement-title" },
|
|
51
29
|
React.createElement("h2", { id: "achievement-title" }, "Achievement Unlocked!"),
|
|
52
|
-
React.createElement("
|
|
30
|
+
React.createElement("img", { src: achievement.icon, alt: achievement.title, style: { width: '50px', height: '50px' } }),
|
|
31
|
+
React.createElement("h3", null, achievement.title),
|
|
32
|
+
React.createElement("p", null, achievement.description),
|
|
53
33
|
React.createElement("button", { onClick: onClose }, "Okay"))));
|
|
54
34
|
};
|
|
55
35
|
var AchievementModal$1 = React.memo(AchievementModal);
|
|
56
36
|
|
|
57
|
-
const BadgesModal = ({ show,
|
|
37
|
+
const BadgesModal = ({ show, achievements, onClose }) => {
|
|
58
38
|
if (!show)
|
|
59
39
|
return null;
|
|
60
40
|
const modalStyle = {
|
|
@@ -84,10 +64,10 @@ const BadgesModal = ({ show, badges, onClose }) => {
|
|
|
84
64
|
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
85
65
|
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "badges-title" },
|
|
86
66
|
React.createElement("h2", { id: "badges-title" }, "Your Achievements"),
|
|
87
|
-
React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'center' } },
|
|
88
|
-
React.createElement("img", { src:
|
|
89
|
-
React.createElement("h4", null,
|
|
90
|
-
React.createElement("p", null,
|
|
67
|
+
React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'center' } }, achievements.map(achievement => (React.createElement("div", { key: achievement.id, style: { margin: '10px', textAlign: 'center' } },
|
|
68
|
+
React.createElement("img", { src: achievement.icon, alt: achievement.title, style: { width: '50px', height: '50px' } }),
|
|
69
|
+
React.createElement("h4", null, achievement.title),
|
|
70
|
+
React.createElement("p", null, achievement.description))))),
|
|
91
71
|
React.createElement("button", { onClick: onClose, style: { marginTop: '20px' } }, "Close"))));
|
|
92
72
|
};
|
|
93
73
|
var BadgesModal$1 = React.memo(BadgesModal);
|
|
@@ -109,52 +89,149 @@ const BadgesButton = ({ onClick, position }) => {
|
|
|
109
89
|
};
|
|
110
90
|
var BadgesButton$1 = React.memo(BadgesButton);
|
|
111
91
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
92
|
+
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
93
|
+
|
|
94
|
+
function getDefaultExportFromCjs (x) {
|
|
95
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var reactConfetti_min = {exports: {}};
|
|
99
|
+
|
|
100
|
+
(function (module, exports) {
|
|
101
|
+
!function(t,e){module.exports=e(React);}("undefined"!=typeof self?self:commonjsGlobal,(function(t){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r});},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0});},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(r,i,function(e){return t[e]}.bind(null,i));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=2)}([function(e,n){e.exports=t;},function(t,e,n){var r={linear:function(t,e,n,r){return (n-e)*t/r+e},easeInQuad:function(t,e,n,r){return (n-e)*(t/=r)*t+e},easeOutQuad:function(t,e,n,r){return -(n-e)*(t/=r)*(t-2)+e},easeInOutQuad:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t+e:-i/2*(--t*(t-2)-1)+e},easeInCubic:function(t,e,n,r){return (n-e)*(t/=r)*t*t+e},easeOutCubic:function(t,e,n,r){return (n-e)*((t=t/r-1)*t*t+1)+e},easeInOutCubic:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t*t+e:i/2*((t-=2)*t*t+2)+e},easeInQuart:function(t,e,n,r){return (n-e)*(t/=r)*t*t*t+e},easeOutQuart:function(t,e,n,r){return -(n-e)*((t=t/r-1)*t*t*t-1)+e},easeInOutQuart:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t*t*t+e:-i/2*((t-=2)*t*t*t-2)+e},easeInQuint:function(t,e,n,r){return (n-e)*(t/=r)*t*t*t*t+e},easeOutQuint:function(t,e,n,r){return (n-e)*((t=t/r-1)*t*t*t*t+1)+e},easeInOutQuint:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?i/2*t*t*t*t*t+e:i/2*((t-=2)*t*t*t*t+2)+e},easeInSine:function(t,e,n,r){var i=n-e;return -i*Math.cos(t/r*(Math.PI/2))+i+e},easeOutSine:function(t,e,n,r){return (n-e)*Math.sin(t/r*(Math.PI/2))+e},easeInOutSine:function(t,e,n,r){return -(n-e)/2*(Math.cos(Math.PI*t/r)-1)+e},easeInExpo:function(t,e,n,r){return 0==t?e:(n-e)*Math.pow(2,10*(t/r-1))+e},easeOutExpo:function(t,e,n,r){var i=n-e;return t==r?e+i:i*(1-Math.pow(2,-10*t/r))+e},easeInOutExpo:function(t,e,n,r){var i=n-e;return 0===t?e:t===r?e+i:(t/=r/2)<1?i/2*Math.pow(2,10*(t-1))+e:i/2*(2-Math.pow(2,-10*--t))+e},easeInCirc:function(t,e,n,r){return -(n-e)*(Math.sqrt(1-(t/=r)*t)-1)+e},easeOutCirc:function(t,e,n,r){return (n-e)*Math.sqrt(1-(t=t/r-1)*t)+e},easeInOutCirc:function(t,e,n,r){var i=n-e;return (t/=r/2)<1?-i/2*(Math.sqrt(1-t*t)-1)+e:i/2*(Math.sqrt(1-(t-=2)*t)+1)+e},easeInElastic:function(t,e,n,r){var i,o,a,c=n-e;return a=1.70158,0===t?e:1==(t/=r)?e+c:((o=0)||(o=.3*r),(i=c)<Math.abs(c)?(i=c,a=o/4):a=o/(2*Math.PI)*Math.asin(c/i),-i*Math.pow(2,10*(t-=1))*Math.sin((t*r-a)*(2*Math.PI)/o)+e)},easeOutElastic:function(t,e,n,r){var i,o,a,c=n-e;return a=1.70158,0===t?e:1==(t/=r)?e+c:((o=0)||(o=.3*r),(i=c)<Math.abs(c)?(i=c,a=o/4):a=o/(2*Math.PI)*Math.asin(c/i),i*Math.pow(2,-10*t)*Math.sin((t*r-a)*(2*Math.PI)/o)+c+e)},easeInOutElastic:function(t,e,n,r){var i,o,a,c=n-e;return a=1.70158,0===t?e:2==(t/=r/2)?e+c:((o=0)||(o=r*(.3*1.5)),(i=c)<Math.abs(c)?(i=c,a=o/4):a=o/(2*Math.PI)*Math.asin(c/i),t<1?i*Math.pow(2,10*(t-=1))*Math.sin((t*r-a)*(2*Math.PI)/o)*-.5+e:i*Math.pow(2,-10*(t-=1))*Math.sin((t*r-a)*(2*Math.PI)/o)*.5+c+e)},easeInBack:function(t,e,n,r,i){return void 0===i&&(i=1.70158),(n-e)*(t/=r)*t*((i+1)*t-i)+e},easeOutBack:function(t,e,n,r,i){return void 0===i&&(i=1.70158),(n-e)*((t=t/r-1)*t*((i+1)*t+i)+1)+e},easeInOutBack:function(t,e,n,r,i){var o=n-e;return void 0===i&&(i=1.70158),(t/=r/2)<1?o/2*(t*t*((1+(i*=1.525))*t-i))+e:o/2*((t-=2)*t*((1+(i*=1.525))*t+i)+2)+e},easeInBounce:function(t,e,n,i){var o=n-e;return o-r.easeOutBounce(i-t,0,o,i)+e},easeOutBounce:function(t,e,n,r){var i=n-e;return (t/=r)<1/2.75?i*(7.5625*t*t)+e:t<2/2.75?i*(7.5625*(t-=1.5/2.75)*t+.75)+e:t<2.5/2.75?i*(7.5625*(t-=2.25/2.75)*t+.9375)+e:i*(7.5625*(t-=2.625/2.75)*t+.984375)+e},easeInOutBounce:function(t,e,n,i){var o=n-e;return t<i/2?.5*r.easeInBounce(2*t,0,o,i)+e:.5*r.easeOutBounce(2*t-i,0,o,i)+.5*o+e}};t.exports=r;},function(t,e,n){t.exports=n(3);},function(t,e,n){n.r(e),n.d(e,"ReactConfetti",(function(){return Q}));var r,i,o=n(0),a=n.n(o),c=n(1),s=n.n(c);function u(t,e){return t+Math.random()*(e-t)}function f(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r);}}function h(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}!function(t){t[t.Circle=0]="Circle",t[t.Square=1]="Square",t[t.Strip=2]="Strip";}(r||(r={})),function(t){t[t.Positive=1]="Positive",t[t.Negative=-1]="Negative";}(i||(i={}));var l=function(){function t(e,n,r,o){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),h(this,"context",void 0),h(this,"radius",void 0),h(this,"x",void 0),h(this,"y",void 0),h(this,"w",void 0),h(this,"h",void 0),h(this,"vx",void 0),h(this,"vy",void 0),h(this,"shape",void 0),h(this,"angle",void 0),h(this,"angularSpin",void 0),h(this,"color",void 0),h(this,"rotateY",void 0),h(this,"rotationDirection",void 0),h(this,"getOptions",void 0),this.getOptions=n;var a,c,s=this.getOptions(),f=s.colors,l=s.initialVelocityX,p=s.initialVelocityY;this.context=e,this.x=r,this.y=o,this.w=u(5,20),this.h=u(5,20),this.radius=u(5,10),this.vx="number"==typeof l?u(-l,l):u(l.min,l.max),this.vy="number"==typeof p?u(-p,0):u(p.min,p.max),this.shape=(a=0,c=2,Math.floor(a+Math.random()*(c-a+1))),this.angle=u(0,360)*Math.PI/180,this.angularSpin=u(-.2,.2),this.color=f[Math.floor(Math.random()*f.length)],this.rotateY=u(0,1),this.rotationDirection=u(0,1)?i.Positive:i.Negative;}var e,n;return e=t,(n=[{key:"update",value:function(){var t=this.getOptions(),e=t.gravity,n=t.wind,o=t.friction,a=t.opacity,c=t.drawShape;this.x+=this.vx,this.y+=this.vy,this.vy+=e,this.vx+=n,this.vx*=o,this.vy*=o,this.rotateY>=1&&this.rotationDirection===i.Positive?this.rotationDirection=i.Negative:this.rotateY<=-1&&this.rotationDirection===i.Negative&&(this.rotationDirection=i.Positive);var s=.1*this.rotationDirection;if(this.rotateY+=s,this.angle+=this.angularSpin,this.context.save(),this.context.translate(this.x,this.y),this.context.rotate(this.angle),this.context.scale(1,this.rotateY),this.context.rotate(this.angle),this.context.beginPath(),this.context.fillStyle=this.color,this.context.strokeStyle=this.color,this.context.globalAlpha=a,this.context.lineCap="round",this.context.lineWidth=2,c&&"function"==typeof c)c.call(this,this.context);else switch(this.shape){case r.Circle:this.context.beginPath(),this.context.arc(0,0,this.radius,0,2*Math.PI),this.context.fill();break;case r.Square:this.context.fillRect(-this.w/2,-this.h/2,this.w,this.h);break;case r.Strip:this.context.fillRect(-this.w/6,-this.h/2,this.w/3,this.h);}this.context.closePath(),this.context.restore();}}])&&f(e.prototype,n),t}();function p(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var v=function t(e,n){var r=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),p(this,"canvas",void 0),p(this,"context",void 0),p(this,"getOptions",void 0),p(this,"x",0),p(this,"y",0),p(this,"w",0),p(this,"h",0),p(this,"lastNumberOfPieces",0),p(this,"tweenInitTime",Date.now()),p(this,"particles",[]),p(this,"particlesGenerated",0),p(this,"removeParticleAt",(function(t){r.particles.splice(t,1);})),p(this,"getParticle",(function(){var t=u(r.x,r.w+r.x),e=u(r.y,r.h+r.y);return new l(r.context,r.getOptions,t,e)})),p(this,"animate",(function(){var t=r.canvas,e=r.context,n=r.particlesGenerated,i=r.lastNumberOfPieces,o=r.getOptions(),a=o.run,c=o.recycle,s=o.numberOfPieces,u=o.debug,f=o.tweenFunction,h=o.tweenDuration;if(!a)return !1;var l=r.particles.length,p=c?l:n,v=Date.now();if(p<s){i!==s&&(r.tweenInitTime=v,r.lastNumberOfPieces=s);for(var y=r.tweenInitTime,d=f(v-y>h?h:Math.max(0,v-y),p,s,h),b=Math.round(d-p),g=0;g<b;g++)r.particles.push(r.getParticle());r.particlesGenerated+=b;}return u&&(e.font="12px sans-serif",e.fillStyle="#333",e.textAlign="right",e.fillText("Particles: ".concat(l),t.width-10,t.height-20)),r.particles.forEach((function(e,n){e.update(),(e.y>t.height||e.y<-100||e.x>t.width+100||e.x<-100)&&(c&&p<=s?r.particles[n]=r.getParticle():r.removeParticleAt(n));})),l>0||p<s})),this.canvas=e;var i=this.canvas.getContext("2d");if(!i)throw new Error("Could not get canvas context");this.context=i,this.getOptions=n;};function y(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r);}return n}function d(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?y(Object(n),!0).forEach((function(e){g(t,e,n[e]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):y(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e));}));}return t}function b(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r);}}function g(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var O={width:"undefined"!=typeof window?window.innerWidth:300,height:"undefined"!=typeof window?window.innerHeight:200,numberOfPieces:200,friction:.99,wind:0,gravity:.1,initialVelocityX:4,initialVelocityY:10,colors:["#f44336","#e91e63","#9c27b0","#673ab7","#3f51b5","#2196f3","#03a9f4","#00bcd4","#009688","#4CAF50","#8BC34A","#CDDC39","#FFEB3B","#FFC107","#FF9800","#FF5722","#795548"],opacity:1,debug:!1,tweenFunction:s.a.easeInOutQuad,tweenDuration:5e3,recycle:!0,run:!0},w=function(){function t(e,n){var r=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),g(this,"canvas",void 0),g(this,"context",void 0),g(this,"_options",void 0),g(this,"generator",void 0),g(this,"rafId",void 0),g(this,"setOptionsWithDefaults",(function(t){var e={confettiSource:{x:0,y:0,w:r.canvas.width,h:0}};r._options=d(d(d({},e),O),t),Object.assign(r,t.confettiSource);})),g(this,"update",(function(){var t=r.options,e=t.run,n=t.onConfettiComplete,i=r.canvas,o=r.context;e&&(o.fillStyle="white",o.clearRect(0,0,i.width,i.height)),r.generator.animate()?r.rafId=requestAnimationFrame(r.update):(n&&"function"==typeof n&&r.generator.particlesGenerated>0&&n.call(r,r),r._options.run=!1);})),g(this,"reset",(function(){r.generator&&r.generator.particlesGenerated>0&&(r.generator.particlesGenerated=0,r.generator.particles=[],r.generator.lastNumberOfPieces=0);})),g(this,"stop",(function(){r.options={run:!1},r.rafId&&(cancelAnimationFrame(r.rafId),r.rafId=void 0);})),this.canvas=e;var i=this.canvas.getContext("2d");if(!i)throw new Error("Could not get canvas context");this.context=i,this.generator=new v(this.canvas,(function(){return r.options})),this.options=n,this.update();}var e,n;return e=t,(n=[{key:"options",get:function(){return this._options},set:function(t){var e=this._options&&this._options.run,n=this._options&&this._options.recycle;this.setOptionsWithDefaults(t),this.generator&&(Object.assign(this.generator,this.options.confettiSource),"boolean"==typeof t.recycle&&t.recycle&&!1===n&&(this.generator.lastNumberOfPieces=this.generator.particles.length)),"boolean"==typeof t.run&&t.run&&!1===e&&this.update();}}])&&b(e.prototype,n),t}();function m(t){return function(t){if(Array.isArray(t))return C(t)}(t)||function(t){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(t))return Array.from(t)}(t)||S(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function x(t){return (x="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function P(){return (P=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r]);}return t}).apply(this,arguments)}function j(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r);}return n}function M(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?j(Object(n),!0).forEach((function(e){T(t,e,n[e]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):j(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e));}));}return t}function I(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(t)))return;var n=[],r=!0,i=!1,o=void 0;try{for(var a,c=t[Symbol.iterator]();!(r=(a=c.next()).done)&&(n.push(a.value),!e||n.length!==e);r=!0);}catch(t){i=!0,o=t;}finally{try{r||null==c.return||c.return();}finally{if(i)throw o}}return n}(t,e)||S(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function S(t,e){if(t){if("string"==typeof t)return C(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return "Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?C(t,e):void 0}}function C(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n<e;n++)r[n]=t[n];return r}function D(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function E(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r);}}function _(t,e){return (_=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function R(t){var e=function(){if("undefined"==typeof Reflect||!Reflect.construct)return !1;if(Reflect.construct.sham)return !1;if("function"==typeof Proxy)return !0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],(function(){}))),!0}catch(t){return !1}}();return function(){var n,r=F(t);if(e){var i=F(this).constructor;n=Reflect.construct(r,arguments,i);}else n=r.apply(this,arguments);return k(this,n)}}function k(t,e){return !e||"object"!==x(e)&&"function"!=typeof e?A(t):e}function A(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function F(t){return (F=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function T(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var B=a.a.createRef(),N=function(t){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&_(t,e);}(o,t);var e,n,i=R(o);function o(t){var e;D(this,o);for(var n=arguments.length,r=new Array(n>1?n-1:0),c=1;c<n;c++)r[c-1]=arguments[c];return T(A(e=i.call.apply(i,[this,t].concat(r))),"canvas",a.a.createRef()),T(A(e),"confetti",void 0),e.canvas=t.canvasRef||B,e}return e=o,(n=[{key:"componentDidMount",value:function(){if(this.canvas.current){var t=q(this.props)[0];this.confetti=new w(this.canvas.current,t);}}},{key:"componentDidUpdate",value:function(){var t=q(this.props)[0];this.confetti&&(this.confetti.options=t);}},{key:"componentWillUnmount",value:function(){this.confetti&&this.confetti.stop(),this.confetti=void 0;}},{key:"render",value:function(){var t=I(q(this.props),2),e=t[0],n=t[1],r=M({zIndex:2,position:"absolute",pointerEvents:"none",top:0,left:0,bottom:0,right:0},n.style);return a.a.createElement("canvas",P({width:e.width,height:e.height,ref:this.canvas},n,{style:r}))}}])&&E(e.prototype,n),o}(o.Component);function q(t){var e={},n={},r=[].concat(m(Object.keys(O)),["confettiSource","drawShape","onConfettiComplete"]),i=["canvasRef"];for(var o in t){var a=t[o];r.includes(o)?e[o]=a:i.includes(o)?i[o]=a:n[o]=a;}return [e,n,{}]}T(N,"defaultProps",M({},O)),T(N,"displayName","ReactConfetti");var Q=a.a.forwardRef((function(t,e){return a.a.createElement(N,P({canvasRef:e},t))}));e.default=Q;}]).default}));
|
|
102
|
+
|
|
103
|
+
} (reactConfetti_min));
|
|
104
|
+
|
|
105
|
+
var reactConfetti_minExports = reactConfetti_min.exports;
|
|
106
|
+
var Confetti = /*@__PURE__*/getDefaultExportFromCjs(reactConfetti_minExports);
|
|
107
|
+
|
|
108
|
+
function on(obj) {
|
|
109
|
+
var args = [];
|
|
110
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
111
|
+
args[_i - 1] = arguments[_i];
|
|
112
|
+
}
|
|
113
|
+
if (obj && obj.addEventListener) {
|
|
114
|
+
obj.addEventListener.apply(obj, args);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function off(obj) {
|
|
118
|
+
var args = [];
|
|
119
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
120
|
+
args[_i - 1] = arguments[_i];
|
|
121
|
+
}
|
|
122
|
+
if (obj && obj.removeEventListener) {
|
|
123
|
+
obj.removeEventListener.apply(obj, args);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
var isBrowser = typeof window !== 'undefined';
|
|
127
|
+
|
|
128
|
+
var useEffectOnce = function (effect) {
|
|
129
|
+
useEffect(effect, []);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
var useUnmount = function (fn) {
|
|
133
|
+
var fnRef = useRef(fn);
|
|
134
|
+
// update the ref each render so if it change the newest callback will be invoked
|
|
135
|
+
fnRef.current = fn;
|
|
136
|
+
useEffectOnce(function () { return function () { return fnRef.current(); }; });
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
var useRafState = function (initialState) {
|
|
140
|
+
var frame = useRef(0);
|
|
141
|
+
var _a = useState(initialState), state = _a[0], setState = _a[1];
|
|
142
|
+
var setRafState = useCallback(function (value) {
|
|
143
|
+
cancelAnimationFrame(frame.current);
|
|
144
|
+
frame.current = requestAnimationFrame(function () {
|
|
145
|
+
setState(value);
|
|
146
|
+
});
|
|
147
|
+
}, []);
|
|
148
|
+
useUnmount(function () {
|
|
149
|
+
cancelAnimationFrame(frame.current);
|
|
117
150
|
});
|
|
118
|
-
|
|
119
|
-
|
|
151
|
+
return [state, setRafState];
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
var useWindowSize = function (initialWidth, initialHeight) {
|
|
155
|
+
if (initialWidth === void 0) { initialWidth = Infinity; }
|
|
156
|
+
if (initialHeight === void 0) { initialHeight = Infinity; }
|
|
157
|
+
var _a = useRafState({
|
|
158
|
+
width: isBrowser ? window.innerWidth : initialWidth,
|
|
159
|
+
height: isBrowser ? window.innerHeight : initialHeight,
|
|
160
|
+
}), state = _a[0], setState = _a[1];
|
|
161
|
+
useEffect(function () {
|
|
162
|
+
if (isBrowser) {
|
|
163
|
+
var handler_1 = function () {
|
|
164
|
+
setState({
|
|
165
|
+
width: window.innerWidth,
|
|
166
|
+
height: window.innerHeight,
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
on(window, 'resize', handler_1);
|
|
170
|
+
return function () {
|
|
171
|
+
off(window, 'resize', handler_1);
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}, []);
|
|
175
|
+
return state;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const ConfettiWrapper = ({ show, confettiProps }) => {
|
|
179
|
+
const { width, height } = useWindowSize();
|
|
180
|
+
if (!show)
|
|
181
|
+
return null;
|
|
182
|
+
return (React.createElement(Confetti, Object.assign({ width: width, height: height }, confettiProps)));
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const AchievementContext = createContext(undefined);
|
|
186
|
+
const AchievementProvider = ({ children, config, storageKey = 'react-achievements', badgesButtonPosition = 'top-right' }) => {
|
|
187
|
+
const [metrics, setMetrics] = useState({});
|
|
188
|
+
const [achievedAchievements, setAchievedAchievements] = useState(() => {
|
|
189
|
+
const saved = localStorage.getItem(`${storageKey}-achievements`);
|
|
120
190
|
return saved ? JSON.parse(saved) : [];
|
|
121
191
|
});
|
|
122
|
-
const [
|
|
123
|
-
const [levels] = useState(initialLevels);
|
|
124
|
-
const [achievementModalMessage, setAchievementModalMessage] = useState('');
|
|
192
|
+
const [newAchievement, setNewAchievement] = useState(null);
|
|
125
193
|
const [showBadges, setShowBadges] = useState(false);
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
194
|
+
const [showConfetti, setShowConfetti] = useState(false);
|
|
195
|
+
const checkAchievements = () => {
|
|
196
|
+
const newAchievements = [];
|
|
197
|
+
Object.entries(config).forEach(([metricKey, conditions]) => {
|
|
198
|
+
const metricValue = metrics[metricKey];
|
|
199
|
+
conditions.forEach(condition => {
|
|
200
|
+
if (condition.check(metricValue) && !achievedAchievements.includes(condition.data.id)) {
|
|
201
|
+
newAchievements.push(condition.data);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
if (newAchievements.length > 0) {
|
|
206
|
+
const updatedAchievements = [...achievedAchievements, ...newAchievements.map(a => a.id)];
|
|
207
|
+
setAchievedAchievements(updatedAchievements);
|
|
208
|
+
localStorage.setItem(`${storageKey}-achievements`, JSON.stringify(updatedAchievements));
|
|
209
|
+
setNewAchievement(newAchievements[0]);
|
|
210
|
+
setShowConfetti(true);
|
|
132
211
|
}
|
|
133
|
-
}
|
|
134
|
-
const
|
|
135
|
-
setAchievementModalMessage(message);
|
|
136
|
-
}, []);
|
|
137
|
-
const showBadgesModal = useCallback(() => {
|
|
212
|
+
};
|
|
213
|
+
const showBadgesModal = () => {
|
|
138
214
|
setShowBadges(true);
|
|
139
|
-
}
|
|
140
|
-
const contextValue =
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
215
|
+
};
|
|
216
|
+
const contextValue = {
|
|
217
|
+
metrics,
|
|
218
|
+
setMetrics: (newMetrics) => {
|
|
219
|
+
setMetrics(newMetrics);
|
|
220
|
+
checkAchievements();
|
|
145
221
|
},
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
achievedLevels,
|
|
149
|
-
handleAchieve,
|
|
150
|
-
showAchievementModal,
|
|
222
|
+
achievedAchievements,
|
|
223
|
+
checkAchievements,
|
|
151
224
|
showBadgesModal
|
|
152
|
-
}
|
|
225
|
+
};
|
|
153
226
|
return (React.createElement(AchievementContext.Provider, { value: contextValue },
|
|
154
227
|
children,
|
|
155
|
-
React.createElement(AchievementModal$1, { show: !!
|
|
156
|
-
|
|
157
|
-
|
|
228
|
+
React.createElement(AchievementModal$1, { show: !!newAchievement, achievement: newAchievement, onClose: () => {
|
|
229
|
+
setNewAchievement(null);
|
|
230
|
+
setShowConfetti(false);
|
|
231
|
+
} }),
|
|
232
|
+
React.createElement(BadgesModal$1, { show: showBadges, achievements: Object.values(config).flatMap(conditions => conditions.filter(c => achievedAchievements.includes(c.data.id)).map(c => c.data)), onClose: () => setShowBadges(false) }),
|
|
233
|
+
React.createElement(BadgesButton$1, { onClick: showBadgesModal, position: badgesButtonPosition }),
|
|
234
|
+
React.createElement(ConfettiWrapper, { show: showConfetti })));
|
|
158
235
|
};
|
|
159
236
|
const useAchievement = () => {
|
|
160
237
|
const context = useContext(AchievementContext);
|
|
@@ -164,20 +241,4 @@ const useAchievement = () => {
|
|
|
164
241
|
return context;
|
|
165
242
|
};
|
|
166
243
|
|
|
167
|
-
|
|
168
|
-
const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
|
|
169
|
-
useEffect(() => {
|
|
170
|
-
if (metric >= threshold && !achievedLevels.includes(threshold)) {
|
|
171
|
-
onAchieve();
|
|
172
|
-
const levelConfig = levels.find(level => level.threshold === threshold);
|
|
173
|
-
if (levelConfig) {
|
|
174
|
-
setMetric(metric);
|
|
175
|
-
handleAchieve(levelConfig.level, message);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}, [metric, threshold, onAchieve, achievedLevels, levels, message, setMetric, handleAchieve]);
|
|
179
|
-
return React.createElement(React.Fragment, null, children);
|
|
180
|
-
};
|
|
181
|
-
var Achievement$1 = React.memo(Achievement);
|
|
182
|
-
|
|
183
|
-
export { Achievement$1 as Achievement, AchievementProvider, useAchievement };
|
|
244
|
+
export { AchievementProvider, ConfettiWrapper, useAchievement };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type MetricValue = number | boolean | string | any;
|
|
2
|
+
export interface Metrics {
|
|
3
|
+
[key: string]: MetricValue;
|
|
4
|
+
}
|
|
5
|
+
export interface AchievementData {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
icon: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AchievementCondition {
|
|
12
|
+
check: (metricValue: MetricValue) => boolean;
|
|
13
|
+
data: AchievementData;
|
|
14
|
+
}
|
|
15
|
+
export interface AchievementConfig {
|
|
16
|
+
[metricKey: string]: AchievementCondition[];
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M560-440q-50 0-85-35t-35-85q0-50 35-85t85-35q50 0 85 35t35 85q0 50-35 85t-85 35ZM280-320q-33 0-56.5-23.5T200-400v-320q0-33 23.5-56.5T280-800h560q33 0 56.5 23.5T920-720v320q0 33-23.5 56.5T840-320H280Zm80-80h400q0-33 23.5-56.5T840-480v-160q-33 0-56.5-23.5T760-720H360q0 33-23.5 56.5T280-640v160q33 0 56.5 23.5T360-400Zm440 240H120q-33 0-56.5-23.5T40-240v-440h80v440h680v80ZM280-400v-320 320Z"/></svg>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { AchievementData } from '../types';
|
|
2
3
|
|
|
3
4
|
interface AchievementModalProps {
|
|
4
5
|
show: boolean;
|
|
5
|
-
|
|
6
|
+
achievement: AchievementData | null;
|
|
6
7
|
onClose: () => void;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
const AchievementModal: React.FC<AchievementModalProps> = ({ show,
|
|
10
|
-
if (!show) return null;
|
|
10
|
+
const AchievementModal: React.FC<AchievementModalProps> = ({ show, achievement, onClose }) => {
|
|
11
|
+
if (!show || !achievement) return null;
|
|
11
12
|
|
|
12
13
|
const modalStyle: React.CSSProperties = {
|
|
13
14
|
position: 'fixed',
|
|
@@ -36,7 +37,9 @@ const AchievementModal: React.FC<AchievementModalProps> = ({ show, message, onCl
|
|
|
36
37
|
<div style={overlayStyle} onClick={onClose} />
|
|
37
38
|
<div style={modalStyle} role="dialog" aria-modal="true" aria-labelledby="achievement-title">
|
|
38
39
|
<h2 id="achievement-title">Achievement Unlocked!</h2>
|
|
39
|
-
<
|
|
40
|
+
<img src={achievement.icon} alt={achievement.title} style={{ width: '50px', height: '50px' }} />
|
|
41
|
+
<h3>{achievement.title}</h3>
|
|
42
|
+
<p>{achievement.description}</p>
|
|
40
43
|
<button onClick={onClose}>Okay</button>
|
|
41
44
|
</div>
|
|
42
45
|
</>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { AchievementData } from '../types';
|
|
3
3
|
|
|
4
4
|
interface BadgesModalProps {
|
|
5
5
|
show: boolean;
|
|
6
|
-
|
|
6
|
+
achievements: AchievementData[];
|
|
7
7
|
onClose: () => void;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const BadgesModal: React.FC<BadgesModalProps> = ({ show,
|
|
10
|
+
const BadgesModal: React.FC<BadgesModalProps> = ({ show, achievements, onClose }) => {
|
|
11
11
|
if (!show) return null;
|
|
12
12
|
|
|
13
13
|
const modalStyle: React.CSSProperties = {
|
|
@@ -41,11 +41,11 @@ const BadgesModal: React.FC<BadgesModalProps> = ({ show, badges, onClose }) => {
|
|
|
41
41
|
<div style={modalStyle} role="dialog" aria-modal="true" aria-labelledby="badges-title">
|
|
42
42
|
<h2 id="badges-title">Your Achievements</h2>
|
|
43
43
|
<div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center' }}>
|
|
44
|
-
{
|
|
45
|
-
<div key={
|
|
46
|
-
<img src={
|
|
47
|
-
<h4>{
|
|
48
|
-
<p>{
|
|
44
|
+
{achievements.map(achievement => (
|
|
45
|
+
<div key={achievement.id} style={{ margin: '10px', textAlign: 'center' }}>
|
|
46
|
+
<img src={achievement.icon} alt={achievement.title} style={{ width: '50px', height: '50px' }} />
|
|
47
|
+
<h4>{achievement.title}</h4>
|
|
48
|
+
<p>{achievement.description}</p>
|
|
49
49
|
</div>
|
|
50
50
|
))}
|
|
51
51
|
</div>
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Confetti from 'react-confetti';
|
|
3
3
|
import { useWindowSize } from 'react-use';
|
|
4
|
+
import { ConfettiProps } from 'react-confetti';
|
|
4
5
|
|
|
5
6
|
interface ConfettiWrapperProps {
|
|
6
7
|
show: boolean;
|
|
8
|
+
confettiProps?: Partial<ConfettiProps>;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
const ConfettiWrapper: React.FC<ConfettiWrapperProps> = ({ show }) => {
|
|
11
|
+
const ConfettiWrapper: React.FC<ConfettiWrapperProps> = ({ show, confettiProps }) => {
|
|
10
12
|
const { width, height } = useWindowSize();
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
if (!show) return null;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Confetti
|
|
18
|
+
width={width}
|
|
19
|
+
height={height}
|
|
20
|
+
{...confettiProps}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
13
23
|
};
|
|
14
24
|
|
|
15
|
-
export default ConfettiWrapper;
|
|
25
|
+
export default ConfettiWrapper;
|
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
import React, { createContext, useContext, useState, ReactNode
|
|
2
|
-
import {
|
|
3
|
-
import { defaultLevels, LevelConfig } from '../levels';
|
|
1
|
+
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
2
|
+
import { Metrics, AchievementConfig, AchievementData } from '../types';
|
|
4
3
|
import AchievementModal from '../components/AchievementModal';
|
|
5
4
|
import BadgesModal from '../components/BadgesModal';
|
|
6
5
|
import BadgesButton from '../components/BadgesButton';
|
|
6
|
+
import ConfettiWrapper from '../components/ConfettiWrapper';
|
|
7
7
|
|
|
8
8
|
interface AchievementContextProps {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
achievedLevels: number[];
|
|
14
|
-
handleAchieve: (level: number, message: string) => void;
|
|
15
|
-
showAchievementModal: (message: string) => void;
|
|
9
|
+
metrics: Metrics;
|
|
10
|
+
setMetrics: (metrics: Metrics) => void;
|
|
11
|
+
achievedAchievements: string[];
|
|
12
|
+
checkAchievements: () => void;
|
|
16
13
|
showBadgesModal: () => void;
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
interface AchievementProviderProps {
|
|
20
17
|
children: ReactNode;
|
|
21
|
-
|
|
22
|
-
initialLevels?: LevelConfig[];
|
|
18
|
+
config: AchievementConfig;
|
|
23
19
|
storageKey?: string;
|
|
24
20
|
badgesButtonPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
25
21
|
}
|
|
@@ -28,69 +24,75 @@ const AchievementContext = createContext<AchievementContextProps | undefined>(un
|
|
|
28
24
|
|
|
29
25
|
export const AchievementProvider: React.FC<AchievementProviderProps> = ({
|
|
30
26
|
children,
|
|
31
|
-
|
|
32
|
-
initialLevels = defaultLevels,
|
|
27
|
+
config,
|
|
33
28
|
storageKey = 'react-achievements',
|
|
34
29
|
badgesButtonPosition = 'top-right'
|
|
35
30
|
}) => {
|
|
36
|
-
const [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
const [achievedLevels, setAchievedLevels] = useState<number[]>(() => {
|
|
41
|
-
const saved = localStorage.getItem(`${storageKey}-levels`);
|
|
31
|
+
const [metrics, setMetrics] = useState<Metrics>({});
|
|
32
|
+
const [achievedAchievements, setAchievedAchievements] = useState<string[]>(() => {
|
|
33
|
+
const saved = localStorage.getItem(`${storageKey}-achievements`);
|
|
42
34
|
return saved ? JSON.parse(saved) : [];
|
|
43
35
|
});
|
|
44
|
-
const [
|
|
45
|
-
const [levels] = useState<LevelConfig[]>(initialLevels);
|
|
46
|
-
const [achievementModalMessage, setAchievementModalMessage] = useState('');
|
|
36
|
+
const [newAchievement, setNewAchievement] = useState<AchievementData | null>(null);
|
|
47
37
|
const [showBadges, setShowBadges] = useState(false);
|
|
38
|
+
const [showConfetti, setShowConfetti] = useState(false);
|
|
48
39
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
const newAchievedLevels = [...achievedLevels, level];
|
|
52
|
-
setAchievedLevels(newAchievedLevels);
|
|
53
|
-
localStorage.setItem(`${storageKey}-levels`, JSON.stringify(newAchievedLevels));
|
|
54
|
-
setAchievementModalMessage(message);
|
|
55
|
-
}
|
|
56
|
-
}, [achievedLevels, storageKey]);
|
|
40
|
+
const checkAchievements = () => {
|
|
41
|
+
const newAchievements: AchievementData[] = [];
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
43
|
+
Object.entries(config).forEach(([metricKey, conditions]) => {
|
|
44
|
+
const metricValue = metrics[metricKey];
|
|
45
|
+
conditions.forEach(condition => {
|
|
46
|
+
if (condition.check(metricValue) && !achievedAchievements.includes(condition.data.id)) {
|
|
47
|
+
newAchievements.push(condition.data);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (newAchievements.length > 0) {
|
|
53
|
+
const updatedAchievements = [...achievedAchievements, ...newAchievements.map(a => a.id)];
|
|
54
|
+
setAchievedAchievements(updatedAchievements);
|
|
55
|
+
localStorage.setItem(`${storageKey}-achievements`, JSON.stringify(updatedAchievements));
|
|
56
|
+
setNewAchievement(newAchievements[0]);
|
|
57
|
+
setShowConfetti(true);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
61
60
|
|
|
62
|
-
const showBadgesModal =
|
|
61
|
+
const showBadgesModal = () => {
|
|
63
62
|
setShowBadges(true);
|
|
64
|
-
}
|
|
63
|
+
};
|
|
65
64
|
|
|
66
|
-
const contextValue =
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
const contextValue: AchievementContextProps = {
|
|
66
|
+
metrics,
|
|
67
|
+
setMetrics: (newMetrics: Metrics) => {
|
|
68
|
+
setMetrics(newMetrics);
|
|
69
|
+
checkAchievements();
|
|
71
70
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
achievedLevels,
|
|
75
|
-
handleAchieve,
|
|
76
|
-
showAchievementModal,
|
|
71
|
+
achievedAchievements,
|
|
72
|
+
checkAchievements,
|
|
77
73
|
showBadgesModal
|
|
78
|
-
}
|
|
74
|
+
};
|
|
79
75
|
|
|
80
76
|
return (
|
|
81
77
|
<AchievementContext.Provider value={contextValue}>
|
|
82
78
|
{children}
|
|
83
79
|
<AchievementModal
|
|
84
|
-
show={!!
|
|
85
|
-
|
|
86
|
-
onClose={() =>
|
|
80
|
+
show={!!newAchievement}
|
|
81
|
+
achievement={newAchievement}
|
|
82
|
+
onClose={() => {
|
|
83
|
+
setNewAchievement(null);
|
|
84
|
+
setShowConfetti(false);
|
|
85
|
+
}}
|
|
87
86
|
/>
|
|
88
87
|
<BadgesModal
|
|
89
88
|
show={showBadges}
|
|
90
|
-
|
|
89
|
+
achievements={Object.values(config).flatMap(conditions =>
|
|
90
|
+
conditions.filter(c => achievedAchievements.includes(c.data.id)).map(c => c.data)
|
|
91
|
+
)}
|
|
91
92
|
onClose={() => setShowBadges(false)}
|
|
92
93
|
/>
|
|
93
94
|
<BadgesButton onClick={showBadgesModal} position={badgesButtonPosition} />
|
|
95
|
+
<ConfettiWrapper show={showConfetti} />
|
|
94
96
|
</AchievementContext.Provider>
|
|
95
97
|
);
|
|
96
98
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { AchievementProvider, useAchievement } from './context/AchievementContext';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { LevelConfig } from './levels';
|
|
2
|
+
import { Metrics, AchievementConfig, AchievementData, AchievementCondition } from './types';
|
|
3
|
+
import ConfettiWrapper from './components/ConfettiWrapper';
|
|
5
4
|
|
|
6
|
-
export {
|
|
5
|
+
export {
|
|
6
|
+
AchievementProvider,
|
|
7
|
+
useAchievement,
|
|
8
|
+
Metrics,
|
|
9
|
+
AchievementConfig,
|
|
10
|
+
AchievementData,
|
|
11
|
+
AchievementCondition,
|
|
12
|
+
ConfettiWrapper
|
|
13
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
declare module 'react-confetti' {
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
3
|
|
|
4
|
-
interface ConfettiProps {
|
|
4
|
+
export interface ConfettiProps {
|
|
5
5
|
width?: number;
|
|
6
6
|
height?: number;
|
|
7
7
|
numberOfPieces?: number;
|
|
@@ -16,6 +16,4 @@ declare module 'react-confetti' {
|
|
|
16
16
|
|
|
17
17
|
const Confetti: ComponentType<ConfettiProps>;
|
|
18
18
|
export default Confetti;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
declare module 'react-use'
|
|
19
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type MetricValue = number | boolean | string | any;
|
|
2
|
+
|
|
3
|
+
export interface Metrics {
|
|
4
|
+
[key: string]: MetricValue;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface AchievementData {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
description: string;
|
|
11
|
+
icon: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AchievementCondition {
|
|
15
|
+
check: (metricValue: MetricValue) => boolean;
|
|
16
|
+
data: AchievementData;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AchievementConfig {
|
|
20
|
+
[metricKey: string]: AchievementCondition[];
|
|
21
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -105,5 +105,7 @@
|
|
|
105
105
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
|
106
106
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
107
107
|
},
|
|
108
|
-
"include": [
|
|
108
|
+
"include": [
|
|
109
|
+
"src",
|
|
110
|
+
"react-confetti.d.ts"]
|
|
109
111
|
}
|
package/src/badges.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface BadgeConfig {
|
|
2
|
-
id: string;
|
|
3
|
-
icon: string;
|
|
4
|
-
title: string;
|
|
5
|
-
description: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const defaultBadges: BadgeConfig[] = [
|
|
9
|
-
{
|
|
10
|
-
id: 'beginner',
|
|
11
|
-
icon: '/path/to/beginner-icon.png',
|
|
12
|
-
title: 'Beginner',
|
|
13
|
-
description: 'Achieved beginner level',
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
id: 'intermediate',
|
|
17
|
-
icon: '/path/to/intermediate-icon.png',
|
|
18
|
-
title: 'Intermediate',
|
|
19
|
-
description: 'Achieved intermediate level',
|
|
20
|
-
},
|
|
21
|
-
// Add more badges as needed
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
export { defaultBadges };
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import { useAchievement } from '../context/AchievementContext';
|
|
3
|
-
|
|
4
|
-
interface AchievementProps {
|
|
5
|
-
metric: number;
|
|
6
|
-
threshold: number;
|
|
7
|
-
onAchieve: () => void;
|
|
8
|
-
message: string;
|
|
9
|
-
children: React.ReactNode;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const Achievement: React.FC<AchievementProps> = ({ metric, threshold, onAchieve, message, children }) => {
|
|
13
|
-
const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
if (metric >= threshold && !achievedLevels.includes(threshold)) {
|
|
17
|
-
onAchieve();
|
|
18
|
-
const levelConfig = levels.find(level => level.threshold === threshold);
|
|
19
|
-
if (levelConfig) {
|
|
20
|
-
setMetric(metric);
|
|
21
|
-
handleAchieve(levelConfig.level, message);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}, [metric, threshold, onAchieve, achievedLevels, levels, message, setMetric, handleAchieve]);
|
|
25
|
-
|
|
26
|
-
return <>{children}</>;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export default React.memo(Achievement);
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { useAchievement } from '../context/AchievementContext';
|
|
3
|
-
|
|
4
|
-
interface ProgressProps {
|
|
5
|
-
style?: React.CSSProperties;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const Progress: React.FC<ProgressProps> = ({ style }) => {
|
|
9
|
-
const { metric, levels, achievedLevels } = useAchievement();
|
|
10
|
-
const maxLevel = levels[levels.length - 1];
|
|
11
|
-
const progress = (metric / maxLevel.threshold) * 100;
|
|
12
|
-
|
|
13
|
-
const containerStyle: React.CSSProperties = {
|
|
14
|
-
width: '100%',
|
|
15
|
-
backgroundColor: '#e0e0e0',
|
|
16
|
-
borderRadius: '8px',
|
|
17
|
-
overflow: 'hidden',
|
|
18
|
-
...style,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const barStyle: React.CSSProperties = {
|
|
22
|
-
width: `${progress}%`,
|
|
23
|
-
height: '20px',
|
|
24
|
-
backgroundColor: '#4caf50',
|
|
25
|
-
transition: 'width 0.5s ease-in-out',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<div style={containerStyle}>
|
|
30
|
-
<div style={barStyle} role="progressbar" aria-valuenow={metric} aria-valuemin={0} aria-valuemax={maxLevel.threshold} />
|
|
31
|
-
<p>Level: {achievedLevels.length} / {levels.length}</p>
|
|
32
|
-
<p>Progress: {metric} / {maxLevel.threshold}</p>
|
|
33
|
-
</div>
|
|
34
|
-
);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export default React.memo(Progress);
|
package/src/levels.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface LevelConfig {
|
|
2
|
-
level: number;
|
|
3
|
-
threshold: number;
|
|
4
|
-
badgeId: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const defaultLevels: LevelConfig[] = [
|
|
8
|
-
{ level: 1, threshold: 10, badgeId: 'beginner' },
|
|
9
|
-
{ level: 2, threshold: 50, badgeId: 'intermediate' },
|
|
10
|
-
// Add more levels as needed
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
export { defaultLevels };
|