react-achievements 1.0.2 → 1.0.3
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/badges.d.ts +2 -2
- package/dist/components/Achievement.d.ts +2 -2
- package/dist/components/AchievementModal.d.ts +2 -2
- package/dist/components/BadgesButton.d.ts +7 -0
- package/dist/components/BadgesModal.d.ts +9 -0
- package/dist/components/Progress.d.ts +6 -0
- package/dist/context/AchievementContext.d.ts +11 -4
- package/dist/index.cjs.js +98 -131
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +100 -133
- package/dist/levels.d.ts +3 -3
- package/package.json +3 -2
- package/src/badges.ts +2 -2
- package/src/components/Achievement.tsx +5 -5
- package/src/components/AchievementModal.tsx +3 -3
- package/src/components/BadgesButton.tsx +29 -0
- package/src/components/BadgesModal.tsx +58 -0
- package/src/components/Progress.tsx +37 -0
- package/src/context/AchievementContext.tsx +74 -35
- package/src/index.ts +3 -1
- package/src/levels.ts +3 -3
- package/src/components/Badge.tsx +0 -34
package/dist/badges.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ interface AchievementModalProps {
|
|
|
4
4
|
message: string;
|
|
5
5
|
onClose: () => void;
|
|
6
6
|
}
|
|
7
|
-
declare const
|
|
8
|
-
export default
|
|
7
|
+
declare const _default: React.NamedExoticComponent<AchievementModalProps>;
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BadgeConfig } from '../badges';
|
|
3
|
+
interface BadgesModalProps {
|
|
4
|
+
show: boolean;
|
|
5
|
+
badges: BadgeConfig[];
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: React.NamedExoticComponent<BadgesModalProps>;
|
|
9
|
+
export default _default;
|
|
@@ -8,9 +8,16 @@ interface AchievementContextProps {
|
|
|
8
8
|
levels: LevelConfig[];
|
|
9
9
|
achievedLevels: number[];
|
|
10
10
|
handleAchieve: (level: number, message: string) => void;
|
|
11
|
+
showAchievementModal: (message: string) => void;
|
|
12
|
+
showBadgesModal: () => void;
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
interface AchievementProviderProps {
|
|
13
15
|
children: ReactNode;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
initialBadges?: BadgeConfig[];
|
|
17
|
+
initialLevels?: LevelConfig[];
|
|
18
|
+
storageKey?: string;
|
|
19
|
+
badgesButtonPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
20
|
+
}
|
|
21
|
+
export declare const AchievementProvider: React.FC<AchievementProviderProps>;
|
|
22
|
+
export declare const useAchievement: () => AchievementContextProps;
|
|
23
|
+
export {};
|
package/dist/index.cjs.js
CHANGED
|
@@ -18,103 +18,12 @@ const defaultBadges = [
|
|
|
18
18
|
// Add more badges as needed
|
|
19
19
|
];
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const defaultLevels = [
|
|
22
22
|
{ level: 1, threshold: 10, badgeId: 'beginner' },
|
|
23
23
|
{ level: 2, threshold: 50, badgeId: 'intermediate' },
|
|
24
24
|
// Add more levels as needed
|
|
25
25
|
];
|
|
26
26
|
|
|
27
|
-
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
28
|
-
|
|
29
|
-
function getDefaultExportFromCjs (x) {
|
|
30
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
var reactConfetti_min = {exports: {}};
|
|
34
|
-
|
|
35
|
-
(function (module, exports) {
|
|
36
|
-
!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}));
|
|
37
|
-
|
|
38
|
-
} (reactConfetti_min));
|
|
39
|
-
|
|
40
|
-
var reactConfetti_minExports = reactConfetti_min.exports;
|
|
41
|
-
var Confetti = /*@__PURE__*/getDefaultExportFromCjs(reactConfetti_minExports);
|
|
42
|
-
|
|
43
|
-
function on(obj) {
|
|
44
|
-
var args = [];
|
|
45
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
46
|
-
args[_i - 1] = arguments[_i];
|
|
47
|
-
}
|
|
48
|
-
if (obj && obj.addEventListener) {
|
|
49
|
-
obj.addEventListener.apply(obj, args);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function off(obj) {
|
|
53
|
-
var args = [];
|
|
54
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
55
|
-
args[_i - 1] = arguments[_i];
|
|
56
|
-
}
|
|
57
|
-
if (obj && obj.removeEventListener) {
|
|
58
|
-
obj.removeEventListener.apply(obj, args);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
var isBrowser = typeof window !== 'undefined';
|
|
62
|
-
|
|
63
|
-
var useEffectOnce = function (effect) {
|
|
64
|
-
React.useEffect(effect, []);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
var useUnmount = function (fn) {
|
|
68
|
-
var fnRef = React.useRef(fn);
|
|
69
|
-
// update the ref each render so if it change the newest callback will be invoked
|
|
70
|
-
fnRef.current = fn;
|
|
71
|
-
useEffectOnce(function () { return function () { return fnRef.current(); }; });
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
var useRafState = function (initialState) {
|
|
75
|
-
var frame = React.useRef(0);
|
|
76
|
-
var _a = React.useState(initialState), state = _a[0], setState = _a[1];
|
|
77
|
-
var setRafState = React.useCallback(function (value) {
|
|
78
|
-
cancelAnimationFrame(frame.current);
|
|
79
|
-
frame.current = requestAnimationFrame(function () {
|
|
80
|
-
setState(value);
|
|
81
|
-
});
|
|
82
|
-
}, []);
|
|
83
|
-
useUnmount(function () {
|
|
84
|
-
cancelAnimationFrame(frame.current);
|
|
85
|
-
});
|
|
86
|
-
return [state, setRafState];
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
var useWindowSize = function (initialWidth, initialHeight) {
|
|
90
|
-
if (initialWidth === void 0) { initialWidth = Infinity; }
|
|
91
|
-
if (initialHeight === void 0) { initialHeight = Infinity; }
|
|
92
|
-
var _a = useRafState({
|
|
93
|
-
width: isBrowser ? window.innerWidth : initialWidth,
|
|
94
|
-
height: isBrowser ? window.innerHeight : initialHeight,
|
|
95
|
-
}), state = _a[0], setState = _a[1];
|
|
96
|
-
React.useEffect(function () {
|
|
97
|
-
if (isBrowser) {
|
|
98
|
-
var handler_1 = function () {
|
|
99
|
-
setState({
|
|
100
|
-
width: window.innerWidth,
|
|
101
|
-
height: window.innerHeight,
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
on(window, 'resize', handler_1);
|
|
105
|
-
return function () {
|
|
106
|
-
off(window, 'resize', handler_1);
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
}, []);
|
|
110
|
-
return state;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const ConfettiWrapper = ({ show }) => {
|
|
114
|
-
const { width, height } = useWindowSize();
|
|
115
|
-
return show ? React.createElement(Confetti, { width: width, height: height }) : null;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
27
|
const AchievementModal = ({ show, message, onClose }) => {
|
|
119
28
|
if (!show)
|
|
120
29
|
return null;
|
|
@@ -140,57 +49,114 @@ const AchievementModal = ({ show, message, onClose }) => {
|
|
|
140
49
|
};
|
|
141
50
|
return (React.createElement(React.Fragment, null,
|
|
142
51
|
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
143
|
-
React.createElement("div", { style: modalStyle },
|
|
144
|
-
React.createElement("h2",
|
|
52
|
+
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "achievement-title" },
|
|
53
|
+
React.createElement("h2", { id: "achievement-title" }, "Achievement Unlocked!"),
|
|
145
54
|
React.createElement("p", null, message),
|
|
146
55
|
React.createElement("button", { onClick: onClose }, "Okay"))));
|
|
147
56
|
};
|
|
57
|
+
var AchievementModal$1 = React.memo(AchievementModal);
|
|
148
58
|
|
|
149
|
-
const
|
|
150
|
-
|
|
59
|
+
const BadgesModal = ({ show, badges, onClose }) => {
|
|
60
|
+
if (!show)
|
|
61
|
+
return null;
|
|
62
|
+
const modalStyle = {
|
|
151
63
|
position: 'fixed',
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
flexDirection: 'column',
|
|
156
|
-
alignItems: 'center',
|
|
64
|
+
top: '50%',
|
|
65
|
+
left: '50%',
|
|
66
|
+
transform: 'translate(-50%, -50%)',
|
|
157
67
|
backgroundColor: '#fff',
|
|
158
|
-
|
|
68
|
+
padding: '20px',
|
|
159
69
|
borderRadius: '8px',
|
|
160
|
-
padding: '10px',
|
|
161
70
|
boxShadow: '0 0 10px rgba(0,0,0,0.1)',
|
|
71
|
+
zIndex: 1000,
|
|
72
|
+
maxWidth: '80%',
|
|
73
|
+
maxHeight: '80%',
|
|
74
|
+
overflow: 'auto',
|
|
75
|
+
};
|
|
76
|
+
const overlayStyle = {
|
|
77
|
+
position: 'fixed',
|
|
78
|
+
top: 0,
|
|
79
|
+
left: 0,
|
|
80
|
+
right: 0,
|
|
81
|
+
bottom: 0,
|
|
82
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
83
|
+
zIndex: 999,
|
|
84
|
+
};
|
|
85
|
+
return (React.createElement(React.Fragment, null,
|
|
86
|
+
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
87
|
+
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "badges-title" },
|
|
88
|
+
React.createElement("h2", { id: "badges-title" }, "Your Achievements"),
|
|
89
|
+
React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'center' } }, badges.map(badge => (React.createElement("div", { key: badge.id, style: { margin: '10px', textAlign: 'center' } },
|
|
90
|
+
React.createElement("img", { src: badge.icon, alt: badge.title, style: { width: '50px', height: '50px' } }),
|
|
91
|
+
React.createElement("h4", null, badge.title),
|
|
92
|
+
React.createElement("p", null, badge.description))))),
|
|
93
|
+
React.createElement("button", { onClick: onClose, style: { marginTop: '20px' } }, "Close"))));
|
|
94
|
+
};
|
|
95
|
+
var BadgesModal$1 = React.memo(BadgesModal);
|
|
96
|
+
|
|
97
|
+
const BadgesButton = ({ onClick, position }) => {
|
|
98
|
+
const buttonStyle = {
|
|
99
|
+
position: 'fixed',
|
|
100
|
+
[position.split('-')[0]]: '20px',
|
|
101
|
+
[position.split('-')[1]]: '20px',
|
|
102
|
+
padding: '10px 20px',
|
|
103
|
+
backgroundColor: '#007bff',
|
|
104
|
+
color: '#fff',
|
|
105
|
+
border: 'none',
|
|
106
|
+
borderRadius: '5px',
|
|
107
|
+
cursor: 'pointer',
|
|
108
|
+
zIndex: 998,
|
|
162
109
|
};
|
|
163
|
-
return (React.createElement("
|
|
164
|
-
React.createElement("img", { src: icon, alt: title, style: { width: '50px', height: '50px' } }),
|
|
165
|
-
React.createElement("h4", null, title),
|
|
166
|
-
React.createElement("p", null, description)));
|
|
110
|
+
return (React.createElement("button", { style: buttonStyle, onClick: onClick }, "View Achievements"));
|
|
167
111
|
};
|
|
112
|
+
var BadgesButton$1 = React.memo(BadgesButton);
|
|
168
113
|
|
|
169
114
|
const AchievementContext = React.createContext(undefined);
|
|
170
|
-
const AchievementProvider = ({ children }) => {
|
|
171
|
-
const [metric, setMetric] = React.useState(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
115
|
+
const AchievementProvider = ({ children, initialBadges = defaultBadges, initialLevels = defaultLevels, storageKey = 'react-achievements', badgesButtonPosition = 'top-right' }) => {
|
|
116
|
+
const [metric, setMetric] = React.useState(() => {
|
|
117
|
+
const saved = localStorage.getItem(`${storageKey}-metric`);
|
|
118
|
+
return saved ? parseInt(saved, 10) : 0;
|
|
119
|
+
});
|
|
120
|
+
const [achievedLevels, setAchievedLevels] = React.useState(() => {
|
|
121
|
+
const saved = localStorage.getItem(`${storageKey}-levels`);
|
|
122
|
+
return saved ? JSON.parse(saved) : [];
|
|
123
|
+
});
|
|
124
|
+
const [badges] = React.useState(initialBadges);
|
|
125
|
+
const [levels] = React.useState(initialLevels);
|
|
126
|
+
const [achievementModalMessage, setAchievementModalMessage] = React.useState('');
|
|
127
|
+
const [showBadges, setShowBadges] = React.useState(false);
|
|
128
|
+
const handleAchieve = React.useCallback((level, message) => {
|
|
176
129
|
if (!achievedLevels.includes(level)) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
130
|
+
const newAchievedLevels = [...achievedLevels, level];
|
|
131
|
+
setAchievedLevels(newAchievedLevels);
|
|
132
|
+
localStorage.setItem(`${storageKey}-levels`, JSON.stringify(newAchievedLevels));
|
|
133
|
+
setAchievementModalMessage(message);
|
|
180
134
|
}
|
|
181
|
-
};
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
135
|
+
}, [achievedLevels, storageKey]);
|
|
136
|
+
const showAchievementModal = React.useCallback((message) => {
|
|
137
|
+
setAchievementModalMessage(message);
|
|
138
|
+
}, []);
|
|
139
|
+
const showBadgesModal = React.useCallback(() => {
|
|
140
|
+
setShowBadges(true);
|
|
141
|
+
}, []);
|
|
142
|
+
const contextValue = React.useMemo(() => ({
|
|
143
|
+
metric,
|
|
144
|
+
setMetric: (value) => {
|
|
145
|
+
setMetric(value);
|
|
146
|
+
localStorage.setItem(`${storageKey}-metric`, value.toString());
|
|
147
|
+
},
|
|
148
|
+
badges,
|
|
149
|
+
levels,
|
|
150
|
+
achievedLevels,
|
|
151
|
+
handleAchieve,
|
|
152
|
+
showAchievementModal,
|
|
153
|
+
showBadgesModal
|
|
154
|
+
}), [metric, badges, levels, achievedLevels, handleAchieve, showAchievementModal, showBadgesModal, storageKey]);
|
|
155
|
+
return (React.createElement(AchievementContext.Provider, { value: contextValue },
|
|
187
156
|
children,
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}),
|
|
192
|
-
React.createElement(ConfettiWrapper, { show: showConfetti }),
|
|
193
|
-
React.createElement(AchievementModal, { show: !!modalMessage, message: modalMessage, onClose: handleCloseModal })));
|
|
157
|
+
React.createElement(AchievementModal$1, { show: !!achievementModalMessage, message: achievementModalMessage, onClose: () => setAchievementModalMessage('') }),
|
|
158
|
+
React.createElement(BadgesModal$1, { show: showBadges, badges: badges.filter(badge => { var _a; return achievedLevels.includes(((_a = levels.find(level => level.badgeId === badge.id)) === null || _a === void 0 ? void 0 : _a.level) || -1); }), onClose: () => setShowBadges(false) }),
|
|
159
|
+
React.createElement(BadgesButton$1, { onClick: showBadgesModal, position: badgesButtonPosition })));
|
|
194
160
|
};
|
|
195
161
|
const useAchievement = () => {
|
|
196
162
|
const context = React.useContext(AchievementContext);
|
|
@@ -211,10 +177,11 @@ const Achievement = ({ metric, threshold, onAchieve, message, children }) => {
|
|
|
211
177
|
handleAchieve(levelConfig.level, message);
|
|
212
178
|
}
|
|
213
179
|
}
|
|
214
|
-
}, [metric, threshold, onAchieve,
|
|
215
|
-
return React.createElement(
|
|
180
|
+
}, [metric, threshold, onAchieve, achievedLevels, levels, message, setMetric, handleAchieve]);
|
|
181
|
+
return React.createElement(React.Fragment, null, children);
|
|
216
182
|
};
|
|
183
|
+
var Achievement$1 = React.memo(Achievement);
|
|
217
184
|
|
|
218
|
-
exports.Achievement = Achievement;
|
|
185
|
+
exports.Achievement = Achievement$1;
|
|
219
186
|
exports.AchievementProvider = AchievementProvider;
|
|
220
187
|
exports.useAchievement = useAchievement;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { AchievementProvider, useAchievement } from './context/AchievementContext';
|
|
2
2
|
import Achievement from './components/Achievement';
|
|
3
|
-
|
|
3
|
+
import { BadgeConfig } from './badges';
|
|
4
|
+
import { LevelConfig } from './levels';
|
|
5
|
+
export { AchievementProvider, useAchievement, Achievement, BadgeConfig, LevelConfig };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { createContext, useState, useCallback, useMemo, useContext, useEffect } from 'react';
|
|
2
2
|
|
|
3
3
|
const defaultBadges = [
|
|
4
4
|
{
|
|
@@ -16,103 +16,12 @@ const defaultBadges = [
|
|
|
16
16
|
// Add more badges as needed
|
|
17
17
|
];
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const defaultLevels = [
|
|
20
20
|
{ level: 1, threshold: 10, badgeId: 'beginner' },
|
|
21
21
|
{ level: 2, threshold: 50, badgeId: 'intermediate' },
|
|
22
22
|
// Add more levels as needed
|
|
23
23
|
];
|
|
24
24
|
|
|
25
|
-
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
26
|
-
|
|
27
|
-
function getDefaultExportFromCjs (x) {
|
|
28
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
var reactConfetti_min = {exports: {}};
|
|
32
|
-
|
|
33
|
-
(function (module, exports) {
|
|
34
|
-
!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}));
|
|
35
|
-
|
|
36
|
-
} (reactConfetti_min));
|
|
37
|
-
|
|
38
|
-
var reactConfetti_minExports = reactConfetti_min.exports;
|
|
39
|
-
var Confetti = /*@__PURE__*/getDefaultExportFromCjs(reactConfetti_minExports);
|
|
40
|
-
|
|
41
|
-
function on(obj) {
|
|
42
|
-
var args = [];
|
|
43
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
44
|
-
args[_i - 1] = arguments[_i];
|
|
45
|
-
}
|
|
46
|
-
if (obj && obj.addEventListener) {
|
|
47
|
-
obj.addEventListener.apply(obj, args);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function off(obj) {
|
|
51
|
-
var args = [];
|
|
52
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
53
|
-
args[_i - 1] = arguments[_i];
|
|
54
|
-
}
|
|
55
|
-
if (obj && obj.removeEventListener) {
|
|
56
|
-
obj.removeEventListener.apply(obj, args);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
var isBrowser = typeof window !== 'undefined';
|
|
60
|
-
|
|
61
|
-
var useEffectOnce = function (effect) {
|
|
62
|
-
useEffect(effect, []);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
var useUnmount = function (fn) {
|
|
66
|
-
var fnRef = useRef(fn);
|
|
67
|
-
// update the ref each render so if it change the newest callback will be invoked
|
|
68
|
-
fnRef.current = fn;
|
|
69
|
-
useEffectOnce(function () { return function () { return fnRef.current(); }; });
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
var useRafState = function (initialState) {
|
|
73
|
-
var frame = useRef(0);
|
|
74
|
-
var _a = useState(initialState), state = _a[0], setState = _a[1];
|
|
75
|
-
var setRafState = useCallback(function (value) {
|
|
76
|
-
cancelAnimationFrame(frame.current);
|
|
77
|
-
frame.current = requestAnimationFrame(function () {
|
|
78
|
-
setState(value);
|
|
79
|
-
});
|
|
80
|
-
}, []);
|
|
81
|
-
useUnmount(function () {
|
|
82
|
-
cancelAnimationFrame(frame.current);
|
|
83
|
-
});
|
|
84
|
-
return [state, setRafState];
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
var useWindowSize = function (initialWidth, initialHeight) {
|
|
88
|
-
if (initialWidth === void 0) { initialWidth = Infinity; }
|
|
89
|
-
if (initialHeight === void 0) { initialHeight = Infinity; }
|
|
90
|
-
var _a = useRafState({
|
|
91
|
-
width: isBrowser ? window.innerWidth : initialWidth,
|
|
92
|
-
height: isBrowser ? window.innerHeight : initialHeight,
|
|
93
|
-
}), state = _a[0], setState = _a[1];
|
|
94
|
-
useEffect(function () {
|
|
95
|
-
if (isBrowser) {
|
|
96
|
-
var handler_1 = function () {
|
|
97
|
-
setState({
|
|
98
|
-
width: window.innerWidth,
|
|
99
|
-
height: window.innerHeight,
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
on(window, 'resize', handler_1);
|
|
103
|
-
return function () {
|
|
104
|
-
off(window, 'resize', handler_1);
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}, []);
|
|
108
|
-
return state;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const ConfettiWrapper = ({ show }) => {
|
|
112
|
-
const { width, height } = useWindowSize();
|
|
113
|
-
return show ? React.createElement(Confetti, { width: width, height: height }) : null;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
25
|
const AchievementModal = ({ show, message, onClose }) => {
|
|
117
26
|
if (!show)
|
|
118
27
|
return null;
|
|
@@ -138,57 +47,114 @@ const AchievementModal = ({ show, message, onClose }) => {
|
|
|
138
47
|
};
|
|
139
48
|
return (React.createElement(React.Fragment, null,
|
|
140
49
|
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
141
|
-
React.createElement("div", { style: modalStyle },
|
|
142
|
-
React.createElement("h2",
|
|
50
|
+
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "achievement-title" },
|
|
51
|
+
React.createElement("h2", { id: "achievement-title" }, "Achievement Unlocked!"),
|
|
143
52
|
React.createElement("p", null, message),
|
|
144
53
|
React.createElement("button", { onClick: onClose }, "Okay"))));
|
|
145
54
|
};
|
|
55
|
+
var AchievementModal$1 = React.memo(AchievementModal);
|
|
146
56
|
|
|
147
|
-
const
|
|
148
|
-
|
|
57
|
+
const BadgesModal = ({ show, badges, onClose }) => {
|
|
58
|
+
if (!show)
|
|
59
|
+
return null;
|
|
60
|
+
const modalStyle = {
|
|
149
61
|
position: 'fixed',
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
flexDirection: 'column',
|
|
154
|
-
alignItems: 'center',
|
|
62
|
+
top: '50%',
|
|
63
|
+
left: '50%',
|
|
64
|
+
transform: 'translate(-50%, -50%)',
|
|
155
65
|
backgroundColor: '#fff',
|
|
156
|
-
|
|
66
|
+
padding: '20px',
|
|
157
67
|
borderRadius: '8px',
|
|
158
|
-
padding: '10px',
|
|
159
68
|
boxShadow: '0 0 10px rgba(0,0,0,0.1)',
|
|
69
|
+
zIndex: 1000,
|
|
70
|
+
maxWidth: '80%',
|
|
71
|
+
maxHeight: '80%',
|
|
72
|
+
overflow: 'auto',
|
|
73
|
+
};
|
|
74
|
+
const overlayStyle = {
|
|
75
|
+
position: 'fixed',
|
|
76
|
+
top: 0,
|
|
77
|
+
left: 0,
|
|
78
|
+
right: 0,
|
|
79
|
+
bottom: 0,
|
|
80
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
81
|
+
zIndex: 999,
|
|
82
|
+
};
|
|
83
|
+
return (React.createElement(React.Fragment, null,
|
|
84
|
+
React.createElement("div", { style: overlayStyle, onClick: onClose }),
|
|
85
|
+
React.createElement("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "badges-title" },
|
|
86
|
+
React.createElement("h2", { id: "badges-title" }, "Your Achievements"),
|
|
87
|
+
React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'center' } }, badges.map(badge => (React.createElement("div", { key: badge.id, style: { margin: '10px', textAlign: 'center' } },
|
|
88
|
+
React.createElement("img", { src: badge.icon, alt: badge.title, style: { width: '50px', height: '50px' } }),
|
|
89
|
+
React.createElement("h4", null, badge.title),
|
|
90
|
+
React.createElement("p", null, badge.description))))),
|
|
91
|
+
React.createElement("button", { onClick: onClose, style: { marginTop: '20px' } }, "Close"))));
|
|
92
|
+
};
|
|
93
|
+
var BadgesModal$1 = React.memo(BadgesModal);
|
|
94
|
+
|
|
95
|
+
const BadgesButton = ({ onClick, position }) => {
|
|
96
|
+
const buttonStyle = {
|
|
97
|
+
position: 'fixed',
|
|
98
|
+
[position.split('-')[0]]: '20px',
|
|
99
|
+
[position.split('-')[1]]: '20px',
|
|
100
|
+
padding: '10px 20px',
|
|
101
|
+
backgroundColor: '#007bff',
|
|
102
|
+
color: '#fff',
|
|
103
|
+
border: 'none',
|
|
104
|
+
borderRadius: '5px',
|
|
105
|
+
cursor: 'pointer',
|
|
106
|
+
zIndex: 998,
|
|
160
107
|
};
|
|
161
|
-
return (React.createElement("
|
|
162
|
-
React.createElement("img", { src: icon, alt: title, style: { width: '50px', height: '50px' } }),
|
|
163
|
-
React.createElement("h4", null, title),
|
|
164
|
-
React.createElement("p", null, description)));
|
|
108
|
+
return (React.createElement("button", { style: buttonStyle, onClick: onClick }, "View Achievements"));
|
|
165
109
|
};
|
|
110
|
+
var BadgesButton$1 = React.memo(BadgesButton);
|
|
166
111
|
|
|
167
112
|
const AchievementContext = createContext(undefined);
|
|
168
|
-
const AchievementProvider = ({ children }) => {
|
|
169
|
-
const [metric, setMetric] = useState(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
113
|
+
const AchievementProvider = ({ children, initialBadges = defaultBadges, initialLevels = defaultLevels, storageKey = 'react-achievements', badgesButtonPosition = 'top-right' }) => {
|
|
114
|
+
const [metric, setMetric] = useState(() => {
|
|
115
|
+
const saved = localStorage.getItem(`${storageKey}-metric`);
|
|
116
|
+
return saved ? parseInt(saved, 10) : 0;
|
|
117
|
+
});
|
|
118
|
+
const [achievedLevels, setAchievedLevels] = useState(() => {
|
|
119
|
+
const saved = localStorage.getItem(`${storageKey}-levels`);
|
|
120
|
+
return saved ? JSON.parse(saved) : [];
|
|
121
|
+
});
|
|
122
|
+
const [badges] = useState(initialBadges);
|
|
123
|
+
const [levels] = useState(initialLevels);
|
|
124
|
+
const [achievementModalMessage, setAchievementModalMessage] = useState('');
|
|
125
|
+
const [showBadges, setShowBadges] = useState(false);
|
|
126
|
+
const handleAchieve = useCallback((level, message) => {
|
|
174
127
|
if (!achievedLevels.includes(level)) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
128
|
+
const newAchievedLevels = [...achievedLevels, level];
|
|
129
|
+
setAchievedLevels(newAchievedLevels);
|
|
130
|
+
localStorage.setItem(`${storageKey}-levels`, JSON.stringify(newAchievedLevels));
|
|
131
|
+
setAchievementModalMessage(message);
|
|
178
132
|
}
|
|
179
|
-
};
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
133
|
+
}, [achievedLevels, storageKey]);
|
|
134
|
+
const showAchievementModal = useCallback((message) => {
|
|
135
|
+
setAchievementModalMessage(message);
|
|
136
|
+
}, []);
|
|
137
|
+
const showBadgesModal = useCallback(() => {
|
|
138
|
+
setShowBadges(true);
|
|
139
|
+
}, []);
|
|
140
|
+
const contextValue = useMemo(() => ({
|
|
141
|
+
metric,
|
|
142
|
+
setMetric: (value) => {
|
|
143
|
+
setMetric(value);
|
|
144
|
+
localStorage.setItem(`${storageKey}-metric`, value.toString());
|
|
145
|
+
},
|
|
146
|
+
badges,
|
|
147
|
+
levels,
|
|
148
|
+
achievedLevels,
|
|
149
|
+
handleAchieve,
|
|
150
|
+
showAchievementModal,
|
|
151
|
+
showBadgesModal
|
|
152
|
+
}), [metric, badges, levels, achievedLevels, handleAchieve, showAchievementModal, showBadgesModal, storageKey]);
|
|
153
|
+
return (React.createElement(AchievementContext.Provider, { value: contextValue },
|
|
185
154
|
children,
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}),
|
|
190
|
-
React.createElement(ConfettiWrapper, { show: showConfetti }),
|
|
191
|
-
React.createElement(AchievementModal, { show: !!modalMessage, message: modalMessage, onClose: handleCloseModal })));
|
|
155
|
+
React.createElement(AchievementModal$1, { show: !!achievementModalMessage, message: achievementModalMessage, onClose: () => setAchievementModalMessage('') }),
|
|
156
|
+
React.createElement(BadgesModal$1, { show: showBadges, badges: badges.filter(badge => { var _a; return achievedLevels.includes(((_a = levels.find(level => level.badgeId === badge.id)) === null || _a === void 0 ? void 0 : _a.level) || -1); }), onClose: () => setShowBadges(false) }),
|
|
157
|
+
React.createElement(BadgesButton$1, { onClick: showBadgesModal, position: badgesButtonPosition })));
|
|
192
158
|
};
|
|
193
159
|
const useAchievement = () => {
|
|
194
160
|
const context = useContext(AchievementContext);
|
|
@@ -200,7 +166,7 @@ const useAchievement = () => {
|
|
|
200
166
|
|
|
201
167
|
const Achievement = ({ metric, threshold, onAchieve, message, children }) => {
|
|
202
168
|
const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
|
|
203
|
-
|
|
169
|
+
useEffect(() => {
|
|
204
170
|
if (metric >= threshold && !achievedLevels.includes(threshold)) {
|
|
205
171
|
onAchieve();
|
|
206
172
|
const levelConfig = levels.find(level => level.threshold === threshold);
|
|
@@ -209,8 +175,9 @@ const Achievement = ({ metric, threshold, onAchieve, message, children }) => {
|
|
|
209
175
|
handleAchieve(levelConfig.level, message);
|
|
210
176
|
}
|
|
211
177
|
}
|
|
212
|
-
}, [metric, threshold, onAchieve,
|
|
213
|
-
return React.createElement(
|
|
178
|
+
}, [metric, threshold, onAchieve, achievedLevels, levels, message, setMetric, handleAchieve]);
|
|
179
|
+
return React.createElement(React.Fragment, null, children);
|
|
214
180
|
};
|
|
181
|
+
var Achievement$1 = React.memo(Achievement);
|
|
215
182
|
|
|
216
|
-
export { Achievement, AchievementProvider, useAchievement };
|
|
183
|
+
export { Achievement$1 as Achievement, AchievementProvider, useAchievement };
|
package/dist/levels.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
interface LevelConfig {
|
|
1
|
+
export interface LevelConfig {
|
|
2
2
|
level: number;
|
|
3
3
|
threshold: number;
|
|
4
4
|
badgeId: string;
|
|
5
5
|
}
|
|
6
|
-
declare const
|
|
7
|
-
export {
|
|
6
|
+
declare const defaultLevels: LevelConfig[];
|
|
7
|
+
export { defaultLevels };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-achievements",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "This package allows users to transpose a React achievements engine over their React apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"types": "dist/index.d.ts",
|
|
13
13
|
"scripts": {
|
|
14
14
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
15
|
-
"build": "rollup -c"
|
|
15
|
+
"build": "rollup -c",
|
|
16
|
+
"deploy": "npm run build && npm publish"
|
|
16
17
|
},
|
|
17
18
|
"author": "David Brown",
|
|
18
19
|
"license": "ISC",
|
package/src/badges.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
interface BadgeConfig {
|
|
1
|
+
export interface BadgeConfig {
|
|
2
2
|
id: string;
|
|
3
3
|
icon: string;
|
|
4
4
|
title: string;
|
|
@@ -21,4 +21,4 @@ const defaultBadges: BadgeConfig[] = [
|
|
|
21
21
|
// Add more badges as needed
|
|
22
22
|
];
|
|
23
23
|
|
|
24
|
-
export { defaultBadges
|
|
24
|
+
export { defaultBadges };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
2
|
import { useAchievement } from '../context/AchievementContext';
|
|
3
3
|
|
|
4
4
|
interface AchievementProps {
|
|
@@ -12,7 +12,7 @@ interface AchievementProps {
|
|
|
12
12
|
const Achievement: React.FC<AchievementProps> = ({ metric, threshold, onAchieve, message, children }) => {
|
|
13
13
|
const { setMetric, achievedLevels, levels, handleAchieve } = useAchievement();
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
useEffect(() => {
|
|
16
16
|
if (metric >= threshold && !achievedLevels.includes(threshold)) {
|
|
17
17
|
onAchieve();
|
|
18
18
|
const levelConfig = levels.find(level => level.threshold === threshold);
|
|
@@ -21,9 +21,9 @@ const Achievement: React.FC<AchievementProps> = ({ metric, threshold, onAchieve,
|
|
|
21
21
|
handleAchieve(levelConfig.level, message);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
}, [metric, threshold, onAchieve,
|
|
24
|
+
}, [metric, threshold, onAchieve, achievedLevels, levels, message, setMetric, handleAchieve]);
|
|
25
25
|
|
|
26
|
-
return
|
|
26
|
+
return <>{children}</>;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
export default Achievement;
|
|
29
|
+
export default React.memo(Achievement);
|
|
@@ -34,8 +34,8 @@ const AchievementModal: React.FC<AchievementModalProps> = ({ show, message, onCl
|
|
|
34
34
|
return (
|
|
35
35
|
<>
|
|
36
36
|
<div style={overlayStyle} onClick={onClose} />
|
|
37
|
-
<div style={modalStyle}>
|
|
38
|
-
<h2>Achievement Unlocked!</h2>
|
|
37
|
+
<div style={modalStyle} role="dialog" aria-modal="true" aria-labelledby="achievement-title">
|
|
38
|
+
<h2 id="achievement-title">Achievement Unlocked!</h2>
|
|
39
39
|
<p>{message}</p>
|
|
40
40
|
<button onClick={onClose}>Okay</button>
|
|
41
41
|
</div>
|
|
@@ -43,4 +43,4 @@ const AchievementModal: React.FC<AchievementModalProps> = ({ show, message, onCl
|
|
|
43
43
|
);
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
export default AchievementModal;
|
|
46
|
+
export default React.memo(AchievementModal);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface BadgesButtonProps {
|
|
4
|
+
onClick: () => void;
|
|
5
|
+
position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const BadgesButton: React.FC<BadgesButtonProps> = ({ onClick, position }) => {
|
|
9
|
+
const buttonStyle: React.CSSProperties = {
|
|
10
|
+
position: 'fixed',
|
|
11
|
+
[position.split('-')[0]]: '20px',
|
|
12
|
+
[position.split('-')[1]]: '20px',
|
|
13
|
+
padding: '10px 20px',
|
|
14
|
+
backgroundColor: '#007bff',
|
|
15
|
+
color: '#fff',
|
|
16
|
+
border: 'none',
|
|
17
|
+
borderRadius: '5px',
|
|
18
|
+
cursor: 'pointer',
|
|
19
|
+
zIndex: 998,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<button style={buttonStyle} onClick={onClick}>
|
|
24
|
+
View Achievements
|
|
25
|
+
</button>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default React.memo(BadgesButton);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BadgeConfig } from '../badges';
|
|
3
|
+
|
|
4
|
+
interface BadgesModalProps {
|
|
5
|
+
show: boolean;
|
|
6
|
+
badges: BadgeConfig[];
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const BadgesModal: React.FC<BadgesModalProps> = ({ show, badges, onClose }) => {
|
|
11
|
+
if (!show) return null;
|
|
12
|
+
|
|
13
|
+
const modalStyle: React.CSSProperties = {
|
|
14
|
+
position: 'fixed',
|
|
15
|
+
top: '50%',
|
|
16
|
+
left: '50%',
|
|
17
|
+
transform: 'translate(-50%, -50%)',
|
|
18
|
+
backgroundColor: '#fff',
|
|
19
|
+
padding: '20px',
|
|
20
|
+
borderRadius: '8px',
|
|
21
|
+
boxShadow: '0 0 10px rgba(0,0,0,0.1)',
|
|
22
|
+
zIndex: 1000,
|
|
23
|
+
maxWidth: '80%',
|
|
24
|
+
maxHeight: '80%',
|
|
25
|
+
overflow: 'auto',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const overlayStyle: React.CSSProperties = {
|
|
29
|
+
position: 'fixed',
|
|
30
|
+
top: 0,
|
|
31
|
+
left: 0,
|
|
32
|
+
right: 0,
|
|
33
|
+
bottom: 0,
|
|
34
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
35
|
+
zIndex: 999,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<div style={overlayStyle} onClick={onClose} />
|
|
41
|
+
<div style={modalStyle} role="dialog" aria-modal="true" aria-labelledby="badges-title">
|
|
42
|
+
<h2 id="badges-title">Your Achievements</h2>
|
|
43
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center' }}>
|
|
44
|
+
{badges.map(badge => (
|
|
45
|
+
<div key={badge.id} style={{ margin: '10px', textAlign: 'center' }}>
|
|
46
|
+
<img src={badge.icon} alt={badge.title} style={{ width: '50px', height: '50px' }} />
|
|
47
|
+
<h4>{badge.title}</h4>
|
|
48
|
+
<p>{badge.description}</p>
|
|
49
|
+
</div>
|
|
50
|
+
))}
|
|
51
|
+
</div>
|
|
52
|
+
<button onClick={onClose} style={{ marginTop: '20px' }}>Close</button>
|
|
53
|
+
</div>
|
|
54
|
+
</>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default React.memo(BadgesModal);
|
|
@@ -0,0 +1,37 @@
|
|
|
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);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
1
|
+
import React, { createContext, useContext, useState, ReactNode, useCallback, useMemo } from 'react';
|
|
2
2
|
import { defaultBadges, BadgeConfig } from '../badges';
|
|
3
|
-
import {
|
|
4
|
-
import ConfettiWrapper from '../components/ConfettiWrapper';
|
|
3
|
+
import { defaultLevels, LevelConfig } from '../levels';
|
|
5
4
|
import AchievementModal from '../components/AchievementModal';
|
|
6
|
-
import
|
|
5
|
+
import BadgesModal from '../components/BadgesModal';
|
|
6
|
+
import BadgesButton from '../components/BadgesButton';
|
|
7
7
|
|
|
8
8
|
interface AchievementContextProps {
|
|
9
9
|
metric: number;
|
|
@@ -12,54 +12,93 @@ interface AchievementContextProps {
|
|
|
12
12
|
levels: LevelConfig[];
|
|
13
13
|
achievedLevels: number[];
|
|
14
14
|
handleAchieve: (level: number, message: string) => void;
|
|
15
|
+
showAchievementModal: (message: string) => void;
|
|
16
|
+
showBadgesModal: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface AchievementProviderProps {
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
initialBadges?: BadgeConfig[];
|
|
22
|
+
initialLevels?: LevelConfig[];
|
|
23
|
+
storageKey?: string;
|
|
24
|
+
badgesButtonPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
const AchievementContext = createContext<AchievementContextProps | undefined>(undefined);
|
|
18
28
|
|
|
19
|
-
const AchievementProvider: React.FC<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
export const AchievementProvider: React.FC<AchievementProviderProps> = ({
|
|
30
|
+
children,
|
|
31
|
+
initialBadges = defaultBadges,
|
|
32
|
+
initialLevels = defaultLevels,
|
|
33
|
+
storageKey = 'react-achievements',
|
|
34
|
+
badgesButtonPosition = 'top-right'
|
|
35
|
+
}) => {
|
|
36
|
+
const [metric, setMetric] = useState(() => {
|
|
37
|
+
const saved = localStorage.getItem(`${storageKey}-metric`);
|
|
38
|
+
return saved ? parseInt(saved, 10) : 0;
|
|
39
|
+
});
|
|
40
|
+
const [achievedLevels, setAchievedLevels] = useState<number[]>(() => {
|
|
41
|
+
const saved = localStorage.getItem(`${storageKey}-levels`);
|
|
42
|
+
return saved ? JSON.parse(saved) : [];
|
|
43
|
+
});
|
|
44
|
+
const [badges] = useState<BadgeConfig[]>(initialBadges);
|
|
45
|
+
const [levels] = useState<LevelConfig[]>(initialLevels);
|
|
46
|
+
const [achievementModalMessage, setAchievementModalMessage] = useState('');
|
|
47
|
+
const [showBadges, setShowBadges] = useState(false);
|
|
24
48
|
|
|
25
|
-
const handleAchieve = (level: number, message: string) => {
|
|
49
|
+
const handleAchieve = useCallback((level: number, message: string) => {
|
|
26
50
|
if (!achievedLevels.includes(level)) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
const newAchievedLevels = [...achievedLevels, level];
|
|
52
|
+
setAchievedLevels(newAchievedLevels);
|
|
53
|
+
localStorage.setItem(`${storageKey}-levels`, JSON.stringify(newAchievedLevels));
|
|
54
|
+
setAchievementModalMessage(message);
|
|
30
55
|
}
|
|
31
|
-
};
|
|
56
|
+
}, [achievedLevels, storageKey]);
|
|
57
|
+
|
|
58
|
+
const showAchievementModal = useCallback((message: string) => {
|
|
59
|
+
setAchievementModalMessage(message);
|
|
60
|
+
}, []);
|
|
32
61
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
62
|
+
const showBadgesModal = useCallback(() => {
|
|
63
|
+
setShowBadges(true);
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
const contextValue = useMemo(() => ({
|
|
67
|
+
metric,
|
|
68
|
+
setMetric: (value: number) => {
|
|
69
|
+
setMetric(value);
|
|
70
|
+
localStorage.setItem(`${storageKey}-metric`, value.toString());
|
|
71
|
+
},
|
|
72
|
+
badges,
|
|
73
|
+
levels,
|
|
74
|
+
achievedLevels,
|
|
75
|
+
handleAchieve,
|
|
76
|
+
showAchievementModal,
|
|
77
|
+
showBadgesModal
|
|
78
|
+
}), [metric, badges, levels, achievedLevels, handleAchieve, showAchievementModal, showBadgesModal, storageKey]);
|
|
37
79
|
|
|
38
80
|
return (
|
|
39
|
-
<AchievementContext.Provider value={
|
|
81
|
+
<AchievementContext.Provider value={contextValue}>
|
|
40
82
|
{children}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
<
|
|
52
|
-
<AchievementModal show={!!modalMessage} message={modalMessage} onClose={handleCloseModal} />
|
|
83
|
+
<AchievementModal
|
|
84
|
+
show={!!achievementModalMessage}
|
|
85
|
+
message={achievementModalMessage}
|
|
86
|
+
onClose={() => setAchievementModalMessage('')}
|
|
87
|
+
/>
|
|
88
|
+
<BadgesModal
|
|
89
|
+
show={showBadges}
|
|
90
|
+
badges={badges.filter(badge => achievedLevels.includes(levels.find(level => level.badgeId === badge.id)?.level || -1))}
|
|
91
|
+
onClose={() => setShowBadges(false)}
|
|
92
|
+
/>
|
|
93
|
+
<BadgesButton onClick={showBadgesModal} position={badgesButtonPosition} />
|
|
53
94
|
</AchievementContext.Provider>
|
|
54
95
|
);
|
|
55
96
|
};
|
|
56
97
|
|
|
57
|
-
const useAchievement = () => {
|
|
98
|
+
export const useAchievement = () => {
|
|
58
99
|
const context = useContext(AchievementContext);
|
|
59
100
|
if (context === undefined) {
|
|
60
101
|
throw new Error('useAchievement must be used within an AchievementProvider');
|
|
61
102
|
}
|
|
62
103
|
return context;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export { AchievementProvider, useAchievement };
|
|
104
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { AchievementProvider, useAchievement } from './context/AchievementContext';
|
|
2
2
|
import Achievement from './components/Achievement';
|
|
3
|
+
import { BadgeConfig } from './badges';
|
|
4
|
+
import { LevelConfig } from './levels';
|
|
3
5
|
|
|
4
|
-
export { AchievementProvider, useAchievement, Achievement };
|
|
6
|
+
export { AchievementProvider, useAchievement, Achievement, BadgeConfig, LevelConfig };
|
package/src/levels.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
interface LevelConfig {
|
|
1
|
+
export interface LevelConfig {
|
|
2
2
|
level: number;
|
|
3
3
|
threshold: number;
|
|
4
4
|
badgeId: string;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const defaultLevels: LevelConfig[] = [
|
|
8
8
|
{ level: 1, threshold: 10, badgeId: 'beginner' },
|
|
9
9
|
{ level: 2, threshold: 50, badgeId: 'intermediate' },
|
|
10
10
|
// Add more levels as needed
|
|
11
11
|
];
|
|
12
12
|
|
|
13
|
-
export {
|
|
13
|
+
export { defaultLevels };
|
package/src/components/Badge.tsx
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
interface BadgeProps {
|
|
4
|
-
icon: string;
|
|
5
|
-
title: string;
|
|
6
|
-
description: string;
|
|
7
|
-
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const Badge: React.FC<BadgeProps> = ({ icon, title, description, position = 'top-right' }) => {
|
|
11
|
-
const badgeStyle: React.CSSProperties = {
|
|
12
|
-
position: 'fixed',
|
|
13
|
-
[position.split('-')[0]]: '10px',
|
|
14
|
-
[position.split('-')[1]]: '10px',
|
|
15
|
-
display: 'flex',
|
|
16
|
-
flexDirection: 'column',
|
|
17
|
-
alignItems: 'center',
|
|
18
|
-
backgroundColor: '#fff',
|
|
19
|
-
border: '1px solid #ccc',
|
|
20
|
-
borderRadius: '8px',
|
|
21
|
-
padding: '10px',
|
|
22
|
-
boxShadow: '0 0 10px rgba(0,0,0,0.1)',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<div style={badgeStyle}>
|
|
27
|
-
<img src={icon} alt={title} style={{ width: '50px', height: '50px' }} />
|
|
28
|
-
<h4>{title}</h4>
|
|
29
|
-
<p>{description}</p>
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export default Badge;
|