questro
Version:
A lightweight, modular gamification library for React with unique visual components. Features combo meters, daily challenges, achievement toasts, and progress rings. Add points, badges, quests, leaderboards, levels/XP, streaks, and notifications with zero
2 lines • 12.6 kB
JavaScript
'use strict';var chunkPADZRWVT_js=require('./chunk-PADZRWVT.js'),react=require('react'),jsxRuntime=require('react/jsx-runtime');var Q=class{constructor(i=[],t={}){this.events=chunkPADZRWVT_js.a();this.on=this.events.on;this.emit=this.events.emit;this.config={maxActiveQuests:t.maxActiveQuests??5,autoStartQuests:t.autoStartQuests??false},this.state={quests:[...i],activeQuests:i.filter(s=>s.status==="in-progress"),completedQuests:i.filter(s=>s.status==="completed"),lastUpdated:chunkPADZRWVT_js.b()},this.checkExpiredQuests();}notifyStateChange(){this.state.lastUpdated=chunkPADZRWVT_js.b(),this.emit("state-changed",this.state);}checkExpiredQuests(){let i=chunkPADZRWVT_js.b(),t=[];this.state.quests.forEach(s=>{s.status==="in-progress"&&s.expiresAt&&s.expiresAt<i&&(s.status="expired",s.updatedAt=i,t.push(s));}),t.length>0&&(this.state.activeQuests=this.state.activeQuests.filter(s=>!t.some(o=>o.id===s.id)),t.forEach(s=>this.emit("quest-expired",s)),this.notifyStateChange());}getState(){return {quests:[...this.state.quests],activeQuests:[...this.state.activeQuests],completedQuests:[...this.state.completedQuests],lastUpdated:this.state.lastUpdated}}getAllQuests(){return [...this.state.quests]}getQuestById(i){return this.state.quests.find(t=>t.id===i)}getActiveQuests(){return this.checkExpiredQuests(),[...this.state.activeQuests]}getCompletedQuests(){return [...this.state.completedQuests]}getAvailableQuests(){return this.state.quests.filter(i=>i.status==="available")}startQuest(i){let t=this.state.quests.find(s=>s.id===i);return t?t.status!=="available"?{success:false,error:new Error("Quest is not available")}:this.state.activeQuests.length>=this.config.maxActiveQuests?{success:false,error:new Error("Maximum active quests reached")}:(t.status="in-progress",t.startDate=chunkPADZRWVT_js.b(),t.updatedAt=chunkPADZRWVT_js.b(),this.state.activeQuests.push(t),this.emit("quest-started",t),this.notifyStateChange(),{success:true,data:t}):{success:false,error:new Error("Quest not found")}}updateObjectiveProgress(i,t,s){let o=this.state.quests.find(l=>l.id===i);if(!o)return {success:false,error:new Error("Quest not found")};if(o.status!=="in-progress")return {success:false,error:new Error("Quest is not in progress")};let n=o.objectives.find(l=>l.id===t);return n?n.completed?{success:false,error:new Error("Objective already completed")}:(n.current=Math.min(s,n.target),n.current>=n.target&&(n.completed=true,this.emit("objective-completed",{quest:o,objective:n})),o.updatedAt=chunkPADZRWVT_js.b(),this.emit("objective-progress",{quest:o,objective:n}),this.notifyStateChange(),this.checkQuestCompletion(i),{success:true,data:o}):{success:false,error:new Error("Objective not found")}}completeObjective(i,t){let s=this.state.quests.find(n=>n.id===i);if(!s)return {success:false,error:new Error("Quest not found")};let o=s.objectives.find(n=>n.id===t);return o?this.updateObjectiveProgress(i,t,o.target):{success:false,error:new Error("Objective not found")}}checkQuestCompletion(i){let t=this.state.quests.find(o=>o.id===i);return t?t.status!=="in-progress"?{success:true,data:t}:(t.objectives.every(o=>o.completed)&&(t.status="completed",t.completedAt=chunkPADZRWVT_js.b(),t.updatedAt=chunkPADZRWVT_js.b(),this.state.activeQuests=this.state.activeQuests.filter(o=>o.id!==i),this.state.completedQuests.push(t),this.emit("quest-completed",t),this.notifyStateChange()),{success:true,data:t}):{success:false,error:new Error("Quest not found")}}abandonQuest(i){let t=this.state.quests.find(s=>s.id===i);return t?t.status!=="in-progress"?{success:false,error:new Error("Quest is not in progress")}:(t.status="failed",t.updatedAt=chunkPADZRWVT_js.b(),this.state.activeQuests=this.state.activeQuests.filter(s=>s.id!==i),this.emit("quest-failed",t),this.notifyStateChange(),{success:true,data:t}):{success:false,error:new Error("Quest not found")}}resetQuest(i){let t=this.state.quests.find(s=>s.id===i);return t?(t.status="available",t.objectives.forEach(s=>{s.current=0,s.completed=false;}),t.startDate=void 0,t.completedAt=void 0,t.updatedAt=chunkPADZRWVT_js.b(),this.state.activeQuests=this.state.activeQuests.filter(s=>s.id!==i),this.state.completedQuests=this.state.completedQuests.filter(s=>s.id!==i),this.notifyStateChange(),{success:true,data:t}):{success:false,error:new Error("Quest not found")}}addQuest(i){let t={...i,id:chunkPADZRWVT_js.c(),createdAt:chunkPADZRWVT_js.b(),updatedAt:chunkPADZRWVT_js.b()};return this.state.quests.push(t),t.status==="in-progress"?this.state.activeQuests.push(t):t.status==="completed"&&this.state.completedQuests.push(t),this.notifyStateChange(),this.config.autoStartQuests&&t.status==="available"?this.startQuest(t.id):{success:true,data:t}}removeQuest(i){return this.state.quests.some(s=>s.id===i)?(this.state.quests=this.state.quests.filter(s=>s.id!==i),this.state.activeQuests=this.state.activeQuests.filter(s=>s.id!==i),this.state.completedQuests=this.state.completedQuests.filter(s=>s.id!==i),this.notifyStateChange(),{success:true,data:true}):{success:false,error:new Error("Quest not found")}}reset(){this.state={quests:[],activeQuests:[],completedQuests:[],lastUpdated:chunkPADZRWVT_js.b()},this.notifyStateChange();}};var C=react.createContext(null);function V({children:e,quests:i=[],config:t={}}){let s=react.useMemo(()=>new Q(i,t),[]),o=react.useMemo(()=>({service:s}),[s]);return jsxRuntime.jsx(C.Provider,{value:o,children:e})}function E(){let e=react.useContext(C);if(!e)throw new Error("useQuestsContext must be used within QuestsProvider");return e}function G(){let{service:e}=E(),[i,t]=react.useState(e.getAllQuests()),[s,o]=react.useState(e.getActiveQuests()),[n,l]=react.useState(e.getCompletedQuests()),[m,g]=react.useState(e.getAvailableQuests());react.useEffect(()=>{let u=e.on("state-changed",()=>{t(e.getAllQuests()),o(e.getActiveQuests()),l(e.getCompletedQuests()),g(e.getAvailableQuests());});return ()=>u()},[e]);let f=react.useCallback(u=>{e.startQuest(u);},[e]),I=react.useCallback(u=>{e.abandonQuest(u);},[e]),S=react.useCallback((u,h,O)=>{e.updateObjectiveProgress(u,h,O);},[e]),A=react.useCallback((u,h)=>{e.completeObjective(u,h);},[e]),w=react.useCallback(u=>e.getQuestById(u),[e]),j=react.useCallback(u=>{e.resetQuest(u);},[e]),P=react.useCallback(u=>{e.addQuest(u);},[e]),R=react.useCallback(u=>{e.removeQuest(u);},[e]);return {allQuests:i,activeQuests:s,completedQuests:n,availableQuests:m,startQuest:f,abandonQuest:I,updateProgress:S,completeObjective:A,getQuestById:w,resetQuest:j,addQuest:P,removeQuest:R}}function T({quest:e,onStart:i,onAbandon:t,showActions:s=true,className:o=""}){let n=e.objectives.length,l=e.objectives.filter(f=>f.completed).length,m=n>0?Math.round(l/n*100):0,g={easy:"#4ade80",medium:"#fbbf24",hard:"#f87171",expert:"#a78bfa"};return jsxRuntime.jsxs("div",{className:`quest-card ${o}`,style:r.card,children:[jsxRuntime.jsxs("div",{style:r.header,children:[e.icon&&jsxRuntime.jsx("span",{style:r.icon,children:e.icon}),jsxRuntime.jsxs("div",{style:r.headerInfo,children:[jsxRuntime.jsx("h3",{style:r.title,children:e.title}),jsxRuntime.jsx("span",{style:{...r.difficulty,backgroundColor:g[e.difficulty]},children:e.difficulty})]})]}),jsxRuntime.jsx("p",{style:r.description,children:e.description}),jsxRuntime.jsxs("div",{style:r.objectives,children:[jsxRuntime.jsx("h4",{style:r.objectivesTitle,children:"Objectives:"}),e.objectives.map(f=>jsxRuntime.jsx(L,{objective:f},f.id))]}),e.status==="in-progress"&&jsxRuntime.jsxs("div",{style:r.progress,children:[jsxRuntime.jsx("div",{style:r.progressBar,children:jsxRuntime.jsx("div",{style:{...r.progressFill,width:`${m}%`}})}),jsxRuntime.jsxs("span",{style:r.progressText,children:[l,"/",n," completed"]})]}),e.rewards&&jsxRuntime.jsxs("div",{style:r.rewards,children:[jsxRuntime.jsx("span",{style:r.rewardsLabel,children:"Rewards:"}),e.rewards.points&&jsxRuntime.jsxs("span",{style:r.rewardItem,children:["\u{1F3AF} ",e.rewards.points," pts"]}),e.rewards.badgeId&&jsxRuntime.jsx("span",{style:r.rewardItem,children:"\u{1F3C6} Badge"})]}),s&&jsxRuntime.jsxs("div",{style:r.actions,children:[e.status==="available"&&i&&jsxRuntime.jsx("button",{onClick:i,style:{...r.button,...r.buttonStart},children:"Start Quest"}),e.status==="in-progress"&&t&&jsxRuntime.jsx("button",{onClick:t,style:{...r.button,...r.buttonAbandon},children:"Abandon"}),e.status==="completed"&&jsxRuntime.jsx("span",{style:r.statusCompleted,children:"\u2713 Completed"})]})]})}function L({objective:e}){let i=e.target>0?Math.round(e.current/e.target*100):0;return jsxRuntime.jsxs("div",{style:r.objectiveItem,children:[jsxRuntime.jsxs("div",{style:r.objectiveHeader,children:[jsxRuntime.jsxs("span",{style:e.completed?r.objectiveCompleted:r.objectiveText,children:[e.completed?"\u2713":"\u25CB"," ",e.description]}),jsxRuntime.jsxs("span",{style:r.objectiveProgress,children:[e.current,"/",e.target]})]}),!e.completed&&e.target>0&&jsxRuntime.jsx("div",{style:r.objectiveBar,children:jsxRuntime.jsx("div",{style:{...r.objectiveBarFill,width:`${i}%`}})})]})}function K({quests:e,onQuestStart:i,onQuestAbandon:t,showActions:s=true,emptyMessage:o="No quests available",className:n=""}){return e.length===0?jsxRuntime.jsx("div",{style:r.emptyMessage,children:o}):jsxRuntime.jsx("div",{className:`quest-list ${n}`,style:r.list,children:e.map(l=>jsxRuntime.jsx(T,{quest:l,onStart:i?()=>i(l.id):void 0,onAbandon:t?()=>t(l.id):void 0,showActions:s},l.id))})}function X({activeCount:e,completedCount:i,availableCount:t,className:s=""}){return jsxRuntime.jsxs("div",{className:`quest-stats ${s}`,style:r.stats,children:[jsxRuntime.jsxs("div",{style:r.statItem,children:[jsxRuntime.jsx("span",{style:r.statValue,children:e}),jsxRuntime.jsx("span",{style:r.statLabel,children:"Active"})]}),jsxRuntime.jsxs("div",{style:r.statItem,children:[jsxRuntime.jsx("span",{style:r.statValue,children:i}),jsxRuntime.jsx("span",{style:r.statLabel,children:"Completed"})]}),jsxRuntime.jsxs("div",{style:r.statItem,children:[jsxRuntime.jsx("span",{style:r.statValue,children:t}),jsxRuntime.jsx("span",{style:r.statLabel,children:"Available"})]})]})}var r={card:{border:"1px solid #e5e7eb",borderRadius:"8px",padding:"16px",marginBottom:"12px",backgroundColor:"#ffffff"},header:{display:"flex",alignItems:"center",marginBottom:"12px"},icon:{fontSize:"32px",marginRight:"12px"},headerInfo:{flex:1,display:"flex",alignItems:"center",justifyContent:"space-between"},title:{margin:0,fontSize:"18px",fontWeight:600},difficulty:{padding:"4px 8px",borderRadius:"4px",fontSize:"12px",fontWeight:600,color:"#ffffff",textTransform:"capitalize"},description:{margin:"0 0 16px 0",color:"#6b7280",fontSize:"14px"},objectives:{marginBottom:"16px"},objectivesTitle:{margin:"0 0 8px 0",fontSize:"14px",fontWeight:600},objectiveItem:{marginBottom:"8px"},objectiveHeader:{display:"flex",justifyContent:"space-between",marginBottom:"4px"},objectiveText:{fontSize:"14px",color:"#374151"},objectiveCompleted:{fontSize:"14px",color:"#10b981",textDecoration:"line-through"},objectiveProgress:{fontSize:"14px",color:"#6b7280"},objectiveBar:{height:"4px",backgroundColor:"#e5e7eb",borderRadius:"2px",overflow:"hidden"},objectiveBarFill:{height:"100%",backgroundColor:"#3b82f6",transition:"width 0.3s ease"},progress:{marginBottom:"16px"},progressBar:{height:"8px",backgroundColor:"#e5e7eb",borderRadius:"4px",overflow:"hidden",marginBottom:"4px"},progressFill:{height:"100%",backgroundColor:"#10b981",transition:"width 0.3s ease"},progressText:{fontSize:"12px",color:"#6b7280"},rewards:{display:"flex",alignItems:"center",gap:"8px",marginBottom:"16px",padding:"8px",backgroundColor:"#fef3c7",borderRadius:"4px"},rewardsLabel:{fontSize:"14px",fontWeight:600},rewardItem:{fontSize:"14px"},actions:{display:"flex",gap:"8px"},button:{padding:"8px 16px",borderRadius:"6px",border:"none",fontSize:"14px",fontWeight:600,cursor:"pointer",transition:"all 0.2s"},buttonStart:{backgroundColor:"#3b82f6",color:"#ffffff"},buttonAbandon:{backgroundColor:"#ef4444",color:"#ffffff"},statusCompleted:{color:"#10b981",fontWeight:600,fontSize:"14px"},list:{display:"flex",flexDirection:"column"},emptyMessage:{textAlign:"center",padding:"32px",color:"#9ca3af",fontSize:"14px"},stats:{display:"flex",gap:"16px",padding:"16px",backgroundColor:"#f9fafb",borderRadius:"8px",marginBottom:"16px"},statItem:{flex:1,display:"flex",flexDirection:"column",alignItems:"center"},statValue:{fontSize:"24px",fontWeight:700,color:"#111827"},statLabel:{fontSize:"12px",color:"#6b7280",textTransform:"uppercase",marginTop:"4px"}};exports.a=Q;exports.b=V;exports.c=E;exports.d=G;exports.e=T;exports.f=K;exports.g=X;//# sourceMappingURL=chunk-7USSAWNV.js.map
//# sourceMappingURL=chunk-7USSAWNV.js.map