@popp0102/questify 0.10.0 → 0.10.1
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/questify.js +44 -49
- package/dist/questify.js.map +1 -1
- package/package.json +1 -1
package/dist/questify.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as
|
|
1
|
+
import { jsx as m } from "react/jsx-runtime";
|
|
2
2
|
import { createContext as Q, useState as O, useEffect as q, useContext as B } from "react";
|
|
3
3
|
const I = {}, F = {
|
|
4
4
|
store: async (i, t) => {
|
|
@@ -7,8 +7,8 @@ const I = {}, F = {
|
|
|
7
7
|
load: async (i) => I[i]
|
|
8
8
|
};
|
|
9
9
|
class y {
|
|
10
|
-
constructor(t, e,
|
|
11
|
-
this.id = t, this.type = e, this.title =
|
|
10
|
+
constructor(t, e, r, l, a) {
|
|
11
|
+
this.id = t, this.type = e, this.title = r, this.solution = l, this.blueprint = a, this.isSolved = !1;
|
|
12
12
|
}
|
|
13
13
|
clone({ isSolved: t }) {
|
|
14
14
|
const e = Object.create(y.prototype);
|
|
@@ -21,18 +21,18 @@ class y {
|
|
|
21
21
|
class v {
|
|
22
22
|
constructor(t) {
|
|
23
23
|
this.id = t.id, this.name = t.name, this.icon = t.icon, this.subtitle = t.subtitle, this.description = t.description, this.trials = t.trials.map(
|
|
24
|
-
(e,
|
|
24
|
+
(e, r) => new y(r, e.type, e.title, e.solution, e.blueprint)
|
|
25
25
|
), this.updateStatus();
|
|
26
26
|
}
|
|
27
|
-
static constructFromTrials(t, e,
|
|
28
|
-
const
|
|
29
|
-
return
|
|
27
|
+
static constructFromTrials(t, e, r, l, a, n) {
|
|
28
|
+
const s = Object.create(v.prototype);
|
|
29
|
+
return s.id = t, s.name = e, s.icon = l, s.subtitle = a, s.description = n, s.trials = r, s.updateStatus(), s;
|
|
30
30
|
}
|
|
31
31
|
submitAnswer(t, e) {
|
|
32
|
-
const
|
|
33
|
-
if (!
|
|
32
|
+
const r = this.trials.find((l) => l.id === t);
|
|
33
|
+
if (!r)
|
|
34
34
|
return null;
|
|
35
|
-
if (
|
|
35
|
+
if (r.solution === e.trim().toLowerCase()) {
|
|
36
36
|
const l = this.trials.map(
|
|
37
37
|
(a) => a.id === t ? a.markAsSolved() : a
|
|
38
38
|
);
|
|
@@ -42,9 +42,9 @@ class v {
|
|
|
42
42
|
}
|
|
43
43
|
updateStatus() {
|
|
44
44
|
const t = this.trials.filter((l) => l.isSolved).length, e = this.trials.length;
|
|
45
|
-
let
|
|
46
|
-
t === 0 ?
|
|
47
|
-
status:
|
|
45
|
+
let r;
|
|
46
|
+
t === 0 ? r = "not-started" : t === e ? r = "completed" : r = "in-progress", this.progressSummary = {
|
|
47
|
+
status: r,
|
|
48
48
|
solvedCount: t,
|
|
49
49
|
totalTrials: e,
|
|
50
50
|
percentageComplete: e > 0 ? t / e * 100 : 0
|
|
@@ -93,7 +93,7 @@ class H {
|
|
|
93
93
|
return e.activeTrialIndex = t, e;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
-
const
|
|
96
|
+
const x = Q({
|
|
97
97
|
hunts: [],
|
|
98
98
|
playerLocation: null,
|
|
99
99
|
activeHunt: () => null,
|
|
@@ -113,12 +113,12 @@ const g = Q({
|
|
|
113
113
|
}
|
|
114
114
|
});
|
|
115
115
|
function R({ huntConfigs: i, persister: t, children: e }) {
|
|
116
|
-
const
|
|
116
|
+
const r = t || F, [l, a] = O(i.map((o) => new v(o))), [n, s] = O(new H());
|
|
117
117
|
q(() => {
|
|
118
118
|
async function o() {
|
|
119
119
|
const d = await Promise.all(
|
|
120
120
|
i.map(async (u) => {
|
|
121
|
-
const
|
|
121
|
+
const T = `questify-${u.id}-solved-trials`, p = await r.load(T), S = new v(u);
|
|
122
122
|
if (p) {
|
|
123
123
|
const f = JSON.parse(p), h = S.trials.map((w) => f.includes(w.id) ? w.markAsSolved() : w);
|
|
124
124
|
return v.constructFromTrials(u.id, u.name, h);
|
|
@@ -129,7 +129,7 @@ function R({ huntConfigs: i, persister: t, children: e }) {
|
|
|
129
129
|
a(d);
|
|
130
130
|
}
|
|
131
131
|
o();
|
|
132
|
-
}, [
|
|
132
|
+
}, [r, i]);
|
|
133
133
|
function c() {
|
|
134
134
|
return n.activeHuntId === null ? null : l.find((o) => o.id === n.activeHuntId) || null;
|
|
135
135
|
}
|
|
@@ -137,7 +137,7 @@ function R({ huntConfigs: i, persister: t, children: e }) {
|
|
|
137
137
|
const o = c();
|
|
138
138
|
return !o || n.activeTrialIndex === null ? null : o.trials[n.activeTrialIndex] || null;
|
|
139
139
|
}
|
|
140
|
-
function
|
|
140
|
+
function g() {
|
|
141
141
|
return n.isOnHuntSelection();
|
|
142
142
|
}
|
|
143
143
|
function C() {
|
|
@@ -149,13 +149,13 @@ function R({ huntConfigs: i, persister: t, children: e }) {
|
|
|
149
149
|
function L(o) {
|
|
150
150
|
if (!l.find((u) => u.id === o))
|
|
151
151
|
throw new Error(`Hunt with id "${o}" not found`);
|
|
152
|
-
|
|
152
|
+
s(n.moveToHunt(o));
|
|
153
153
|
}
|
|
154
154
|
function P() {
|
|
155
|
-
|
|
155
|
+
s(n.moveToHuntSelection());
|
|
156
156
|
}
|
|
157
157
|
function k() {
|
|
158
|
-
|
|
158
|
+
s(n.moveToTrialSelectScreen());
|
|
159
159
|
}
|
|
160
160
|
function $(o) {
|
|
161
161
|
const d = c();
|
|
@@ -163,18 +163,18 @@ function R({ huntConfigs: i, persister: t, children: e }) {
|
|
|
163
163
|
throw new Error("Cannot move to trial when no hunt is selected");
|
|
164
164
|
if (o < 0 || o >= d.trials.length)
|
|
165
165
|
throw new Error(`Trial index ${o} is out of bounds for hunt "${d.id}"`);
|
|
166
|
-
|
|
166
|
+
s(n.moveToTrialScreen(o));
|
|
167
167
|
}
|
|
168
168
|
async function j(o) {
|
|
169
169
|
const d = b(), u = c();
|
|
170
170
|
if (!d || !u)
|
|
171
171
|
return !1;
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
174
|
-
const p = l.map((h) => h.id === u.id ?
|
|
172
|
+
const T = u.submitAnswer(d.id, o);
|
|
173
|
+
if (T) {
|
|
174
|
+
const p = l.map((h) => h.id === u.id ? T : h);
|
|
175
175
|
a(p);
|
|
176
|
-
const S = `questify-${u.id}-solved-trials`, f =
|
|
177
|
-
return await
|
|
176
|
+
const S = `questify-${u.id}-solved-trials`, f = T.trials.filter((h) => h.isSolved).map((h) => h.id);
|
|
177
|
+
return await r.store(S, JSON.stringify(f)), !0;
|
|
178
178
|
}
|
|
179
179
|
return !1;
|
|
180
180
|
}
|
|
@@ -183,7 +183,7 @@ function R({ huntConfigs: i, persister: t, children: e }) {
|
|
|
183
183
|
playerLocation: n,
|
|
184
184
|
activeHunt: c,
|
|
185
185
|
activeTrial: b,
|
|
186
|
-
isOnHuntSelection:
|
|
186
|
+
isOnHuntSelection: g,
|
|
187
187
|
isOnTrialSelection: C,
|
|
188
188
|
isOnActiveTrial: E,
|
|
189
189
|
activateHunt: L,
|
|
@@ -192,7 +192,7 @@ function R({ huntConfigs: i, persister: t, children: e }) {
|
|
|
192
192
|
moveToTrialScreen: $,
|
|
193
193
|
submitAnswer: j
|
|
194
194
|
};
|
|
195
|
-
return /* @__PURE__ */
|
|
195
|
+
return /* @__PURE__ */ m(x.Provider, { value: N, children: e });
|
|
196
196
|
}
|
|
197
197
|
class J {
|
|
198
198
|
constructor() {
|
|
@@ -208,26 +208,21 @@ class J {
|
|
|
208
208
|
return this.registry.has(t);
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
-
const
|
|
211
|
+
const A = new J();
|
|
212
212
|
function V() {
|
|
213
|
-
const i = B(
|
|
213
|
+
const i = B(x);
|
|
214
214
|
if (!i.hunts || i.hunts.length === 0)
|
|
215
215
|
throw new Error("No hunts found. Make sure you pass huntConfigs to the QuestifyProvider");
|
|
216
|
-
function t(
|
|
216
|
+
function t(r, l, a) {
|
|
217
217
|
if (i.isOnHuntSelection()) {
|
|
218
|
-
const n = i.hunts.map((
|
|
219
|
-
|
|
220
|
-
name: r.name,
|
|
221
|
-
progressSummary: r.progressSummary,
|
|
222
|
-
onSelectHunt: () => i.activateHunt(r.id)
|
|
223
|
-
}));
|
|
224
|
-
return /* @__PURE__ */ T(s, { hunts: n });
|
|
218
|
+
const n = i.hunts.map((s) => ({ ...s, onSelectHunt: () => i.activateHunt(s.id) }));
|
|
219
|
+
return /* @__PURE__ */ m(r, { hunts: n });
|
|
225
220
|
}
|
|
226
221
|
if (i.isOnTrialSelection()) {
|
|
227
222
|
const n = i.activeHunt();
|
|
228
223
|
if (!n)
|
|
229
224
|
throw new Error("Cannot render trial selection without an active hunt");
|
|
230
|
-
const
|
|
225
|
+
const s = n.trials.map((c) => ({
|
|
231
226
|
id: c.id,
|
|
232
227
|
title: c.title,
|
|
233
228
|
type: c.type,
|
|
@@ -235,11 +230,11 @@ function V() {
|
|
|
235
230
|
solution: c.solution,
|
|
236
231
|
onSelectTrial: () => i.moveToTrialScreen(c.id)
|
|
237
232
|
}));
|
|
238
|
-
return /* @__PURE__ */
|
|
233
|
+
return /* @__PURE__ */ m(
|
|
239
234
|
l,
|
|
240
235
|
{
|
|
241
236
|
hunt: n,
|
|
242
|
-
trials:
|
|
237
|
+
trials: s,
|
|
243
238
|
onBack: i.moveToHuntSelection
|
|
244
239
|
}
|
|
245
240
|
);
|
|
@@ -248,23 +243,23 @@ function V() {
|
|
|
248
243
|
const n = i.activeTrial();
|
|
249
244
|
if (!n)
|
|
250
245
|
throw new Error("Cannot render trial screen without an active trial");
|
|
251
|
-
const
|
|
252
|
-
if (!
|
|
246
|
+
const s = A.get(n.type);
|
|
247
|
+
if (!s)
|
|
253
248
|
throw new Error(`No trial component registered for type: ${n.type}`);
|
|
254
|
-
return /* @__PURE__ */
|
|
249
|
+
return /* @__PURE__ */ m(
|
|
255
250
|
a,
|
|
256
251
|
{
|
|
257
252
|
title: n.title,
|
|
258
253
|
onBack: i.moveToTrialSelectScreen,
|
|
259
254
|
isSolved: n.isSolved,
|
|
260
|
-
TrialComponent: () => /* @__PURE__ */
|
|
255
|
+
TrialComponent: () => /* @__PURE__ */ m(s, { ...n.blueprint, title: n.title })
|
|
261
256
|
}
|
|
262
257
|
);
|
|
263
258
|
}
|
|
264
259
|
throw new Error("Invalid player location state");
|
|
265
260
|
}
|
|
266
|
-
function e(
|
|
267
|
-
return i.submitAnswer(
|
|
261
|
+
function e(r) {
|
|
262
|
+
return i.submitAnswer(r);
|
|
268
263
|
}
|
|
269
264
|
return {
|
|
270
265
|
renderScreen: t,
|
|
@@ -272,7 +267,7 @@ function V() {
|
|
|
272
267
|
};
|
|
273
268
|
}
|
|
274
269
|
const z = (i, t) => {
|
|
275
|
-
|
|
270
|
+
A.register(i, t);
|
|
276
271
|
};
|
|
277
272
|
export {
|
|
278
273
|
R as QuestifyProvider,
|
package/dist/questify.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questify.js","sources":["../lib/store/MemoryPersister.ts","../lib/models/Trial.ts","../lib/models/Hunt.ts","../lib/models/PlayerLocation.ts","../lib/store/QuestifyContext.tsx","../lib/registry/TrialRegistry.ts","../lib/hooks/useQuestify.tsx","../lib/index.ts"],"sourcesContent":["const storage = {};\nexport const memoryPersister = {\n store: async (key, value) => {\n storage[key] = value;\n },\n load: async (key) => {\n return storage[key];\n },\n};\n","class Trial {\n id: number;\n type: string;\n title: string;\n solution: string;\n blueprint: Record<string, any>;\n isSolved: boolean;\n\n constructor(id: number, type: string, title: string, solution: string, blueprint: Record<string, any>) {\n this.id = id;\n this.type = type;\n this.title = title;\n this.solution = solution;\n this.blueprint = blueprint;\n this.isSolved = false;\n }\n\n private clone({ isSolved }: { isSolved: boolean }): Trial {\n const cloned = Object.create(Trial.prototype);\n cloned.id = this.id;\n cloned.type = this.type;\n cloned.title = this.title;\n cloned.solution = this.solution;\n cloned.blueprint = this.blueprint;\n cloned.isSolved = isSolved;\n return cloned;\n }\n\n markAsSolved(): Trial {\n return this.clone({ isSolved: true });\n }\n}\n\nexport default Trial;\n","import Trial from '@models/Trial';\n\nenum HuntStatus {\n NOT_STARTED = 'not-started',\n IN_PROGRESS = 'in-progress',\n COMPLETED = 'completed'\n}\n\ninterface TrialConfig {\n type: string;\n title: string;\n solution: string;\n blueprint: Record<string, any>;\n}\n\ninterface HuntConfig {\n id: string;\n name: string;\n icon?: string;\n subtitle?: string;\n description?: string;\n trials: TrialConfig[];\n}\n\ninterface ProgressSummary {\n status: HuntStatus;\n solvedCount: number;\n totalTrials: number;\n percentageComplete: number;\n}\n\nclass Hunt {\n id: string;\n name: string;\n icon?: string;\n subtitle?: string;\n description?: string;\n trials: Trial[];\n progressSummary: ProgressSummary;\n\n constructor(config: HuntConfig) {\n this.id = config.id;\n this.name = config.name;\n this.icon = config.icon;\n this.subtitle = config.subtitle;\n this.description = config.description;\n this.trials = config.trials.map((trialConfig, index) =>\n new Trial(index, trialConfig.type, trialConfig.title, trialConfig.solution, trialConfig.blueprint)\n );\n this.updateStatus();\n }\n\n static constructFromTrials(id: string, name: string, trials: Trial[], icon?: string, subtitle?: string, description?: string): Hunt {\n const hunt = Object.create(Hunt.prototype);\n hunt.id = id;\n hunt.name = name;\n hunt.icon = icon;\n hunt.subtitle = subtitle;\n hunt.description = description;\n hunt.trials = trials;\n hunt.updateStatus();\n return hunt;\n }\n\n submitAnswer(trialId: number, answer: string): Hunt | null {\n const trial = this.trials.find(trial => trial.id === trialId);\n\n if (!trial) {\n return null;\n }\n\n if (trial.solution === answer.trim().toLowerCase()) {\n const updatedTrials = this.trials.map(trial =>\n trial.id === trialId ? trial.markAsSolved() : trial\n );\n return this.clone({ trials: updatedTrials });\n }\n\n return null;\n }\n\n private updateStatus(): void {\n const solvedCount = this.trials.filter(trial => trial.isSolved).length;\n const totalTrials = this.trials.length;\n\n let status: HuntStatus;\n if (solvedCount === 0) {\n status = HuntStatus.NOT_STARTED;\n } else if (solvedCount === totalTrials) {\n status = HuntStatus.COMPLETED;\n } else {\n status = HuntStatus.IN_PROGRESS;\n }\n\n this.progressSummary = {\n status,\n solvedCount,\n totalTrials,\n percentageComplete: totalTrials > 0 ? (solvedCount / totalTrials) * 100 : 0\n };\n }\n\n private clone(updates: Partial<{ trials: Trial[] }>): Hunt {\n const cloned = Object.create(Hunt.prototype);\n cloned.id = this.id;\n cloned.name = this.name;\n cloned.icon = this.icon;\n cloned.subtitle = this.subtitle;\n cloned.description = this.description;\n cloned.trials = updates.trials ?? this.trials;\n cloned.updateStatus();\n return cloned;\n }\n}\n\nexport default Hunt;\n","class PlayerLocation {\n activeHuntId: string | null;\n activeTrialIndex: number | null;\n\n constructor(huntId: string | null = null, trialIndex: number | null = null) {\n this.activeHuntId = huntId;\n this.activeTrialIndex = trialIndex;\n }\n\n private clone(): PlayerLocation {\n const cloned = Object.create(PlayerLocation.prototype);\n cloned.activeHuntId = this.activeHuntId;\n cloned.activeTrialIndex = this.activeTrialIndex;\n return cloned;\n }\n\n isOnHuntSelection(): boolean {\n return this.activeHuntId === null;\n }\n\n isOnTrialSelection(): boolean {\n return this.activeHuntId !== null && this.activeTrialIndex === null;\n }\n\n isOnActiveTrial(): boolean {\n return this.activeHuntId !== null && this.activeTrialIndex !== null;\n }\n\n moveToHuntSelection(): PlayerLocation {\n const newLocation = this.clone();\n newLocation.activeHuntId = null;\n newLocation.activeTrialIndex = null;\n return newLocation;\n }\n\n moveToHunt(huntId: string): PlayerLocation {\n const newLocation = this.clone();\n newLocation.activeHuntId = huntId;\n newLocation.activeTrialIndex = null;\n return newLocation;\n }\n\n moveToTrialSelectScreen(): PlayerLocation {\n if (this.activeHuntId === null) {\n throw new Error('Cannot move to trial select when no hunt is active');\n }\n\n const newLocation = this.clone();\n newLocation.activeTrialIndex = null;\n return newLocation;\n }\n\n moveToTrialScreen(trialIdx: number): PlayerLocation {\n if (this.activeHuntId === null) {\n throw new Error('Cannot move to trial when no hunt is active');\n }\n\n const newLocation = this.clone();\n newLocation.activeTrialIndex = trialIdx;\n return newLocation;\n }\n}\n\nexport default PlayerLocation;\n","import { useState, useEffect, createContext } from \"react\";\nimport { memoryPersister } from '@store/MemoryPersister';\nimport Hunt from '@models/Hunt';\nimport PlayerLocation from '@models/PlayerLocation';\n\nexport const QuestifyContext = createContext({\n hunts: [],\n playerLocation: null,\n activeHunt: () => null,\n activeTrial: () => null,\n isOnHuntSelection: () => false,\n isOnTrialSelection: () => false,\n isOnActiveTrial: () => false,\n activateHunt: () => {},\n moveToHuntSelection: () => {},\n moveToTrialSelectScreen: () => {},\n moveToTrialScreen: () => {},\n submitAnswer: () => {},\n});\n\nexport default function QuestifyProvider({ huntConfigs, persister, children }) {\n const progressPersister = persister || memoryPersister;\n const [hunts, setHunts] = useState(huntConfigs.map(config => new Hunt(config)));\n const [playerLocation, setPlayerLocation] = useState(new PlayerLocation());\n\n useEffect(() => {\n async function loadProgress() {\n const restoredHunts = await Promise.all(\n huntConfigs.map(async (config) => {\n const storageKey = `questify-${config.id}-solved-trials`;\n const savedTrialsStr = await progressPersister.load(storageKey);\n const restoredHunt = new Hunt(config);\n\n if (savedTrialsStr) {\n const solvedTrialIds = JSON.parse(savedTrialsStr);\n const updatedTrials = restoredHunt.trials.map(trial => solvedTrialIds.includes(trial.id) ? trial.markAsSolved() : trial);\n return Hunt.constructFromTrials(config.id, config.name, updatedTrials);\n }\n\n return restoredHunt;\n })\n );\n\n setHunts(restoredHunts);\n }\n\n loadProgress();\n }, [progressPersister, huntConfigs]);\n\n function activeHunt() {\n if (playerLocation.activeHuntId === null) {\n return null;\n }\n return hunts.find(hunt => hunt.id === playerLocation.activeHuntId) || null;\n }\n\n function activeTrial() {\n const hunt = activeHunt();\n if (!hunt || playerLocation.activeTrialIndex === null) {\n return null;\n }\n return hunt.trials[playerLocation.activeTrialIndex] || null;\n }\n\n function isOnHuntSelection() {\n return playerLocation.isOnHuntSelection();\n }\n\n function isOnTrialSelection() {\n return playerLocation.isOnTrialSelection();\n }\n\n function isOnActiveTrial() {\n return playerLocation.isOnActiveTrial();\n }\n\n function activateHunt(huntId) {\n const hunt = hunts.find(hunt => hunt.id === huntId);\n if (!hunt) {\n throw new Error(`Hunt with id \"${huntId}\" not found`);\n }\n setPlayerLocation(playerLocation.moveToHunt(huntId));\n }\n\n function moveToHuntSelection() {\n setPlayerLocation(playerLocation.moveToHuntSelection());\n }\n\n function moveToTrialSelectScreen() {\n setPlayerLocation(playerLocation.moveToTrialSelectScreen());\n }\n\n function moveToTrialScreen(trialIdx) {\n const hunt = activeHunt();\n if (!hunt) {\n throw new Error('Cannot move to trial when no hunt is selected');\n }\n if (trialIdx < 0 || trialIdx >= hunt.trials.length) {\n throw new Error(`Trial index ${trialIdx} is out of bounds for hunt \"${hunt.id}\"`);\n }\n setPlayerLocation(playerLocation.moveToTrialScreen(trialIdx));\n }\n\n async function handleSubmitAnswer(answer) {\n const trial = activeTrial();\n const currentHunt = activeHunt();\n\n if (!trial || !currentHunt) {\n return false;\n }\n\n const newHunt = currentHunt.submitAnswer(trial.id, answer);\n\n if (newHunt) {\n const updatedHunts = hunts.map(hunt => hunt.id === currentHunt.id ? newHunt : hunt);\n setHunts(updatedHunts);\n\n const storageKey = `questify-${currentHunt.id}-solved-trials`;\n const solvedTrialIds = newHunt.trials.filter(trial => trial.isSolved).map(trial => trial.id);\n await progressPersister.store(storageKey, JSON.stringify(solvedTrialIds));\n return true;\n }\n\n return false;\n }\n\n const questifyCtxValue = {\n hunts: hunts,\n playerLocation: playerLocation,\n activeHunt: activeHunt,\n activeTrial: activeTrial,\n isOnHuntSelection: isOnHuntSelection,\n isOnTrialSelection: isOnTrialSelection,\n isOnActiveTrial: isOnActiveTrial,\n activateHunt: activateHunt,\n moveToHuntSelection: moveToHuntSelection,\n moveToTrialSelectScreen: moveToTrialSelectScreen,\n moveToTrialScreen: moveToTrialScreen,\n submitAnswer: handleSubmitAnswer,\n };\n\n return (\n <QuestifyContext.Provider value={questifyCtxValue}>\n {children}\n </QuestifyContext.Provider>\n );\n}\n","type TrialComponent = React.ComponentType<any>;\n\nclass TrialRegistry {\n private registry: Map<string, TrialComponent> = new Map();\n\n register(type: string, component: TrialComponent): void {\n this.registry.set(type, component);\n }\n\n get(type: string): TrialComponent | undefined {\n return this.registry.get(type);\n }\n\n has(type: string): boolean {\n return this.registry.has(type);\n }\n}\n\nexport const trialRegistry = new TrialRegistry();\n","import { useContext } from \"react\";\nimport { QuestifyContext } from \"@store/QuestifyContext\";\nimport { trialRegistry } from \"@registry/TrialRegistry\";\n\nexport function useQuestify() {\n const context = useContext(QuestifyContext);\n\n if (!context.hunts || context.hunts.length === 0) {\n throw new Error(\"No hunts found. Make sure you pass huntConfigs to the QuestifyProvider\");\n }\n\n function renderScreen(HuntSelectComponent, TrialSelectComponent, TrialScreenComponent) {\n if (context.isOnHuntSelection()) {\n const hunts = context.hunts.map((hunt) => ({\n id: hunt.id,\n name: hunt.name,\n progressSummary: hunt.progressSummary,\n onSelectHunt: () => context.activateHunt(hunt.id)\n }));\n return <HuntSelectComponent hunts={hunts} />;\n }\n\n if (context.isOnTrialSelection()) {\n const activeHunt = context.activeHunt();\n if (!activeHunt) {\n throw new Error(\"Cannot render trial selection without an active hunt\");\n }\n\n const trials = activeHunt.trials.map((trial) => ({\n id: trial.id,\n title: trial.title,\n type: trial.type,\n isSolved: trial.isSolved,\n solution: trial.solution,\n onSelectTrial: () => context.moveToTrialScreen(trial.id)\n }));\n\n return <TrialSelectComponent\n hunt={activeHunt}\n trials={trials}\n onBack={context.moveToHuntSelection}\n />;\n }\n\n if (context.isOnActiveTrial()) {\n const trial = context.activeTrial();\n if (!trial) {\n throw new Error(\"Cannot render trial screen without an active trial\");\n }\n\n const TrialComponent = trialRegistry.get(trial.type);\n\n if (!TrialComponent) {\n throw new Error(`No trial component registered for type: ${trial.type}`);\n }\n\n return <TrialScreenComponent\n title={trial.title}\n onBack={context.moveToTrialSelectScreen}\n isSolved={trial.isSolved} \n TrialComponent={() => <TrialComponent {...trial.blueprint} title={trial.title}/>}\n />;\n }\n\n throw new Error(\"Invalid player location state\");\n }\n\n function submitAnswer(answer) {\n return context.submitAnswer(answer);\n }\n\n return {\n renderScreen: renderScreen,\n submitAnswer: submitAnswer,\n };\n}\n","import { useQuestify } from '@hooks/useQuestify';\nimport QuestifyProvider from '@store/QuestifyContext';\nimport { trialRegistry } from '@registry/TrialRegistry';\n\nexport const registerTrialComponent = (type: string, component: React.ComponentType<any>) => {\n trialRegistry.register(type, component);\n};\n\nexport { QuestifyProvider, useQuestify };\n"],"names":["storage","memoryPersister","key","value","Trial","id","type","title","solution","blueprint","isSolved","cloned","Hunt","config","trialConfig","index","name","trials","icon","subtitle","description","hunt","trialId","answer","trial","updatedTrials","solvedCount","totalTrials","status","updates","PlayerLocation","huntId","trialIndex","newLocation","trialIdx","QuestifyContext","createContext","QuestifyProvider","huntConfigs","persister","children","progressPersister","hunts","setHunts","useState","playerLocation","setPlayerLocation","useEffect","loadProgress","restoredHunts","storageKey","savedTrialsStr","restoredHunt","solvedTrialIds","activeHunt","activeTrial","isOnHuntSelection","isOnTrialSelection","isOnActiveTrial","activateHunt","moveToHuntSelection","moveToTrialSelectScreen","moveToTrialScreen","handleSubmitAnswer","currentHunt","newHunt","updatedHunts","questifyCtxValue","TrialRegistry","component","trialRegistry","useQuestify","context","useContext","renderScreen","HuntSelectComponent","TrialSelectComponent","TrialScreenComponent","jsx","TrialComponent","submitAnswer","registerTrialComponent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"questify.js","sources":["../lib/store/MemoryPersister.ts","../lib/models/Trial.ts","../lib/models/Hunt.ts","../lib/models/PlayerLocation.ts","../lib/store/QuestifyContext.tsx","../lib/registry/TrialRegistry.ts","../lib/hooks/useQuestify.tsx","../lib/index.ts"],"sourcesContent":["const storage = {};\nexport const memoryPersister = {\n store: async (key, value) => {\n storage[key] = value;\n },\n load: async (key) => {\n return storage[key];\n },\n};\n","class Trial {\n id: number;\n type: string;\n title: string;\n solution: string;\n blueprint: Record<string, any>;\n isSolved: boolean;\n\n constructor(id: number, type: string, title: string, solution: string, blueprint: Record<string, any>) {\n this.id = id;\n this.type = type;\n this.title = title;\n this.solution = solution;\n this.blueprint = blueprint;\n this.isSolved = false;\n }\n\n private clone({ isSolved }: { isSolved: boolean }): Trial {\n const cloned = Object.create(Trial.prototype);\n cloned.id = this.id;\n cloned.type = this.type;\n cloned.title = this.title;\n cloned.solution = this.solution;\n cloned.blueprint = this.blueprint;\n cloned.isSolved = isSolved;\n return cloned;\n }\n\n markAsSolved(): Trial {\n return this.clone({ isSolved: true });\n }\n}\n\nexport default Trial;\n","import Trial from '@models/Trial';\n\nenum HuntStatus {\n NOT_STARTED = 'not-started',\n IN_PROGRESS = 'in-progress',\n COMPLETED = 'completed'\n}\n\ninterface TrialConfig {\n type: string;\n title: string;\n solution: string;\n blueprint: Record<string, any>;\n}\n\ninterface HuntConfig {\n id: string;\n name: string;\n icon?: string;\n subtitle?: string;\n description?: string;\n trials: TrialConfig[];\n}\n\ninterface ProgressSummary {\n status: HuntStatus;\n solvedCount: number;\n totalTrials: number;\n percentageComplete: number;\n}\n\nclass Hunt {\n id: string;\n name: string;\n icon?: string;\n subtitle?: string;\n description?: string;\n trials: Trial[];\n progressSummary: ProgressSummary;\n\n constructor(config: HuntConfig) {\n this.id = config.id;\n this.name = config.name;\n this.icon = config.icon;\n this.subtitle = config.subtitle;\n this.description = config.description;\n this.trials = config.trials.map((trialConfig, index) =>\n new Trial(index, trialConfig.type, trialConfig.title, trialConfig.solution, trialConfig.blueprint)\n );\n this.updateStatus();\n }\n\n static constructFromTrials(id: string, name: string, trials: Trial[], icon?: string, subtitle?: string, description?: string): Hunt {\n const hunt = Object.create(Hunt.prototype);\n hunt.id = id;\n hunt.name = name;\n hunt.icon = icon;\n hunt.subtitle = subtitle;\n hunt.description = description;\n hunt.trials = trials;\n hunt.updateStatus();\n return hunt;\n }\n\n submitAnswer(trialId: number, answer: string): Hunt | null {\n const trial = this.trials.find(trial => trial.id === trialId);\n\n if (!trial) {\n return null;\n }\n\n if (trial.solution === answer.trim().toLowerCase()) {\n const updatedTrials = this.trials.map(trial =>\n trial.id === trialId ? trial.markAsSolved() : trial\n );\n return this.clone({ trials: updatedTrials });\n }\n\n return null;\n }\n\n private updateStatus(): void {\n const solvedCount = this.trials.filter(trial => trial.isSolved).length;\n const totalTrials = this.trials.length;\n\n let status: HuntStatus;\n if (solvedCount === 0) {\n status = HuntStatus.NOT_STARTED;\n } else if (solvedCount === totalTrials) {\n status = HuntStatus.COMPLETED;\n } else {\n status = HuntStatus.IN_PROGRESS;\n }\n\n this.progressSummary = {\n status,\n solvedCount,\n totalTrials,\n percentageComplete: totalTrials > 0 ? (solvedCount / totalTrials) * 100 : 0\n };\n }\n\n private clone(updates: Partial<{ trials: Trial[] }>): Hunt {\n const cloned = Object.create(Hunt.prototype);\n cloned.id = this.id;\n cloned.name = this.name;\n cloned.icon = this.icon;\n cloned.subtitle = this.subtitle;\n cloned.description = this.description;\n cloned.trials = updates.trials ?? this.trials;\n cloned.updateStatus();\n return cloned;\n }\n}\n\nexport default Hunt;\n","class PlayerLocation {\n activeHuntId: string | null;\n activeTrialIndex: number | null;\n\n constructor(huntId: string | null = null, trialIndex: number | null = null) {\n this.activeHuntId = huntId;\n this.activeTrialIndex = trialIndex;\n }\n\n private clone(): PlayerLocation {\n const cloned = Object.create(PlayerLocation.prototype);\n cloned.activeHuntId = this.activeHuntId;\n cloned.activeTrialIndex = this.activeTrialIndex;\n return cloned;\n }\n\n isOnHuntSelection(): boolean {\n return this.activeHuntId === null;\n }\n\n isOnTrialSelection(): boolean {\n return this.activeHuntId !== null && this.activeTrialIndex === null;\n }\n\n isOnActiveTrial(): boolean {\n return this.activeHuntId !== null && this.activeTrialIndex !== null;\n }\n\n moveToHuntSelection(): PlayerLocation {\n const newLocation = this.clone();\n newLocation.activeHuntId = null;\n newLocation.activeTrialIndex = null;\n return newLocation;\n }\n\n moveToHunt(huntId: string): PlayerLocation {\n const newLocation = this.clone();\n newLocation.activeHuntId = huntId;\n newLocation.activeTrialIndex = null;\n return newLocation;\n }\n\n moveToTrialSelectScreen(): PlayerLocation {\n if (this.activeHuntId === null) {\n throw new Error('Cannot move to trial select when no hunt is active');\n }\n\n const newLocation = this.clone();\n newLocation.activeTrialIndex = null;\n return newLocation;\n }\n\n moveToTrialScreen(trialIdx: number): PlayerLocation {\n if (this.activeHuntId === null) {\n throw new Error('Cannot move to trial when no hunt is active');\n }\n\n const newLocation = this.clone();\n newLocation.activeTrialIndex = trialIdx;\n return newLocation;\n }\n}\n\nexport default PlayerLocation;\n","import { useState, useEffect, createContext } from \"react\";\nimport { memoryPersister } from '@store/MemoryPersister';\nimport Hunt from '@models/Hunt';\nimport PlayerLocation from '@models/PlayerLocation';\n\nexport const QuestifyContext = createContext({\n hunts: [],\n playerLocation: null,\n activeHunt: () => null,\n activeTrial: () => null,\n isOnHuntSelection: () => false,\n isOnTrialSelection: () => false,\n isOnActiveTrial: () => false,\n activateHunt: () => {},\n moveToHuntSelection: () => {},\n moveToTrialSelectScreen: () => {},\n moveToTrialScreen: () => {},\n submitAnswer: () => {},\n});\n\nexport default function QuestifyProvider({ huntConfigs, persister, children }) {\n const progressPersister = persister || memoryPersister;\n const [hunts, setHunts] = useState(huntConfigs.map(config => new Hunt(config)));\n const [playerLocation, setPlayerLocation] = useState(new PlayerLocation());\n\n useEffect(() => {\n async function loadProgress() {\n const restoredHunts = await Promise.all(\n huntConfigs.map(async (config) => {\n const storageKey = `questify-${config.id}-solved-trials`;\n const savedTrialsStr = await progressPersister.load(storageKey);\n const restoredHunt = new Hunt(config);\n\n if (savedTrialsStr) {\n const solvedTrialIds = JSON.parse(savedTrialsStr);\n const updatedTrials = restoredHunt.trials.map(trial => solvedTrialIds.includes(trial.id) ? trial.markAsSolved() : trial);\n return Hunt.constructFromTrials(config.id, config.name, updatedTrials);\n }\n\n return restoredHunt;\n })\n );\n\n setHunts(restoredHunts);\n }\n\n loadProgress();\n }, [progressPersister, huntConfigs]);\n\n function activeHunt() {\n if (playerLocation.activeHuntId === null) {\n return null;\n }\n return hunts.find(hunt => hunt.id === playerLocation.activeHuntId) || null;\n }\n\n function activeTrial() {\n const hunt = activeHunt();\n if (!hunt || playerLocation.activeTrialIndex === null) {\n return null;\n }\n return hunt.trials[playerLocation.activeTrialIndex] || null;\n }\n\n function isOnHuntSelection() {\n return playerLocation.isOnHuntSelection();\n }\n\n function isOnTrialSelection() {\n return playerLocation.isOnTrialSelection();\n }\n\n function isOnActiveTrial() {\n return playerLocation.isOnActiveTrial();\n }\n\n function activateHunt(huntId) {\n const hunt = hunts.find(hunt => hunt.id === huntId);\n if (!hunt) {\n throw new Error(`Hunt with id \"${huntId}\" not found`);\n }\n setPlayerLocation(playerLocation.moveToHunt(huntId));\n }\n\n function moveToHuntSelection() {\n setPlayerLocation(playerLocation.moveToHuntSelection());\n }\n\n function moveToTrialSelectScreen() {\n setPlayerLocation(playerLocation.moveToTrialSelectScreen());\n }\n\n function moveToTrialScreen(trialIdx) {\n const hunt = activeHunt();\n if (!hunt) {\n throw new Error('Cannot move to trial when no hunt is selected');\n }\n if (trialIdx < 0 || trialIdx >= hunt.trials.length) {\n throw new Error(`Trial index ${trialIdx} is out of bounds for hunt \"${hunt.id}\"`);\n }\n setPlayerLocation(playerLocation.moveToTrialScreen(trialIdx));\n }\n\n async function handleSubmitAnswer(answer) {\n const trial = activeTrial();\n const currentHunt = activeHunt();\n\n if (!trial || !currentHunt) {\n return false;\n }\n\n const newHunt = currentHunt.submitAnswer(trial.id, answer);\n\n if (newHunt) {\n const updatedHunts = hunts.map(hunt => hunt.id === currentHunt.id ? newHunt : hunt);\n setHunts(updatedHunts);\n\n const storageKey = `questify-${currentHunt.id}-solved-trials`;\n const solvedTrialIds = newHunt.trials.filter(trial => trial.isSolved).map(trial => trial.id);\n await progressPersister.store(storageKey, JSON.stringify(solvedTrialIds));\n return true;\n }\n\n return false;\n }\n\n const questifyCtxValue = {\n hunts: hunts,\n playerLocation: playerLocation,\n activeHunt: activeHunt,\n activeTrial: activeTrial,\n isOnHuntSelection: isOnHuntSelection,\n isOnTrialSelection: isOnTrialSelection,\n isOnActiveTrial: isOnActiveTrial,\n activateHunt: activateHunt,\n moveToHuntSelection: moveToHuntSelection,\n moveToTrialSelectScreen: moveToTrialSelectScreen,\n moveToTrialScreen: moveToTrialScreen,\n submitAnswer: handleSubmitAnswer,\n };\n\n return (\n <QuestifyContext.Provider value={questifyCtxValue}>\n {children}\n </QuestifyContext.Provider>\n );\n}\n","type TrialComponent = React.ComponentType<any>;\n\nclass TrialRegistry {\n private registry: Map<string, TrialComponent> = new Map();\n\n register(type: string, component: TrialComponent): void {\n this.registry.set(type, component);\n }\n\n get(type: string): TrialComponent | undefined {\n return this.registry.get(type);\n }\n\n has(type: string): boolean {\n return this.registry.has(type);\n }\n}\n\nexport const trialRegistry = new TrialRegistry();\n","import { useContext } from \"react\";\nimport { QuestifyContext } from \"@store/QuestifyContext\";\nimport { trialRegistry } from \"@registry/TrialRegistry\";\n\nexport function useQuestify() {\n const context = useContext(QuestifyContext);\n\n if (!context.hunts || context.hunts.length === 0) {\n throw new Error(\"No hunts found. Make sure you pass huntConfigs to the QuestifyProvider\");\n }\n\n function renderScreen(HuntSelectComponent, TrialSelectComponent, TrialScreenComponent) {\n if (context.isOnHuntSelection()) {\n const hunts = context.hunts.map((hunt) => ({ ...hunt, onSelectHunt: () => context.activateHunt(hunt.id) }));\n return <HuntSelectComponent hunts={hunts} />;\n }\n\n if (context.isOnTrialSelection()) {\n const activeHunt = context.activeHunt();\n if (!activeHunt) {\n throw new Error(\"Cannot render trial selection without an active hunt\");\n }\n\n const trials = activeHunt.trials.map((trial) => ({\n id: trial.id,\n title: trial.title,\n type: trial.type,\n isSolved: trial.isSolved,\n solution: trial.solution,\n onSelectTrial: () => context.moveToTrialScreen(trial.id)\n }));\n\n return <TrialSelectComponent\n hunt={activeHunt}\n trials={trials}\n onBack={context.moveToHuntSelection}\n />;\n }\n\n if (context.isOnActiveTrial()) {\n const trial = context.activeTrial();\n if (!trial) {\n throw new Error(\"Cannot render trial screen without an active trial\");\n }\n\n const TrialComponent = trialRegistry.get(trial.type);\n\n if (!TrialComponent) {\n throw new Error(`No trial component registered for type: ${trial.type}`);\n }\n\n return <TrialScreenComponent\n title={trial.title}\n onBack={context.moveToTrialSelectScreen}\n isSolved={trial.isSolved} \n TrialComponent={() => <TrialComponent {...trial.blueprint} title={trial.title}/>}\n />;\n }\n\n throw new Error(\"Invalid player location state\");\n }\n\n function submitAnswer(answer) {\n return context.submitAnswer(answer);\n }\n\n return {\n renderScreen: renderScreen,\n submitAnswer: submitAnswer,\n };\n}\n","import { useQuestify } from '@hooks/useQuestify';\nimport QuestifyProvider from '@store/QuestifyContext';\nimport { trialRegistry } from '@registry/TrialRegistry';\n\nexport const registerTrialComponent = (type: string, component: React.ComponentType<any>) => {\n trialRegistry.register(type, component);\n};\n\nexport { QuestifyProvider, useQuestify };\n"],"names":["storage","memoryPersister","key","value","Trial","id","type","title","solution","blueprint","isSolved","cloned","Hunt","config","trialConfig","index","name","trials","icon","subtitle","description","hunt","trialId","answer","trial","updatedTrials","solvedCount","totalTrials","status","updates","PlayerLocation","huntId","trialIndex","newLocation","trialIdx","QuestifyContext","createContext","QuestifyProvider","huntConfigs","persister","children","progressPersister","hunts","setHunts","useState","playerLocation","setPlayerLocation","useEffect","loadProgress","restoredHunts","storageKey","savedTrialsStr","restoredHunt","solvedTrialIds","activeHunt","activeTrial","isOnHuntSelection","isOnTrialSelection","isOnActiveTrial","activateHunt","moveToHuntSelection","moveToTrialSelectScreen","moveToTrialScreen","handleSubmitAnswer","currentHunt","newHunt","updatedHunts","questifyCtxValue","TrialRegistry","component","trialRegistry","useQuestify","context","useContext","renderScreen","HuntSelectComponent","TrialSelectComponent","TrialScreenComponent","jsx","TrialComponent","submitAnswer","registerTrialComponent"],"mappings":"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"}
|