usegamigameapi 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +271 -0
  2. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,271 @@
1
+ # useGameAPI
2
+
3
+ A React hook for managing interactive quiz/game flows through iframe communication using postMessage. This hook handles question flow, answer submission, result tracking, and seamless communication between a parent window and an iframe.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install usegamigameapi
9
+ ```
10
+
11
+ ## Requirements
12
+
13
+ - React >= 18
14
+
15
+ ## Basic Usage
16
+
17
+ ```tsx
18
+ import { useGameAPI } from 'usegamigameapi';
19
+
20
+ function QuizComponent() {
21
+ const {
22
+ quiz,
23
+ selectedAnswer,
24
+ handleAnswerSelect,
25
+ updateAnswer,
26
+ handleContinue,
27
+ isCompleted,
28
+ currentResult
29
+ } = useGameAPI({
30
+ onAnswerCorrect: ({ currentQuestionIndex }) => {
31
+ console.log('Correct answer at question', currentQuestionIndex);
32
+ // Trigger confetti or other celebrations
33
+ },
34
+ onAnswerIncorrect: () => {
35
+ console.log('Incorrect answer');
36
+ }
37
+ });
38
+
39
+ // Render your quiz UI using the returned state and methods
40
+ }
41
+ ```
42
+
43
+ ## API Documentation
44
+
45
+ ### Hook Parameters
46
+
47
+ The `useGameAPI` hook accepts an object with the following optional callbacks:
48
+
49
+ | Parameter | Type | Description |
50
+ |-----------|------|-------------|
51
+ | `onAnswerCorrect` | `(params: { currentQuestionIndex: number }) => void` | Callback fired when the user submits a correct answer |
52
+ | `onAnswerIncorrect` | `() => void` | Callback fired when the user submits an incorrect answer |
53
+
54
+ ### Return Values
55
+
56
+ The hook returns an object with the following properties:
57
+
58
+ #### State Data
59
+
60
+ | Property | Type | Description |
61
+ |----------|------|-------------|
62
+ | `quiz` | `any` | The current question data received from the parent window (contains text, audio URL, answers array, etc.) |
63
+ | `currentResult` | `any` | The result object after submitting an answer (contains `isCorrect`, `isLastQuestion`, and explanation) |
64
+ | `answers` | `(boolean \| null)[]` | Array of answer history where each index corresponds to a question (true = correct, false = incorrect, null = unanswered) |
65
+ | `correctCount` | `number` | Total count of correctly answered questions |
66
+ | `currentQuestionIndex` | `number` | Zero-based index of the current question |
67
+
68
+ #### State Status
69
+
70
+ | Property | Type | Description |
71
+ |----------|------|-------------|
72
+ | `selectedAnswer` | `{ id: number; content: string } \| null` | The currently selected answer object |
73
+ | `isSubmitting` | `boolean` | Indicates whether an answer submission is in progress |
74
+ | `hasSubmitted` | `boolean` | Indicates whether the current question has been submitted and is waiting for the Continue action |
75
+ | `isCompleted` | `boolean` | Indicates whether all questions have been completed |
76
+
77
+ #### Methods
78
+
79
+ | Method | Type | Description |
80
+ |--------|------|-------------|
81
+ | `handleAnswerSelect` | `(answer: { id: number; content: string }) => void` | Selects an answer for the current question. Only works if not submitting and not already submitted |
82
+ | `updateAnswer` | `() => Promise<void>` | Submits the selected answer to the parent window. Returns a promise that resolves immediately |
83
+ | `handleContinue` | `() => void` | Moves to the next question or marks the quiz as completed if it's the last question. Only works after an answer has been submitted |
84
+ | `finish` | `() => void` | Sends a finish signal to the parent window (typically used to resize iframe) |
85
+
86
+ ## Usage Examples
87
+
88
+ ### Complete Quiz Flow Example
89
+
90
+ ```tsx
91
+ import { useGameAPI } from 'usegamigameapi';
92
+
93
+ function GameQuiz() {
94
+ const {
95
+ quiz,
96
+ selectedAnswer,
97
+ currentResult,
98
+ answers,
99
+ correctCount,
100
+ currentQuestionIndex,
101
+ isSubmitting,
102
+ hasSubmitted,
103
+ isCompleted,
104
+ handleAnswerSelect,
105
+ updateAnswer,
106
+ handleContinue,
107
+ finish
108
+ } = useGameAPI({
109
+ onAnswerCorrect: ({ currentQuestionIndex }) => {
110
+ // Show success animation or confetti
111
+ console.log(`Question ${currentQuestionIndex + 1} answered correctly!`);
112
+ },
113
+ onAnswerIncorrect: () => {
114
+ // Show error feedback
115
+ console.log('Incorrect answer, try again next time!');
116
+ }
117
+ });
118
+
119
+ // Show loading state while waiting for first question
120
+ if (!quiz) {
121
+ return <div>Loading quiz...</div>;
122
+ }
123
+
124
+ // Show completion screen
125
+ if (isCompleted) {
126
+ return (
127
+ <div>
128
+ <h2>Quiz Completed!</h2>
129
+ <p>You got {correctCount} out of {answers.length} questions correct.</p>
130
+ <button onClick={finish}>Finish</button>
131
+ </div>
132
+ );
133
+ }
134
+
135
+ return (
136
+ <div>
137
+ {/* Progress bar */}
138
+ <div>
139
+ Question {currentQuestionIndex + 1} of {answers.length + 1}
140
+ <div style={{ display: 'flex', gap: '4px' }}>
141
+ {answers.map((answer, idx) => (
142
+ <div
143
+ key={idx}
144
+ style={{
145
+ width: '20px',
146
+ height: '4px',
147
+ backgroundColor: answer === true ? 'green' : answer === false ? 'red' : 'gray'
148
+ }}
149
+ />
150
+ ))}
151
+ </div>
152
+ </div>
153
+
154
+ {/* Question */}
155
+ <h3>{quiz.text}</h3>
156
+ {quiz.audioUrl && <audio src={quiz.audioUrl} controls />}
157
+
158
+ {/* Answer options */}
159
+ <div>
160
+ {quiz.answers?.map((answer: { id: number; content: string }) => (
161
+ <button
162
+ key={answer.id}
163
+ onClick={() => handleAnswerSelect(answer)}
164
+ disabled={isSubmitting || hasSubmitted}
165
+ style={{
166
+ backgroundColor: selectedAnswer?.id === answer.id ? '#007bff' : '#f0f0f0',
167
+ opacity: hasSubmitted ? 0.6 : 1
168
+ }}
169
+ >
170
+ {answer.content}
171
+ </button>
172
+ ))}
173
+ </div>
174
+
175
+ {/* Submit button */}
176
+ {!hasSubmitted && (
177
+ <button
178
+ onClick={updateAnswer}
179
+ disabled={!selectedAnswer || isSubmitting}
180
+ >
181
+ Submit Answer
182
+ </button>
183
+ )}
184
+
185
+ {/* Result display and Continue button */}
186
+ {hasSubmitted && currentResult && (
187
+ <div>
188
+ <p>
189
+ {currentResult.isCorrect ? '✓ Correct!' : '✗ Incorrect'}
190
+ </p>
191
+ {currentResult.explanation && <p>{currentResult.explanation}</p>}
192
+ <button onClick={handleContinue}>
193
+ {currentResult.isLastQuestion ? 'Finish Quiz' : 'Next Question'}
194
+ </button>
195
+ </div>
196
+ )}
197
+
198
+ {/* Score */}
199
+ <div>Score: {correctCount}</div>
200
+ </div>
201
+ );
202
+ }
203
+ ```
204
+
205
+ ### Minimal Example
206
+
207
+ ```tsx
208
+ import { useGameAPI } from 'usegamigameapi';
209
+
210
+ function SimpleQuiz() {
211
+ const { quiz, handleAnswerSelect, updateAnswer, handleContinue, selectedAnswer, hasSubmitted } = useGameAPI();
212
+
213
+ return (
214
+ <div>
215
+ <h2>{quiz?.text}</h2>
216
+ {quiz?.answers?.map((answer) => (
217
+ <button
218
+ key={answer.id}
219
+ onClick={() => handleAnswerSelect(answer)}
220
+ disabled={hasSubmitted}
221
+ >
222
+ {answer.content}
223
+ </button>
224
+ ))}
225
+ {!hasSubmitted && (
226
+ <button onClick={updateAnswer} disabled={!selectedAnswer}>
227
+ Submit
228
+ </button>
229
+ )}
230
+ {hasSubmitted && (
231
+ <button onClick={handleContinue}>Continue</button>
232
+ )}
233
+ </div>
234
+ );
235
+ }
236
+ ```
237
+
238
+ ## Architecture
239
+
240
+ This hook uses a **bridge pattern** to facilitate communication between a parent window (Main Web) and a child iframe (Sub Web) through `window.postMessage`. The communication flow works as follows:
241
+
242
+ ### Communication Flow
243
+
244
+ 1. **Initialization**: When the hook mounts, it sends `SHOW_LO5` to request the first question
245
+ 2. **Question Received**: Parent responds with `RETURN_LO5` containing question data
246
+ 3. **Answer Submission**: User selects an answer and calls `updateAnswer()`, which sends `UPDATE_ANSWER` with the answer ID
247
+ 4. **Result Received**: Parent responds with `RETURN_UPDATE_ANSWER` containing `isCorrect`, `isLastQuestion`, and result data
248
+ 5. **Continue**: User calls `handleContinue()` which either requests the next question (`SHOW_LO5`) or marks the quiz as completed
249
+ 6. **Finish**: When complete, `finish()` sends `FINISH` to signal completion (typically for iframe resizing)
250
+
251
+ ### Action Types
252
+
253
+ The bridge uses the following action constants (defined internally):
254
+
255
+ - `SHOW_LO5`: Sub → Main - Request a question
256
+ - `RETURN_LO5`: Main → Sub - Send question data
257
+ - `UPDATE_ANSWER`: Sub → Main - Submit selected answer
258
+ - `RETURN_UPDATE_ANSWER`: Main → Sub - Return answer result
259
+ - `FINISH`: Sub → Main - Signal completion
260
+
261
+ ## Notes
262
+
263
+ - The hook automatically requests the first question when mounted
264
+ - Answer history is tracked in the `answers` array, indexed by question number
265
+ - The hook uses both `useState` and `useRef` to ensure correct closure behavior across renders
266
+ - All communication is asynchronous through postMessage events
267
+ - Make sure your parent window is set up to handle the corresponding postMessage events
268
+
269
+ ## License
270
+
271
+ See package.json for license information.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usegamigameapi",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -10,7 +10,7 @@
10
10
  ],
11
11
  "scripts": {
12
12
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
13
- "publish": "npm run build && npm publish --access public"
13
+ "publish": "npm version patch && npm run build && npm publish --access public"
14
14
  },
15
15
  "peerDependencies": {
16
16
  "react": ">=18"