react-native-elearn-ui 0.1.11 → 0.1.13
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/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/screens/HomeScreen.js +672 -662
- package/lib/module/screens/HomeScreen.js.map +1 -1
- package/lib/module/screens/index.js +0 -8
- package/lib/module/screens/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/screens/HomeScreen.d.ts.map +1 -1
- package/lib/typescript/src/screens/index.d.ts +0 -8
- package/lib/typescript/src/screens/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +0 -8
- package/src/screens/HomeScreen.tsx +471 -534
- package/src/screens/index.ts +0 -8
- package/lib/module/screens/PearlChaptersScreen.js +0 -359
- package/lib/module/screens/PearlChaptersScreen.js.map +0 -1
- package/lib/module/screens/PearlReaderScreen.js +0 -313
- package/lib/module/screens/PearlReaderScreen.js.map +0 -1
- package/lib/module/screens/PearlsScreen.js +0 -153
- package/lib/module/screens/PearlsScreen.js.map +0 -1
- package/lib/module/screens/QbankScreen.js +0 -370
- package/lib/module/screens/QbankScreen.js.map +0 -1
- package/lib/module/screens/QuestionScreen.js +0 -437
- package/lib/module/screens/QuestionScreen.js.map +0 -1
- package/lib/module/screens/QuizStartScreen.js +0 -283
- package/lib/module/screens/QuizStartScreen.js.map +0 -1
- package/lib/module/screens/ResultScreen.js +0 -646
- package/lib/module/screens/ResultScreen.js.map +0 -1
- package/lib/module/screens/TopicListScreen.js +0 -420
- package/lib/module/screens/TopicListScreen.js.map +0 -1
- package/lib/module/screens/pearlsMockData.js +0 -77
- package/lib/module/screens/pearlsMockData.js.map +0 -1
- package/lib/typescript/src/screens/PearlChaptersScreen.d.ts +0 -13
- package/lib/typescript/src/screens/PearlChaptersScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/PearlReaderScreen.d.ts +0 -14
- package/lib/typescript/src/screens/PearlReaderScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/PearlsScreen.d.ts +0 -11
- package/lib/typescript/src/screens/PearlsScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/QbankScreen.d.ts +0 -10
- package/lib/typescript/src/screens/QbankScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/QuestionScreen.d.ts +0 -14
- package/lib/typescript/src/screens/QuestionScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/QuizStartScreen.d.ts +0 -14
- package/lib/typescript/src/screens/QuizStartScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/ResultScreen.d.ts +0 -13
- package/lib/typescript/src/screens/ResultScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/TopicListScreen.d.ts +0 -12
- package/lib/typescript/src/screens/TopicListScreen.d.ts.map +0 -1
- package/lib/typescript/src/screens/pearlsMockData.d.ts +0 -3
- package/lib/typescript/src/screens/pearlsMockData.d.ts.map +0 -1
- package/src/screens/PearlChaptersScreen.tsx +0 -330
- package/src/screens/PearlReaderScreen.tsx +0 -306
- package/src/screens/PearlsScreen.tsx +0 -147
- package/src/screens/QbankScreen.tsx +0 -327
- package/src/screens/QuestionScreen.tsx +0 -423
- package/src/screens/QuizStartScreen.tsx +0 -260
- package/src/screens/ResultScreen.tsx +0 -618
- package/src/screens/TopicListScreen.tsx +0 -388
- package/src/screens/pearlsMockData.ts +0 -70
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
ScrollView,
|
|
5
|
-
StyleSheet,
|
|
6
|
-
TouchableOpacity,
|
|
7
|
-
StatusBar,
|
|
8
|
-
Image,
|
|
9
|
-
} from 'react-native';
|
|
10
|
-
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
11
|
-
import type { Question, QuizResults } from '../types';
|
|
12
|
-
import { useElearnConfig } from '../context/ElearnConfigContext';
|
|
13
|
-
import { useTheme } from '../context/ThemeContext';
|
|
14
|
-
import { Typography, Button, Icon } from '../components';
|
|
15
|
-
|
|
16
|
-
interface QuestionScreenProps {
|
|
17
|
-
quizId?: string;
|
|
18
|
-
questions?: Question[];
|
|
19
|
-
title?: string;
|
|
20
|
-
topicId?: string;
|
|
21
|
-
onClose: () => void;
|
|
22
|
-
onFinishQuiz?: (quizId: string, results: QuizResults) => void;
|
|
23
|
-
hideHeader?: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const QuestionScreen: React.FC<QuestionScreenProps> = ({
|
|
27
|
-
quizId,
|
|
28
|
-
questions,
|
|
29
|
-
title,
|
|
30
|
-
topicId,
|
|
31
|
-
onClose,
|
|
32
|
-
onFinishQuiz,
|
|
33
|
-
hideHeader = false,
|
|
34
|
-
}) => {
|
|
35
|
-
const { config, callbacks } = useElearnConfig();
|
|
36
|
-
const theme = useTheme();
|
|
37
|
-
|
|
38
|
-
const activeTopic = topicId ? config.courses?.flatMap((c) => c.topics).find((t) => t.id === topicId) : undefined;
|
|
39
|
-
const activeQuestions = questions || activeTopic?.questions || [];
|
|
40
|
-
const activeTitle = title || activeTopic?.title || 'Quiz';
|
|
41
|
-
const activeQuizId = quizId || topicId || '';
|
|
42
|
-
|
|
43
|
-
const [currentIndex, setCurrentIndex] = useState(0);
|
|
44
|
-
const [selectedOption, setSelectedOption] = useState<number | null>(null);
|
|
45
|
-
const [isAnswered, setIsAnswered] = useState(false);
|
|
46
|
-
const [userAnswers, setUserAnswers] = useState<{ [questionId: string]: number }>({});
|
|
47
|
-
const [correctCount, setCorrectCount] = useState(0);
|
|
48
|
-
const [startTime] = useState(Date.now());
|
|
49
|
-
const [isPaused, setIsPaused] = useState(false);
|
|
50
|
-
|
|
51
|
-
if (!activeQuestions || activeQuestions.length === 0) {
|
|
52
|
-
return (
|
|
53
|
-
<SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
|
|
54
|
-
<View style={styles.errorContainer}>
|
|
55
|
-
<Typography variant="h2" bold>No questions available</Typography>
|
|
56
|
-
<Button title="Go Back" onPress={onClose} style={styles.errorButton} />
|
|
57
|
-
</View>
|
|
58
|
-
</SafeAreaView>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const currentQuestion = activeQuestions[currentIndex]!;
|
|
63
|
-
const optionPrefixes = ['A', 'B', 'C', 'D', 'E', 'F'];
|
|
64
|
-
|
|
65
|
-
const handleOptionPress = (index: number) => {
|
|
66
|
-
if (isAnswered) return; // Prevent changing answer after selection
|
|
67
|
-
|
|
68
|
-
setSelectedOption(index);
|
|
69
|
-
setIsAnswered(true);
|
|
70
|
-
|
|
71
|
-
const updatedAnswers = { ...userAnswers, [currentQuestion.id]: index };
|
|
72
|
-
setUserAnswers(updatedAnswers);
|
|
73
|
-
|
|
74
|
-
const isCorrect = index === currentQuestion.correctOptionIndex;
|
|
75
|
-
if (isCorrect) {
|
|
76
|
-
setCorrectCount((prev) => prev + 1);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const handleNext = () => {
|
|
81
|
-
if (currentIndex < activeQuestions.length - 1) {
|
|
82
|
-
setCurrentIndex((prev) => prev + 1);
|
|
83
|
-
setSelectedOption(null);
|
|
84
|
-
setIsAnswered(false);
|
|
85
|
-
} else {
|
|
86
|
-
// Last question - finish quiz
|
|
87
|
-
const totalTimeSeconds = Math.round((Date.now() - startTime) / 1000);
|
|
88
|
-
const wrongCount = activeQuestions.length - correctCount;
|
|
89
|
-
const accuracy = Math.round((correctCount / activeQuestions.length) * 100);
|
|
90
|
-
|
|
91
|
-
const results: QuizResults = {
|
|
92
|
-
quizId: activeQuizId,
|
|
93
|
-
totalQuestions: activeQuestions.length,
|
|
94
|
-
correctCount,
|
|
95
|
-
wrongCount,
|
|
96
|
-
skippedCount: 0,
|
|
97
|
-
accuracy,
|
|
98
|
-
timeSpentSeconds: totalTimeSeconds,
|
|
99
|
-
userAnswers,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
if (onFinishQuiz) {
|
|
103
|
-
onFinishQuiz(activeQuizId, results);
|
|
104
|
-
} else {
|
|
105
|
-
callbacks.onFinishQuiz?.(activeQuizId, results);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
|
|
112
|
-
<StatusBar barStyle="dark-content" />
|
|
113
|
-
|
|
114
|
-
{/* Header */}
|
|
115
|
-
{!hideHeader && (
|
|
116
|
-
<View style={styles.header}>
|
|
117
|
-
<TouchableOpacity onPress={onClose} style={styles.backButton}>
|
|
118
|
-
<Icon name="arrow-left" size={20} color={theme.textPrimary} />
|
|
119
|
-
</TouchableOpacity>
|
|
120
|
-
|
|
121
|
-
<Typography variant="h2" bold style={styles.headerTitle}>
|
|
122
|
-
{activeTitle || 'QBank'}
|
|
123
|
-
</Typography>
|
|
124
|
-
|
|
125
|
-
<TouchableOpacity style={styles.shareButton}>
|
|
126
|
-
<Icon name="share" size={20} color={theme.textPrimary} />
|
|
127
|
-
</TouchableOpacity>
|
|
128
|
-
</View>
|
|
129
|
-
)}
|
|
130
|
-
|
|
131
|
-
<ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
|
|
132
|
-
|
|
133
|
-
{/* Question Header & Pause/Bookmark Actions Row */}
|
|
134
|
-
<View style={styles.metaRow}>
|
|
135
|
-
<Typography variant="caption" bold color={theme.textSecondary} style={styles.questionNumLabel}>
|
|
136
|
-
QUESTION {currentIndex + 1}/{activeQuestions.length}
|
|
137
|
-
</Typography>
|
|
138
|
-
<View style={styles.metaActions}>
|
|
139
|
-
<TouchableOpacity style={styles.metaActionBtn}>
|
|
140
|
-
<Icon name="bookmark" size={18} color={theme.textSecondary} />
|
|
141
|
-
</TouchableOpacity>
|
|
142
|
-
<TouchableOpacity onPress={() => setIsPaused(!isPaused)} style={styles.metaActionBtn}>
|
|
143
|
-
<Icon name={isPaused ? 'play' : 'pause-circle'} size={18} color={theme.textSecondary} />
|
|
144
|
-
</TouchableOpacity>
|
|
145
|
-
</View>
|
|
146
|
-
</View>
|
|
147
|
-
|
|
148
|
-
{/* Question text */}
|
|
149
|
-
<Typography variant="h2" bold color={theme.textPrimary} style={styles.questionText}>
|
|
150
|
-
{currentQuestion.text}
|
|
151
|
-
</Typography>
|
|
152
|
-
|
|
153
|
-
{/* Neuron microscope image */}
|
|
154
|
-
{currentQuestion.imageUrl && (
|
|
155
|
-
<Image
|
|
156
|
-
source={{ uri: currentQuestion.imageUrl }}
|
|
157
|
-
style={styles.questionImage}
|
|
158
|
-
resizeMode="cover"
|
|
159
|
-
/>
|
|
160
|
-
)}
|
|
161
|
-
|
|
162
|
-
{/* Options list */}
|
|
163
|
-
<View style={styles.optionsList}>
|
|
164
|
-
{currentQuestion.options.map((option, idx) => {
|
|
165
|
-
const isSelected = selectedOption === idx;
|
|
166
|
-
const isCorrectAnswer = idx === currentQuestion.correctOptionIndex;
|
|
167
|
-
|
|
168
|
-
let optionBg = '#FFFFFF';
|
|
169
|
-
let optionBorder = theme.border;
|
|
170
|
-
let labelColor = theme.textPrimary;
|
|
171
|
-
let prefixColor = theme.textSecondary;
|
|
172
|
-
let statText = '';
|
|
173
|
-
|
|
174
|
-
if (isAnswered) {
|
|
175
|
-
if (isCorrectAnswer) {
|
|
176
|
-
optionBg = '#E6F4F1'; // Tinted green bg
|
|
177
|
-
optionBorder = '#10B981'; // Green border
|
|
178
|
-
labelColor = '#065F46';
|
|
179
|
-
prefixColor = '#065F46';
|
|
180
|
-
statText = '73% got this Correct'; // Mock stats matching mockup 5
|
|
181
|
-
} else if (isSelected) {
|
|
182
|
-
optionBg = '#FEF2F2'; // Tinted red bg
|
|
183
|
-
optionBorder = '#EF4444'; // Red border
|
|
184
|
-
labelColor = '#991B1B';
|
|
185
|
-
prefixColor = '#991B1B';
|
|
186
|
-
statText = '27% Marked Wrong'; // Mock stats matching mockup 5
|
|
187
|
-
}
|
|
188
|
-
} else if (isSelected) {
|
|
189
|
-
optionBg = theme.secondary;
|
|
190
|
-
optionBorder = theme.primary;
|
|
191
|
-
labelColor = theme.primary;
|
|
192
|
-
prefixColor = theme.primary;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return (
|
|
196
|
-
<TouchableOpacity
|
|
197
|
-
key={idx}
|
|
198
|
-
activeOpacity={0.8}
|
|
199
|
-
onPress={() => handleOptionPress(idx)}
|
|
200
|
-
disabled={isAnswered}
|
|
201
|
-
style={[
|
|
202
|
-
styles.optionCard,
|
|
203
|
-
{
|
|
204
|
-
backgroundColor: optionBg,
|
|
205
|
-
borderColor: optionBorder,
|
|
206
|
-
},
|
|
207
|
-
]}
|
|
208
|
-
>
|
|
209
|
-
<View style={styles.optionRow}>
|
|
210
|
-
{/* Option letter label */}
|
|
211
|
-
<Typography variant="body" bold color={prefixColor} style={styles.optionPrefix}>
|
|
212
|
-
{optionPrefixes[idx] || idx + 1}
|
|
213
|
-
</Typography>
|
|
214
|
-
|
|
215
|
-
{/* Option text */}
|
|
216
|
-
<Typography variant="body" color={labelColor} style={styles.optionText}>
|
|
217
|
-
{option}
|
|
218
|
-
</Typography>
|
|
219
|
-
</View>
|
|
220
|
-
|
|
221
|
-
{/* Option stats badge below option text */}
|
|
222
|
-
{isAnswered && statText !== '' && (
|
|
223
|
-
<View style={styles.statBadgeRow}>
|
|
224
|
-
<Typography variant="caption" bold color={isCorrectAnswer ? '#10B981' : '#EF4444'}>
|
|
225
|
-
{statText}
|
|
226
|
-
</Typography>
|
|
227
|
-
</View>
|
|
228
|
-
)}
|
|
229
|
-
</TouchableOpacity>
|
|
230
|
-
);
|
|
231
|
-
})}
|
|
232
|
-
</View>
|
|
233
|
-
|
|
234
|
-
{/* Explanation Card (Appears after answer selection) */}
|
|
235
|
-
{isAnswered && (
|
|
236
|
-
<View style={styles.explanationSection}>
|
|
237
|
-
<Typography variant="h2" bold color={theme.textPrimary} style={styles.explanationTitle}>
|
|
238
|
-
Explanation
|
|
239
|
-
</Typography>
|
|
240
|
-
<Typography variant="body" color={theme.textSecondary} style={styles.explanationBody}>
|
|
241
|
-
{currentQuestion.explanation}
|
|
242
|
-
</Typography>
|
|
243
|
-
|
|
244
|
-
<Typography variant="h3" bold color={theme.textSecondary} style={styles.rxdxId}>
|
|
245
|
-
RXDX ID: R23082
|
|
246
|
-
</Typography>
|
|
247
|
-
</View>
|
|
248
|
-
)}
|
|
249
|
-
|
|
250
|
-
</ScrollView>
|
|
251
|
-
|
|
252
|
-
{/* Answered State Bottom Actions Bar */}
|
|
253
|
-
{isAnswered && (
|
|
254
|
-
<View style={styles.footerRow}>
|
|
255
|
-
{/* Report action */}
|
|
256
|
-
<TouchableOpacity style={styles.footerActionBtn}>
|
|
257
|
-
<Icon name="alert-circle" size={18} color="#EF4444" />
|
|
258
|
-
<Typography variant="caption" bold color="#EF4444" style={styles.footerActionLabel}>
|
|
259
|
-
Report
|
|
260
|
-
</Typography>
|
|
261
|
-
</TouchableOpacity>
|
|
262
|
-
|
|
263
|
-
{/* Whatsapp action */}
|
|
264
|
-
<TouchableOpacity style={styles.footerActionBtn}>
|
|
265
|
-
<Icon name="whatsapp" size={18} color="#22C55E" />
|
|
266
|
-
<Typography variant="caption" bold color="#22C55E" style={styles.footerActionLabel}>
|
|
267
|
-
Whatsapp
|
|
268
|
-
</Typography>
|
|
269
|
-
</TouchableOpacity>
|
|
270
|
-
|
|
271
|
-
{/* Next action button */}
|
|
272
|
-
<TouchableOpacity onPress={handleNext} style={[styles.nextActionBtn, { backgroundColor: theme.primary }]}>
|
|
273
|
-
<Typography variant="body" bold color="#FFFFFF">
|
|
274
|
-
Next
|
|
275
|
-
</Typography>
|
|
276
|
-
</TouchableOpacity>
|
|
277
|
-
</View>
|
|
278
|
-
)}
|
|
279
|
-
</SafeAreaView>
|
|
280
|
-
);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
const styles = StyleSheet.create({
|
|
284
|
-
safeArea: {
|
|
285
|
-
flex: 1,
|
|
286
|
-
},
|
|
287
|
-
header: {
|
|
288
|
-
flexDirection: 'row',
|
|
289
|
-
justifyContent: 'space-between',
|
|
290
|
-
alignItems: 'center',
|
|
291
|
-
paddingHorizontal: 16,
|
|
292
|
-
paddingVertical: 12,
|
|
293
|
-
},
|
|
294
|
-
backButton: {
|
|
295
|
-
padding: 6,
|
|
296
|
-
},
|
|
297
|
-
headerTitle: {
|
|
298
|
-
fontSize: 18,
|
|
299
|
-
fontWeight: '700',
|
|
300
|
-
},
|
|
301
|
-
shareButton: {
|
|
302
|
-
padding: 6,
|
|
303
|
-
},
|
|
304
|
-
scrollContent: {
|
|
305
|
-
paddingHorizontal: 16,
|
|
306
|
-
paddingTop: 8,
|
|
307
|
-
paddingBottom: 32,
|
|
308
|
-
},
|
|
309
|
-
metaRow: {
|
|
310
|
-
flexDirection: 'row',
|
|
311
|
-
justifyContent: 'space-between',
|
|
312
|
-
alignItems: 'center',
|
|
313
|
-
marginBottom: 12,
|
|
314
|
-
},
|
|
315
|
-
questionNumLabel: {
|
|
316
|
-
fontSize: 12,
|
|
317
|
-
letterSpacing: 0.8,
|
|
318
|
-
},
|
|
319
|
-
metaActions: {
|
|
320
|
-
flexDirection: 'row',
|
|
321
|
-
alignItems: 'center',
|
|
322
|
-
},
|
|
323
|
-
metaActionBtn: {
|
|
324
|
-
padding: 6,
|
|
325
|
-
marginLeft: 10,
|
|
326
|
-
},
|
|
327
|
-
questionText: {
|
|
328
|
-
fontSize: 16,
|
|
329
|
-
lineHeight: 22,
|
|
330
|
-
marginBottom: 14,
|
|
331
|
-
},
|
|
332
|
-
questionImage: {
|
|
333
|
-
width: '100%',
|
|
334
|
-
height: 180,
|
|
335
|
-
borderRadius: 12,
|
|
336
|
-
marginBottom: 16,
|
|
337
|
-
backgroundColor: '#F8FAFC',
|
|
338
|
-
},
|
|
339
|
-
optionsList: {
|
|
340
|
-
marginBottom: 12,
|
|
341
|
-
},
|
|
342
|
-
optionCard: {
|
|
343
|
-
borderWidth: 1,
|
|
344
|
-
borderRadius: 10,
|
|
345
|
-
padding: 12,
|
|
346
|
-
marginBottom: 10,
|
|
347
|
-
},
|
|
348
|
-
optionRow: {
|
|
349
|
-
flexDirection: 'row',
|
|
350
|
-
alignItems: 'flex-start',
|
|
351
|
-
},
|
|
352
|
-
optionPrefix: {
|
|
353
|
-
width: 24,
|
|
354
|
-
fontSize: 14,
|
|
355
|
-
fontWeight: '600',
|
|
356
|
-
},
|
|
357
|
-
optionText: {
|
|
358
|
-
flex: 1,
|
|
359
|
-
fontSize: 14,
|
|
360
|
-
lineHeight: 18,
|
|
361
|
-
},
|
|
362
|
-
statBadgeRow: {
|
|
363
|
-
marginTop: 6,
|
|
364
|
-
paddingLeft: 24,
|
|
365
|
-
},
|
|
366
|
-
explanationSection: {
|
|
367
|
-
marginTop: 14,
|
|
368
|
-
paddingTop: 14,
|
|
369
|
-
borderTopWidth: 1,
|
|
370
|
-
borderTopColor: '#E2E8F0',
|
|
371
|
-
},
|
|
372
|
-
explanationTitle: {
|
|
373
|
-
fontSize: 15,
|
|
374
|
-
marginBottom: 6,
|
|
375
|
-
},
|
|
376
|
-
explanationBody: {
|
|
377
|
-
fontSize: 13,
|
|
378
|
-
lineHeight: 18,
|
|
379
|
-
marginBottom: 16,
|
|
380
|
-
},
|
|
381
|
-
rxdxId: {
|
|
382
|
-
fontSize: 12,
|
|
383
|
-
textAlign: 'center',
|
|
384
|
-
marginTop: 12,
|
|
385
|
-
},
|
|
386
|
-
footerRow: {
|
|
387
|
-
flexDirection: 'row',
|
|
388
|
-
alignItems: 'center',
|
|
389
|
-
paddingHorizontal: 16,
|
|
390
|
-
paddingVertical: 12,
|
|
391
|
-
backgroundColor: '#FFFFFF',
|
|
392
|
-
borderTopWidth: 1,
|
|
393
|
-
borderTopColor: '#E2E8F0',
|
|
394
|
-
justifyContent: 'space-between',
|
|
395
|
-
},
|
|
396
|
-
footerActionBtn: {
|
|
397
|
-
flexDirection: 'row',
|
|
398
|
-
alignItems: 'center',
|
|
399
|
-
paddingVertical: 8,
|
|
400
|
-
paddingHorizontal: 12,
|
|
401
|
-
},
|
|
402
|
-
footerActionLabel: {
|
|
403
|
-
marginLeft: 6,
|
|
404
|
-
fontSize: 12,
|
|
405
|
-
},
|
|
406
|
-
nextActionBtn: {
|
|
407
|
-
paddingHorizontal: 24,
|
|
408
|
-
paddingVertical: 10,
|
|
409
|
-
borderRadius: 8,
|
|
410
|
-
minWidth: 80,
|
|
411
|
-
justifyContent: 'center',
|
|
412
|
-
alignItems: 'center',
|
|
413
|
-
},
|
|
414
|
-
errorContainer: {
|
|
415
|
-
flex: 1,
|
|
416
|
-
justifyContent: 'center',
|
|
417
|
-
alignItems: 'center',
|
|
418
|
-
padding: 24,
|
|
419
|
-
},
|
|
420
|
-
errorButton: {
|
|
421
|
-
marginTop: 16,
|
|
422
|
-
},
|
|
423
|
-
});
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
StyleSheet,
|
|
5
|
-
TouchableOpacity,
|
|
6
|
-
StatusBar,
|
|
7
|
-
} from 'react-native';
|
|
8
|
-
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
9
|
-
import type { Topic, Course, Question } from '../types';
|
|
10
|
-
import { useElearnConfig } from '../context/ElearnConfigContext';
|
|
11
|
-
import { useTheme } from '../context/ThemeContext';
|
|
12
|
-
import { Typography, Card, Button, Icon } from '../components';
|
|
13
|
-
|
|
14
|
-
interface QuizStartScreenProps {
|
|
15
|
-
course?: Course;
|
|
16
|
-
courseId?: string;
|
|
17
|
-
topic?: Topic;
|
|
18
|
-
topicId?: string;
|
|
19
|
-
onBack: () => void;
|
|
20
|
-
hideHeader?: boolean;
|
|
21
|
-
onStartQuiz?: (quizId: string, questions: Question[], title: string) => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const QuizStartScreen: React.FC<QuizStartScreenProps> = ({
|
|
25
|
-
course,
|
|
26
|
-
courseId,
|
|
27
|
-
topic,
|
|
28
|
-
topicId,
|
|
29
|
-
onBack,
|
|
30
|
-
hideHeader = false,
|
|
31
|
-
onStartQuiz,
|
|
32
|
-
}) => {
|
|
33
|
-
const { config, callbacks } = useElearnConfig();
|
|
34
|
-
const theme = useTheme();
|
|
35
|
-
|
|
36
|
-
const activeCourse = course || config.courses?.find((c) => c.id === courseId);
|
|
37
|
-
const activeTopic = topic || activeCourse?.topics.find((t) => t.id === topicId) || config.courses?.flatMap((c) => c.topics).find((t) => t.id === topicId);
|
|
38
|
-
|
|
39
|
-
const handleStart = () => {
|
|
40
|
-
if (activeTopic && activeTopic.questions) {
|
|
41
|
-
if (onStartQuiz) {
|
|
42
|
-
onStartQuiz(activeTopic.id, activeTopic.questions, activeTopic.title);
|
|
43
|
-
} else {
|
|
44
|
-
callbacks.onStartQuiz?.(activeTopic.id, activeTopic.questions, activeTopic.title);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
if (!activeTopic) {
|
|
50
|
-
return (
|
|
51
|
-
<SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
|
|
52
|
-
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}>
|
|
53
|
-
<Typography variant="h2" bold style={{ marginBottom: 12 }}>Topic not found</Typography>
|
|
54
|
-
<TouchableOpacity
|
|
55
|
-
onPress={onBack}
|
|
56
|
-
style={{
|
|
57
|
-
paddingHorizontal: 20,
|
|
58
|
-
paddingVertical: 10,
|
|
59
|
-
borderRadius: 8,
|
|
60
|
-
backgroundColor: theme.primary,
|
|
61
|
-
}}
|
|
62
|
-
>
|
|
63
|
-
<Typography variant="body" bold color="#FFFFFF">Go Back</Typography>
|
|
64
|
-
</TouchableOpacity>
|
|
65
|
-
</View>
|
|
66
|
-
</SafeAreaView>
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Mock list of glance topics matching mockup 3
|
|
71
|
-
const glanceTopics = [
|
|
72
|
-
'Cerebral Cortex',
|
|
73
|
-
'Cranial Nerves',
|
|
74
|
-
'Spinal Cord Tracts',
|
|
75
|
-
'Brainstem Anatomy',
|
|
76
|
-
'Basal Ganglia',
|
|
77
|
-
'Thalamus and Hypothalamus',
|
|
78
|
-
'Visual and Auditory Pathways',
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
|
|
83
|
-
<StatusBar barStyle="dark-content" />
|
|
84
|
-
|
|
85
|
-
{/* Header */}
|
|
86
|
-
{!hideHeader && (
|
|
87
|
-
<View style={styles.header}>
|
|
88
|
-
<TouchableOpacity onPress={onBack} style={styles.backButton}>
|
|
89
|
-
<Icon name="arrow-left" size={20} color={theme.textPrimary} />
|
|
90
|
-
</TouchableOpacity>
|
|
91
|
-
<Typography variant="h2" bold style={styles.headerTitle}>
|
|
92
|
-
QBank
|
|
93
|
-
</Typography>
|
|
94
|
-
<TouchableOpacity style={styles.shareButton}>
|
|
95
|
-
<Icon name="share" size={20} color={theme.textPrimary} />
|
|
96
|
-
</TouchableOpacity>
|
|
97
|
-
</View>
|
|
98
|
-
)}
|
|
99
|
-
|
|
100
|
-
<View style={styles.container}>
|
|
101
|
-
<View style={styles.content}>
|
|
102
|
-
|
|
103
|
-
{/* Section Category Title */}
|
|
104
|
-
<Typography variant="h1" bold color={theme.textPrimary} style={styles.categoryTitle}>
|
|
105
|
-
{activeTopic.category || 'Neuro Anatomy'}
|
|
106
|
-
</Typography>
|
|
107
|
-
|
|
108
|
-
{/* Main Info Box */}
|
|
109
|
-
<Card bordered style={styles.infoCard}>
|
|
110
|
-
<View style={styles.topicHeaderRow}>
|
|
111
|
-
{/* Left Circle Icon */}
|
|
112
|
-
<View style={[styles.iconCircle, { backgroundColor: 'rgba(59, 130, 246, 0.1)' }]}>
|
|
113
|
-
<Icon name="file-text" size={20} color="#3B82F6" />
|
|
114
|
-
</View>
|
|
115
|
-
{/* Right details */}
|
|
116
|
-
<View style={styles.topicHeaderDetails}>
|
|
117
|
-
<Typography variant="h2" bold color={theme.textPrimary} style={styles.topicMainTitle}>
|
|
118
|
-
{activeTopic.title}
|
|
119
|
-
</Typography>
|
|
120
|
-
<Typography variant="caption" color={theme.textSecondary}>
|
|
121
|
-
{activeTopic.totalQuestions} Questions
|
|
122
|
-
</Typography>
|
|
123
|
-
</View>
|
|
124
|
-
</View>
|
|
125
|
-
|
|
126
|
-
{/* Launch Button inside the card box */}
|
|
127
|
-
<Button
|
|
128
|
-
title="Start QBank"
|
|
129
|
-
onPress={handleStart}
|
|
130
|
-
variant="primary"
|
|
131
|
-
style={[styles.startButton, { backgroundColor: theme.primary }]}
|
|
132
|
-
disabled={!activeTopic.questions || activeTopic.questions.length === 0}
|
|
133
|
-
/>
|
|
134
|
-
</Card>
|
|
135
|
-
|
|
136
|
-
{/* Glance Topics list */}
|
|
137
|
-
<View style={styles.glanceSection}>
|
|
138
|
-
<Typography variant="h2" bold color={theme.textPrimary} style={styles.glanceTitle}>
|
|
139
|
-
Topics at a Glance
|
|
140
|
-
</Typography>
|
|
141
|
-
<Typography variant="body" color={theme.textSecondary} style={styles.glanceSub}>
|
|
142
|
-
It's recommended that you thoroughly study these topics prior to attempting the QBank.
|
|
143
|
-
</Typography>
|
|
144
|
-
|
|
145
|
-
<View style={styles.bulletList}>
|
|
146
|
-
{glanceTopics.map((item, idx) => (
|
|
147
|
-
<View key={idx} style={styles.bulletRow}>
|
|
148
|
-
<View style={[styles.bulletDot, { backgroundColor: theme.primary }]} />
|
|
149
|
-
<Typography variant="body" color={theme.textPrimary} style={styles.bulletText}>
|
|
150
|
-
{item}
|
|
151
|
-
</Typography>
|
|
152
|
-
</View>
|
|
153
|
-
))}
|
|
154
|
-
</View>
|
|
155
|
-
</View>
|
|
156
|
-
|
|
157
|
-
</View>
|
|
158
|
-
</View>
|
|
159
|
-
</SafeAreaView>
|
|
160
|
-
);
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const styles = StyleSheet.create({
|
|
164
|
-
safeArea: {
|
|
165
|
-
flex: 1,
|
|
166
|
-
},
|
|
167
|
-
header: {
|
|
168
|
-
flexDirection: 'row',
|
|
169
|
-
justifyContent: 'space-between',
|
|
170
|
-
alignItems: 'center',
|
|
171
|
-
paddingHorizontal: 16,
|
|
172
|
-
paddingVertical: 12,
|
|
173
|
-
},
|
|
174
|
-
backButton: {
|
|
175
|
-
padding: 6,
|
|
176
|
-
},
|
|
177
|
-
headerTitle: {
|
|
178
|
-
fontSize: 18,
|
|
179
|
-
fontWeight: '700',
|
|
180
|
-
},
|
|
181
|
-
shareButton: {
|
|
182
|
-
padding: 6,
|
|
183
|
-
},
|
|
184
|
-
container: {
|
|
185
|
-
flex: 1,
|
|
186
|
-
},
|
|
187
|
-
content: {
|
|
188
|
-
flex: 1,
|
|
189
|
-
paddingHorizontal: 16,
|
|
190
|
-
paddingTop: 12,
|
|
191
|
-
},
|
|
192
|
-
categoryTitle: {
|
|
193
|
-
fontSize: 22,
|
|
194
|
-
marginBottom: 16,
|
|
195
|
-
},
|
|
196
|
-
infoCard: {
|
|
197
|
-
padding: 16,
|
|
198
|
-
borderRadius: 16,
|
|
199
|
-
backgroundColor: '#FFFFFF',
|
|
200
|
-
borderWidth: 1,
|
|
201
|
-
borderColor: '#E2E8F0',
|
|
202
|
-
},
|
|
203
|
-
topicHeaderRow: {
|
|
204
|
-
flexDirection: 'row',
|
|
205
|
-
alignItems: 'center',
|
|
206
|
-
marginBottom: 16,
|
|
207
|
-
},
|
|
208
|
-
iconCircle: {
|
|
209
|
-
width: 44,
|
|
210
|
-
height: 44,
|
|
211
|
-
borderRadius: 22,
|
|
212
|
-
justifyContent: 'center',
|
|
213
|
-
alignItems: 'center',
|
|
214
|
-
marginRight: 12,
|
|
215
|
-
},
|
|
216
|
-
topicHeaderDetails: {
|
|
217
|
-
flex: 1,
|
|
218
|
-
},
|
|
219
|
-
topicMainTitle: {
|
|
220
|
-
fontSize: 15,
|
|
221
|
-
lineHeight: 19,
|
|
222
|
-
marginBottom: 2,
|
|
223
|
-
},
|
|
224
|
-
startButton: {
|
|
225
|
-
width: '100%',
|
|
226
|
-
height: 46,
|
|
227
|
-
justifyContent: 'center',
|
|
228
|
-
alignItems: 'center',
|
|
229
|
-
borderRadius: 10,
|
|
230
|
-
},
|
|
231
|
-
glanceSection: {
|
|
232
|
-
marginTop: 24,
|
|
233
|
-
},
|
|
234
|
-
glanceTitle: {
|
|
235
|
-
fontSize: 16,
|
|
236
|
-
marginBottom: 6,
|
|
237
|
-
},
|
|
238
|
-
glanceSub: {
|
|
239
|
-
fontSize: 13,
|
|
240
|
-
lineHeight: 18,
|
|
241
|
-
marginBottom: 16,
|
|
242
|
-
},
|
|
243
|
-
bulletList: {
|
|
244
|
-
marginTop: 4,
|
|
245
|
-
},
|
|
246
|
-
bulletRow: {
|
|
247
|
-
flexDirection: 'row',
|
|
248
|
-
alignItems: 'center',
|
|
249
|
-
marginBottom: 12,
|
|
250
|
-
},
|
|
251
|
-
bulletDot: {
|
|
252
|
-
width: 6,
|
|
253
|
-
height: 6,
|
|
254
|
-
borderRadius: 3,
|
|
255
|
-
marginRight: 12,
|
|
256
|
-
},
|
|
257
|
-
bulletText: {
|
|
258
|
-
fontSize: 14,
|
|
259
|
-
},
|
|
260
|
-
});
|