payload-quiz-plugin 1.0.0
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/LICENSE +35 -0
- package/README.md +413 -0
- package/dist/client.d.mts +303 -0
- package/dist/client.d.ts +303 -0
- package/dist/client.js +769 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +725 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +434 -0
- package/dist/index.d.ts +434 -0
- package/dist/index.js +923 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +902 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React$1 from 'react';
|
|
3
|
+
import { ClassValue } from 'clsx';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Quiz Plugin Types
|
|
7
|
+
* These types are standalone and don't depend on generated payload-types
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Rich text data structure (Lexical format)
|
|
11
|
+
*/
|
|
12
|
+
type RichTextData = {
|
|
13
|
+
root: {
|
|
14
|
+
type: string;
|
|
15
|
+
children: unknown[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
} | null;
|
|
20
|
+
/**
|
|
21
|
+
* Component for rendering rich text content
|
|
22
|
+
* This allows projects to provide their own RichText component
|
|
23
|
+
*/
|
|
24
|
+
type RichTextRenderer = React.ComponentType<{
|
|
25
|
+
data: RichTextData;
|
|
26
|
+
enableGutter?: boolean;
|
|
27
|
+
className?: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Choice option in a question
|
|
31
|
+
*/
|
|
32
|
+
type QuizChoice = {
|
|
33
|
+
id?: string | null;
|
|
34
|
+
text: string;
|
|
35
|
+
isCorrect?: boolean | null;
|
|
36
|
+
explanation?: RichTextData;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Question structure for the quiz
|
|
40
|
+
*/
|
|
41
|
+
type QuizQuestion = {
|
|
42
|
+
id: number;
|
|
43
|
+
question: string;
|
|
44
|
+
requiredAnswers?: number | null;
|
|
45
|
+
choices?: QuizChoice[] | null;
|
|
46
|
+
explanation?: RichTextData;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Test configuration
|
|
50
|
+
*/
|
|
51
|
+
type QuizTest = {
|
|
52
|
+
id?: number;
|
|
53
|
+
title: string;
|
|
54
|
+
slug?: string | null;
|
|
55
|
+
questionCount?: number | null;
|
|
56
|
+
timeLimit?: number | null;
|
|
57
|
+
passMark?: number | null;
|
|
58
|
+
questionsPerPage?: number | null;
|
|
59
|
+
allowGoBack?: boolean | null;
|
|
60
|
+
requireAllAnswered?: boolean | null;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* User's answer to a question
|
|
64
|
+
*/
|
|
65
|
+
type UserAnswer = {
|
|
66
|
+
questionId: number;
|
|
67
|
+
selectedChoiceIds: string[];
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Quiz state for the reducer
|
|
71
|
+
*/
|
|
72
|
+
type QuizState = {
|
|
73
|
+
status: 'loading' | 'ready' | 'in_progress' | 'completed';
|
|
74
|
+
questions: QuizQuestion[];
|
|
75
|
+
currentQuestionIndex: number;
|
|
76
|
+
answers: Map<number, string[]>;
|
|
77
|
+
startTime: number | null;
|
|
78
|
+
endTime: number | null;
|
|
79
|
+
timeRemaining: number;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Actions for the quiz reducer
|
|
83
|
+
*/
|
|
84
|
+
type QuizAction = {
|
|
85
|
+
type: 'SET_QUESTIONS';
|
|
86
|
+
questions: QuizQuestion[];
|
|
87
|
+
} | {
|
|
88
|
+
type: 'START_QUIZ';
|
|
89
|
+
timeLimit: number;
|
|
90
|
+
} | {
|
|
91
|
+
type: 'SELECT_ANSWER';
|
|
92
|
+
questionId: number;
|
|
93
|
+
choiceId: string;
|
|
94
|
+
isMultiple: boolean;
|
|
95
|
+
} | {
|
|
96
|
+
type: 'DESELECT_ANSWER';
|
|
97
|
+
questionId: number;
|
|
98
|
+
choiceId: string;
|
|
99
|
+
} | {
|
|
100
|
+
type: 'NEXT_QUESTION';
|
|
101
|
+
} | {
|
|
102
|
+
type: 'PREV_QUESTION';
|
|
103
|
+
} | {
|
|
104
|
+
type: 'GO_TO_QUESTION';
|
|
105
|
+
index: number;
|
|
106
|
+
} | {
|
|
107
|
+
type: 'TICK_TIMER';
|
|
108
|
+
} | {
|
|
109
|
+
type: 'FINISH_QUIZ';
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Result of the quiz
|
|
113
|
+
*/
|
|
114
|
+
type QuizResult = {
|
|
115
|
+
totalQuestions: number;
|
|
116
|
+
correctAnswers: number;
|
|
117
|
+
incorrectAnswers: number;
|
|
118
|
+
unanswered: number;
|
|
119
|
+
score: number;
|
|
120
|
+
passed: boolean;
|
|
121
|
+
passMark: number;
|
|
122
|
+
timeTaken: number;
|
|
123
|
+
questionResults: QuestionResult[];
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Result for a single question
|
|
127
|
+
*/
|
|
128
|
+
type QuestionResult = {
|
|
129
|
+
questionId: number;
|
|
130
|
+
question: string;
|
|
131
|
+
requiredAnswers: number;
|
|
132
|
+
isCorrect: boolean;
|
|
133
|
+
userAnswers: string[];
|
|
134
|
+
correctAnswers: string[];
|
|
135
|
+
choices: {
|
|
136
|
+
id: string;
|
|
137
|
+
text: string;
|
|
138
|
+
isCorrect: boolean;
|
|
139
|
+
wasSelected: boolean;
|
|
140
|
+
explanation?: RichTextData;
|
|
141
|
+
}[];
|
|
142
|
+
explanation?: RichTextData;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
type QuizContextType = {
|
|
146
|
+
state: QuizState;
|
|
147
|
+
dispatch: React$1.Dispatch<QuizAction>;
|
|
148
|
+
currentQuestion: QuizQuestion | null;
|
|
149
|
+
isFirstQuestion: boolean;
|
|
150
|
+
isLastQuestion: boolean;
|
|
151
|
+
answeredCount: number;
|
|
152
|
+
selectAnswer: (choiceId: string) => void;
|
|
153
|
+
deselectAnswer: (choiceId: string) => void;
|
|
154
|
+
nextQuestion: () => void;
|
|
155
|
+
prevQuestion: () => void;
|
|
156
|
+
goToQuestion: (index: number) => void;
|
|
157
|
+
finishQuiz: () => void;
|
|
158
|
+
calculateResults: (passMark: number) => QuizResult;
|
|
159
|
+
};
|
|
160
|
+
declare function QuizProvider({ children, questions, timeLimit, }: {
|
|
161
|
+
children: React$1.ReactNode;
|
|
162
|
+
questions: QuizQuestion[];
|
|
163
|
+
timeLimit: number;
|
|
164
|
+
}): react_jsx_runtime.JSX.Element;
|
|
165
|
+
declare function useQuiz(): QuizContextType;
|
|
166
|
+
|
|
167
|
+
type Props$4 = {
|
|
168
|
+
timeRemaining: number;
|
|
169
|
+
className?: string;
|
|
170
|
+
};
|
|
171
|
+
declare function QuizTimer({ timeRemaining, className }: Props$4): react_jsx_runtime.JSX.Element;
|
|
172
|
+
|
|
173
|
+
type Props$3 = {
|
|
174
|
+
currentIndex: number;
|
|
175
|
+
totalQuestions: number;
|
|
176
|
+
answeredQuestions: Set<number>;
|
|
177
|
+
onQuestionClick?: (index: number) => void;
|
|
178
|
+
allowNavigation?: boolean;
|
|
179
|
+
className?: string;
|
|
180
|
+
};
|
|
181
|
+
declare function QuizProgress({ currentIndex, totalQuestions, answeredQuestions, onQuestionClick, allowNavigation, className, }: Props$3): react_jsx_runtime.JSX.Element;
|
|
182
|
+
|
|
183
|
+
type Props$2 = {
|
|
184
|
+
question: QuizQuestion;
|
|
185
|
+
selectedChoiceIds: string[];
|
|
186
|
+
onSelectChoice: (choiceId: string) => void;
|
|
187
|
+
onDeselectChoice: (choiceId: string) => void;
|
|
188
|
+
className?: string;
|
|
189
|
+
};
|
|
190
|
+
declare function QuestionCard({ question, selectedChoiceIds, onSelectChoice, onDeselectChoice, className, }: Props$2): react_jsx_runtime.JSX.Element;
|
|
191
|
+
|
|
192
|
+
type Props$1 = {
|
|
193
|
+
id: string;
|
|
194
|
+
text: string;
|
|
195
|
+
isSelected: boolean;
|
|
196
|
+
isMultiple: boolean;
|
|
197
|
+
onClick: () => void;
|
|
198
|
+
disabled?: boolean;
|
|
199
|
+
showResult?: boolean;
|
|
200
|
+
isCorrect?: boolean;
|
|
201
|
+
className?: string;
|
|
202
|
+
};
|
|
203
|
+
declare function ChoiceOption({ id, text, isSelected, isMultiple, onClick, disabled, showResult, isCorrect, className, }: Props$1): react_jsx_runtime.JSX.Element;
|
|
204
|
+
|
|
205
|
+
type Props = {
|
|
206
|
+
result: QuizResult;
|
|
207
|
+
testSlug: string;
|
|
208
|
+
className?: string;
|
|
209
|
+
/** Optional custom component for rendering rich text explanations */
|
|
210
|
+
RichTextComponent?: RichTextRenderer;
|
|
211
|
+
};
|
|
212
|
+
declare function QuizResults({ result, testSlug, className, RichTextComponent }: Props): react_jsx_runtime.JSX.Element;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Types for TestCard component
|
|
216
|
+
* These are standalone and don't depend on generated payload-types
|
|
217
|
+
*/
|
|
218
|
+
/**
|
|
219
|
+
* Media object structure (simplified)
|
|
220
|
+
*/
|
|
221
|
+
type TestCardMedia = {
|
|
222
|
+
url?: string | null;
|
|
223
|
+
alt?: string | null;
|
|
224
|
+
width?: number | null;
|
|
225
|
+
height?: number | null;
|
|
226
|
+
[key: string]: unknown;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Certificate type structure
|
|
230
|
+
*/
|
|
231
|
+
type TestCardCertificateType = {
|
|
232
|
+
id?: number | string;
|
|
233
|
+
shortName?: string | null;
|
|
234
|
+
title?: string | null;
|
|
235
|
+
[key: string]: unknown;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Test meta information
|
|
239
|
+
*/
|
|
240
|
+
type TestCardMeta = {
|
|
241
|
+
title?: string | null;
|
|
242
|
+
description?: string | null;
|
|
243
|
+
image?: TestCardMedia | number | string | null;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Data structure for a test card
|
|
247
|
+
*/
|
|
248
|
+
type TestCardData = {
|
|
249
|
+
id?: number | string;
|
|
250
|
+
slug?: string | null;
|
|
251
|
+
title?: string | null;
|
|
252
|
+
certificateType?: TestCardCertificateType | number | string | null;
|
|
253
|
+
meta?: TestCardMeta | null;
|
|
254
|
+
questionCount?: number | null;
|
|
255
|
+
timeLimit?: number | null;
|
|
256
|
+
passMark?: number | null;
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Props for the TestCard component
|
|
260
|
+
*/
|
|
261
|
+
type TestCardProps = {
|
|
262
|
+
/** Test data to display */
|
|
263
|
+
doc?: TestCardData;
|
|
264
|
+
/** Override title */
|
|
265
|
+
title?: string;
|
|
266
|
+
/** Additional class names */
|
|
267
|
+
className?: string;
|
|
268
|
+
/** Custom media renderer component */
|
|
269
|
+
MediaComponent?: React.ComponentType<{
|
|
270
|
+
resource: TestCardMedia;
|
|
271
|
+
size?: string;
|
|
272
|
+
fill?: boolean;
|
|
273
|
+
pictureClassName?: string;
|
|
274
|
+
imgClassName?: string;
|
|
275
|
+
}>;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* TestCard component for displaying test information in a card format
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```tsx
|
|
283
|
+
* import { TestCard } from '@/plugins/quiz/client'
|
|
284
|
+
* import { Media } from '@/components/Media'
|
|
285
|
+
*
|
|
286
|
+
* <TestCard
|
|
287
|
+
* doc={test}
|
|
288
|
+
* MediaComponent={({ resource, size }) => (
|
|
289
|
+
* <Media resource={resource} size={size} />
|
|
290
|
+
* )}
|
|
291
|
+
* />
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
declare function TestCard({ doc, title: titleFromProps, className, MediaComponent }: TestCardProps): react_jsx_runtime.JSX.Element;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Utility function for merging Tailwind CSS classes
|
|
298
|
+
* This is a common pattern used with ShadCN/Tailwind
|
|
299
|
+
*/
|
|
300
|
+
|
|
301
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
302
|
+
|
|
303
|
+
export { ChoiceOption, QuestionCard, type QuestionResult, type QuizAction, type QuizChoice, QuizProgress, QuizProvider, type QuizQuestion, type QuizResult, QuizResults, type QuizState, type QuizTest, QuizTimer, type RichTextData, type RichTextRenderer, TestCard, type TestCardCertificateType, type TestCardData, type TestCardMedia, type TestCardMeta, type TestCardProps, type UserAnswer, cn, useQuiz };
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React$1 from 'react';
|
|
3
|
+
import { ClassValue } from 'clsx';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Quiz Plugin Types
|
|
7
|
+
* These types are standalone and don't depend on generated payload-types
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Rich text data structure (Lexical format)
|
|
11
|
+
*/
|
|
12
|
+
type RichTextData = {
|
|
13
|
+
root: {
|
|
14
|
+
type: string;
|
|
15
|
+
children: unknown[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
} | null;
|
|
20
|
+
/**
|
|
21
|
+
* Component for rendering rich text content
|
|
22
|
+
* This allows projects to provide their own RichText component
|
|
23
|
+
*/
|
|
24
|
+
type RichTextRenderer = React.ComponentType<{
|
|
25
|
+
data: RichTextData;
|
|
26
|
+
enableGutter?: boolean;
|
|
27
|
+
className?: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Choice option in a question
|
|
31
|
+
*/
|
|
32
|
+
type QuizChoice = {
|
|
33
|
+
id?: string | null;
|
|
34
|
+
text: string;
|
|
35
|
+
isCorrect?: boolean | null;
|
|
36
|
+
explanation?: RichTextData;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Question structure for the quiz
|
|
40
|
+
*/
|
|
41
|
+
type QuizQuestion = {
|
|
42
|
+
id: number;
|
|
43
|
+
question: string;
|
|
44
|
+
requiredAnswers?: number | null;
|
|
45
|
+
choices?: QuizChoice[] | null;
|
|
46
|
+
explanation?: RichTextData;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Test configuration
|
|
50
|
+
*/
|
|
51
|
+
type QuizTest = {
|
|
52
|
+
id?: number;
|
|
53
|
+
title: string;
|
|
54
|
+
slug?: string | null;
|
|
55
|
+
questionCount?: number | null;
|
|
56
|
+
timeLimit?: number | null;
|
|
57
|
+
passMark?: number | null;
|
|
58
|
+
questionsPerPage?: number | null;
|
|
59
|
+
allowGoBack?: boolean | null;
|
|
60
|
+
requireAllAnswered?: boolean | null;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* User's answer to a question
|
|
64
|
+
*/
|
|
65
|
+
type UserAnswer = {
|
|
66
|
+
questionId: number;
|
|
67
|
+
selectedChoiceIds: string[];
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Quiz state for the reducer
|
|
71
|
+
*/
|
|
72
|
+
type QuizState = {
|
|
73
|
+
status: 'loading' | 'ready' | 'in_progress' | 'completed';
|
|
74
|
+
questions: QuizQuestion[];
|
|
75
|
+
currentQuestionIndex: number;
|
|
76
|
+
answers: Map<number, string[]>;
|
|
77
|
+
startTime: number | null;
|
|
78
|
+
endTime: number | null;
|
|
79
|
+
timeRemaining: number;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Actions for the quiz reducer
|
|
83
|
+
*/
|
|
84
|
+
type QuizAction = {
|
|
85
|
+
type: 'SET_QUESTIONS';
|
|
86
|
+
questions: QuizQuestion[];
|
|
87
|
+
} | {
|
|
88
|
+
type: 'START_QUIZ';
|
|
89
|
+
timeLimit: number;
|
|
90
|
+
} | {
|
|
91
|
+
type: 'SELECT_ANSWER';
|
|
92
|
+
questionId: number;
|
|
93
|
+
choiceId: string;
|
|
94
|
+
isMultiple: boolean;
|
|
95
|
+
} | {
|
|
96
|
+
type: 'DESELECT_ANSWER';
|
|
97
|
+
questionId: number;
|
|
98
|
+
choiceId: string;
|
|
99
|
+
} | {
|
|
100
|
+
type: 'NEXT_QUESTION';
|
|
101
|
+
} | {
|
|
102
|
+
type: 'PREV_QUESTION';
|
|
103
|
+
} | {
|
|
104
|
+
type: 'GO_TO_QUESTION';
|
|
105
|
+
index: number;
|
|
106
|
+
} | {
|
|
107
|
+
type: 'TICK_TIMER';
|
|
108
|
+
} | {
|
|
109
|
+
type: 'FINISH_QUIZ';
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Result of the quiz
|
|
113
|
+
*/
|
|
114
|
+
type QuizResult = {
|
|
115
|
+
totalQuestions: number;
|
|
116
|
+
correctAnswers: number;
|
|
117
|
+
incorrectAnswers: number;
|
|
118
|
+
unanswered: number;
|
|
119
|
+
score: number;
|
|
120
|
+
passed: boolean;
|
|
121
|
+
passMark: number;
|
|
122
|
+
timeTaken: number;
|
|
123
|
+
questionResults: QuestionResult[];
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Result for a single question
|
|
127
|
+
*/
|
|
128
|
+
type QuestionResult = {
|
|
129
|
+
questionId: number;
|
|
130
|
+
question: string;
|
|
131
|
+
requiredAnswers: number;
|
|
132
|
+
isCorrect: boolean;
|
|
133
|
+
userAnswers: string[];
|
|
134
|
+
correctAnswers: string[];
|
|
135
|
+
choices: {
|
|
136
|
+
id: string;
|
|
137
|
+
text: string;
|
|
138
|
+
isCorrect: boolean;
|
|
139
|
+
wasSelected: boolean;
|
|
140
|
+
explanation?: RichTextData;
|
|
141
|
+
}[];
|
|
142
|
+
explanation?: RichTextData;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
type QuizContextType = {
|
|
146
|
+
state: QuizState;
|
|
147
|
+
dispatch: React$1.Dispatch<QuizAction>;
|
|
148
|
+
currentQuestion: QuizQuestion | null;
|
|
149
|
+
isFirstQuestion: boolean;
|
|
150
|
+
isLastQuestion: boolean;
|
|
151
|
+
answeredCount: number;
|
|
152
|
+
selectAnswer: (choiceId: string) => void;
|
|
153
|
+
deselectAnswer: (choiceId: string) => void;
|
|
154
|
+
nextQuestion: () => void;
|
|
155
|
+
prevQuestion: () => void;
|
|
156
|
+
goToQuestion: (index: number) => void;
|
|
157
|
+
finishQuiz: () => void;
|
|
158
|
+
calculateResults: (passMark: number) => QuizResult;
|
|
159
|
+
};
|
|
160
|
+
declare function QuizProvider({ children, questions, timeLimit, }: {
|
|
161
|
+
children: React$1.ReactNode;
|
|
162
|
+
questions: QuizQuestion[];
|
|
163
|
+
timeLimit: number;
|
|
164
|
+
}): react_jsx_runtime.JSX.Element;
|
|
165
|
+
declare function useQuiz(): QuizContextType;
|
|
166
|
+
|
|
167
|
+
type Props$4 = {
|
|
168
|
+
timeRemaining: number;
|
|
169
|
+
className?: string;
|
|
170
|
+
};
|
|
171
|
+
declare function QuizTimer({ timeRemaining, className }: Props$4): react_jsx_runtime.JSX.Element;
|
|
172
|
+
|
|
173
|
+
type Props$3 = {
|
|
174
|
+
currentIndex: number;
|
|
175
|
+
totalQuestions: number;
|
|
176
|
+
answeredQuestions: Set<number>;
|
|
177
|
+
onQuestionClick?: (index: number) => void;
|
|
178
|
+
allowNavigation?: boolean;
|
|
179
|
+
className?: string;
|
|
180
|
+
};
|
|
181
|
+
declare function QuizProgress({ currentIndex, totalQuestions, answeredQuestions, onQuestionClick, allowNavigation, className, }: Props$3): react_jsx_runtime.JSX.Element;
|
|
182
|
+
|
|
183
|
+
type Props$2 = {
|
|
184
|
+
question: QuizQuestion;
|
|
185
|
+
selectedChoiceIds: string[];
|
|
186
|
+
onSelectChoice: (choiceId: string) => void;
|
|
187
|
+
onDeselectChoice: (choiceId: string) => void;
|
|
188
|
+
className?: string;
|
|
189
|
+
};
|
|
190
|
+
declare function QuestionCard({ question, selectedChoiceIds, onSelectChoice, onDeselectChoice, className, }: Props$2): react_jsx_runtime.JSX.Element;
|
|
191
|
+
|
|
192
|
+
type Props$1 = {
|
|
193
|
+
id: string;
|
|
194
|
+
text: string;
|
|
195
|
+
isSelected: boolean;
|
|
196
|
+
isMultiple: boolean;
|
|
197
|
+
onClick: () => void;
|
|
198
|
+
disabled?: boolean;
|
|
199
|
+
showResult?: boolean;
|
|
200
|
+
isCorrect?: boolean;
|
|
201
|
+
className?: string;
|
|
202
|
+
};
|
|
203
|
+
declare function ChoiceOption({ id, text, isSelected, isMultiple, onClick, disabled, showResult, isCorrect, className, }: Props$1): react_jsx_runtime.JSX.Element;
|
|
204
|
+
|
|
205
|
+
type Props = {
|
|
206
|
+
result: QuizResult;
|
|
207
|
+
testSlug: string;
|
|
208
|
+
className?: string;
|
|
209
|
+
/** Optional custom component for rendering rich text explanations */
|
|
210
|
+
RichTextComponent?: RichTextRenderer;
|
|
211
|
+
};
|
|
212
|
+
declare function QuizResults({ result, testSlug, className, RichTextComponent }: Props): react_jsx_runtime.JSX.Element;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Types for TestCard component
|
|
216
|
+
* These are standalone and don't depend on generated payload-types
|
|
217
|
+
*/
|
|
218
|
+
/**
|
|
219
|
+
* Media object structure (simplified)
|
|
220
|
+
*/
|
|
221
|
+
type TestCardMedia = {
|
|
222
|
+
url?: string | null;
|
|
223
|
+
alt?: string | null;
|
|
224
|
+
width?: number | null;
|
|
225
|
+
height?: number | null;
|
|
226
|
+
[key: string]: unknown;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Certificate type structure
|
|
230
|
+
*/
|
|
231
|
+
type TestCardCertificateType = {
|
|
232
|
+
id?: number | string;
|
|
233
|
+
shortName?: string | null;
|
|
234
|
+
title?: string | null;
|
|
235
|
+
[key: string]: unknown;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Test meta information
|
|
239
|
+
*/
|
|
240
|
+
type TestCardMeta = {
|
|
241
|
+
title?: string | null;
|
|
242
|
+
description?: string | null;
|
|
243
|
+
image?: TestCardMedia | number | string | null;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Data structure for a test card
|
|
247
|
+
*/
|
|
248
|
+
type TestCardData = {
|
|
249
|
+
id?: number | string;
|
|
250
|
+
slug?: string | null;
|
|
251
|
+
title?: string | null;
|
|
252
|
+
certificateType?: TestCardCertificateType | number | string | null;
|
|
253
|
+
meta?: TestCardMeta | null;
|
|
254
|
+
questionCount?: number | null;
|
|
255
|
+
timeLimit?: number | null;
|
|
256
|
+
passMark?: number | null;
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Props for the TestCard component
|
|
260
|
+
*/
|
|
261
|
+
type TestCardProps = {
|
|
262
|
+
/** Test data to display */
|
|
263
|
+
doc?: TestCardData;
|
|
264
|
+
/** Override title */
|
|
265
|
+
title?: string;
|
|
266
|
+
/** Additional class names */
|
|
267
|
+
className?: string;
|
|
268
|
+
/** Custom media renderer component */
|
|
269
|
+
MediaComponent?: React.ComponentType<{
|
|
270
|
+
resource: TestCardMedia;
|
|
271
|
+
size?: string;
|
|
272
|
+
fill?: boolean;
|
|
273
|
+
pictureClassName?: string;
|
|
274
|
+
imgClassName?: string;
|
|
275
|
+
}>;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* TestCard component for displaying test information in a card format
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```tsx
|
|
283
|
+
* import { TestCard } from '@/plugins/quiz/client'
|
|
284
|
+
* import { Media } from '@/components/Media'
|
|
285
|
+
*
|
|
286
|
+
* <TestCard
|
|
287
|
+
* doc={test}
|
|
288
|
+
* MediaComponent={({ resource, size }) => (
|
|
289
|
+
* <Media resource={resource} size={size} />
|
|
290
|
+
* )}
|
|
291
|
+
* />
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
declare function TestCard({ doc, title: titleFromProps, className, MediaComponent }: TestCardProps): react_jsx_runtime.JSX.Element;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Utility function for merging Tailwind CSS classes
|
|
298
|
+
* This is a common pattern used with ShadCN/Tailwind
|
|
299
|
+
*/
|
|
300
|
+
|
|
301
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
302
|
+
|
|
303
|
+
export { ChoiceOption, QuestionCard, type QuestionResult, type QuizAction, type QuizChoice, QuizProgress, QuizProvider, type QuizQuestion, type QuizResult, QuizResults, type QuizState, type QuizTest, QuizTimer, type RichTextData, type RichTextRenderer, TestCard, type TestCardCertificateType, type TestCardData, type TestCardMedia, type TestCardMeta, type TestCardProps, type UserAnswer, cn, useQuiz };
|