react-native-elearn-ui 0.1.9 → 0.1.10

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 (34) hide show
  1. package/lib/module/index.js +1 -1
  2. package/lib/module/index.js.map +1 -1
  3. package/lib/module/screens/PearlChaptersScreen.js +357 -0
  4. package/lib/module/screens/PearlChaptersScreen.js.map +1 -0
  5. package/lib/module/screens/PearlReaderScreen.js +311 -0
  6. package/lib/module/screens/PearlReaderScreen.js.map +1 -0
  7. package/lib/module/screens/PearlsScreen.js +41 -631
  8. package/lib/module/screens/PearlsScreen.js.map +1 -1
  9. package/lib/module/screens/index.js +2 -0
  10. package/lib/module/screens/index.js.map +1 -1
  11. package/lib/module/screens/pearlsMockData.js +77 -0
  12. package/lib/module/screens/pearlsMockData.js.map +1 -0
  13. package/lib/typescript/src/index.d.ts +1 -1
  14. package/lib/typescript/src/index.d.ts.map +1 -1
  15. package/lib/typescript/src/screens/PearlChaptersScreen.d.ts +12 -0
  16. package/lib/typescript/src/screens/PearlChaptersScreen.d.ts.map +1 -0
  17. package/lib/typescript/src/screens/PearlReaderScreen.d.ts +13 -0
  18. package/lib/typescript/src/screens/PearlReaderScreen.d.ts.map +1 -0
  19. package/lib/typescript/src/screens/PearlsScreen.d.ts +2 -0
  20. package/lib/typescript/src/screens/PearlsScreen.d.ts.map +1 -1
  21. package/lib/typescript/src/screens/index.d.ts +2 -0
  22. package/lib/typescript/src/screens/index.d.ts.map +1 -1
  23. package/lib/typescript/src/screens/pearlsMockData.d.ts +3 -0
  24. package/lib/typescript/src/screens/pearlsMockData.d.ts.map +1 -0
  25. package/lib/typescript/src/types/index.d.ts +15 -0
  26. package/lib/typescript/src/types/index.d.ts.map +1 -1
  27. package/package.json +1 -1
  28. package/src/index.tsx +2 -0
  29. package/src/screens/PearlChaptersScreen.tsx +328 -0
  30. package/src/screens/PearlReaderScreen.tsx +304 -0
  31. package/src/screens/PearlsScreen.tsx +27 -602
  32. package/src/screens/index.ts +2 -0
  33. package/src/screens/pearlsMockData.ts +70 -0
  34. package/src/types/index.ts +17 -0
@@ -0,0 +1,304 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ View,
4
+ ScrollView,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ SafeAreaView,
8
+ StatusBar,
9
+ } from 'react-native';
10
+ import { useTheme } from '../context/ThemeContext';
11
+ import { Typography, Icon } from '../components';
12
+ import { MOCK_PEARLS_TOPICS } from './pearlsMockData';
13
+ import type { PearlTopic, PearlChapter } from '../types';
14
+
15
+ interface PearlReaderScreenProps {
16
+ topic?: PearlTopic;
17
+ topicId?: string;
18
+ chapter?: PearlChapter;
19
+ chapterId?: string;
20
+ onBack: () => void;
21
+ hideHeader?: boolean;
22
+ }
23
+
24
+ export const PearlReaderScreen: React.FC<PearlReaderScreenProps> = ({
25
+ topic,
26
+ topicId,
27
+ chapter,
28
+ chapterId,
29
+ onBack,
30
+ hideHeader = false,
31
+ }) => {
32
+ const theme = useTheme();
33
+
34
+ const activeTopic = topic || MOCK_PEARLS_TOPICS.find((t) => t.id === topicId);
35
+
36
+ // Flatten chapters for reader mode navigation
37
+ const flattenedChapters: PearlChapter[] = [];
38
+ if (activeTopic && activeTopic.sections) {
39
+ Object.keys(activeTopic.sections).forEach((sectionName) => {
40
+ const sectionChapters = activeTopic.sections?.[sectionName] || [];
41
+ flattenedChapters.push(...sectionChapters);
42
+ });
43
+ }
44
+
45
+ const initialIndex = chapterId
46
+ ? flattenedChapters.findIndex((c) => c.id === chapterId)
47
+ : chapter
48
+ ? flattenedChapters.findIndex((c) => c.id === chapter.id)
49
+ : 0;
50
+
51
+ const [activeChapterIndex, setActiveChapterIndex] = useState<number>(initialIndex >= 0 ? initialIndex : 0);
52
+ const [isCompleted, setIsCompleted] = useState(false);
53
+
54
+ const activeChapter = flattenedChapters[activeChapterIndex];
55
+
56
+ if (!activeChapter) {
57
+ return (
58
+ <SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
59
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}>
60
+ <Typography variant="h2" bold style={{ marginBottom: 12 }}>Chapter not found</Typography>
61
+ <TouchableOpacity
62
+ onPress={onBack}
63
+ style={{
64
+ paddingHorizontal: 20,
65
+ paddingVertical: 10,
66
+ borderRadius: 8,
67
+ backgroundColor: theme.primary,
68
+ }}
69
+ >
70
+ <Typography variant="body" bold color="#FFFFFF">Go Back</Typography>
71
+ </TouchableOpacity>
72
+ </View>
73
+ </SafeAreaView>
74
+ );
75
+ }
76
+
77
+ const handlePrevChapter = () => {
78
+ if (activeChapterIndex > 0) {
79
+ setActiveChapterIndex(activeChapterIndex - 1);
80
+ setIsCompleted(false);
81
+ }
82
+ };
83
+
84
+ const handleNextChapter = () => {
85
+ if (activeChapterIndex < flattenedChapters.length - 1) {
86
+ setActiveChapterIndex(activeChapterIndex + 1);
87
+ setIsCompleted(false);
88
+ }
89
+ };
90
+
91
+ return (
92
+ <SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
93
+ <StatusBar barStyle="dark-content" />
94
+
95
+ {/* Header */}
96
+ {!hideHeader && (
97
+ <View style={styles.header}>
98
+ <TouchableOpacity onPress={onBack} style={styles.backButton}>
99
+ <Icon name="arrow-left" size={20} color={theme.textPrimary} />
100
+ </TouchableOpacity>
101
+
102
+ <Typography variant="h2" bold style={styles.headerTitle}>
103
+ Pearls
104
+ </Typography>
105
+
106
+ <View style={styles.headerRightPlaceholder} />
107
+ </View>
108
+ )}
109
+
110
+ {/* Reader Container */}
111
+ <View style={styles.readerContainer}>
112
+ {/* Subheader progress banner */}
113
+ <View style={styles.readerSubHeader}>
114
+ <Typography variant="body" bold color={theme.textPrimary} style={styles.readerSubTitle}>
115
+ {activeChapter.title.split('.')[0] || activeChapter.title}
116
+ </Typography>
117
+ <Typography variant="body" bold color={theme.textSecondary}>
118
+ {activeChapterIndex + 1}/{flattenedChapters.length}
119
+ </Typography>
120
+ </View>
121
+
122
+ <ScrollView contentContainerStyle={styles.readerScroll} showsVerticalScrollIndicator={false}>
123
+ {activeChapter.bullets.map((bullet, idx) => {
124
+ const parts = bullet.split(':');
125
+ const boldPart = parts[0];
126
+ const rest = parts.slice(1).join(':');
127
+
128
+ return (
129
+ <View key={idx} style={styles.bulletRow}>
130
+ <Typography variant="body" color={theme.textPrimary} style={styles.bulletPointDot}>
131
+
132
+ </Typography>
133
+ <Typography variant="body" color={theme.textPrimary} style={styles.bulletText}>
134
+ {rest ? (
135
+ <>
136
+ <Typography variant="body" bold>{boldPart}:</Typography>
137
+ {rest}
138
+ </>
139
+ ) : (
140
+ bullet
141
+ )}
142
+ </Typography>
143
+ </View>
144
+ );
145
+ })}
146
+ </ScrollView>
147
+
148
+ {/* Checkbox status bar */}
149
+ <View style={styles.checkboxBar}>
150
+ <TouchableOpacity
151
+ activeOpacity={0.8}
152
+ onPress={() => setIsCompleted(!isCompleted)}
153
+ style={styles.checkboxRow}
154
+ >
155
+ <View style={[
156
+ styles.checkboxBox,
157
+ { borderColor: theme.border },
158
+ isCompleted && { backgroundColor: theme.primary, borderColor: theme.primary }
159
+ ]}>
160
+ {isCompleted && <View style={styles.checkboxInner} />}
161
+ </View>
162
+ <Typography variant="body" bold color={theme.textPrimary}>
163
+ Mark as Complete
164
+ </Typography>
165
+ </TouchableOpacity>
166
+ </View>
167
+
168
+ {/* Navigation bottom buttons */}
169
+ <View style={styles.footerRow}>
170
+ <TouchableOpacity
171
+ onPress={handlePrevChapter}
172
+ disabled={activeChapterIndex === 0}
173
+ style={[styles.footerBtn, activeChapterIndex === 0 && { opacity: 0.4 }]}
174
+ >
175
+ <Typography variant="body" bold color={theme.textPrimary}>
176
+ Prev
177
+ </Typography>
178
+ </TouchableOpacity>
179
+
180
+ <TouchableOpacity
181
+ onPress={handleNextChapter}
182
+ disabled={activeChapterIndex === flattenedChapters.length - 1}
183
+ style={[
184
+ styles.nextActionBtn,
185
+ { backgroundColor: theme.primary },
186
+ activeChapterIndex === flattenedChapters.length - 1 && { opacity: 0.4 }
187
+ ]}
188
+ >
189
+ <Typography variant="body" bold color="#FFFFFF">
190
+ Next
191
+ </Typography>
192
+ </TouchableOpacity>
193
+ </View>
194
+ </View>
195
+ </SafeAreaView>
196
+ );
197
+ };
198
+
199
+ const styles = StyleSheet.create({
200
+ safeArea: {
201
+ flex: 1,
202
+ },
203
+ header: {
204
+ flexDirection: 'row',
205
+ justifyContent: 'space-between',
206
+ alignItems: 'center',
207
+ paddingHorizontal: 16,
208
+ paddingVertical: 12,
209
+ },
210
+ backButton: {
211
+ padding: 6,
212
+ },
213
+ headerTitle: {
214
+ fontSize: 18,
215
+ fontWeight: '700',
216
+ },
217
+ headerRightPlaceholder: {
218
+ width: 32,
219
+ },
220
+ readerContainer: {
221
+ flex: 1,
222
+ },
223
+ readerSubHeader: {
224
+ flexDirection: 'row',
225
+ justifyContent: 'space-between',
226
+ alignItems: 'center',
227
+ paddingHorizontal: 16,
228
+ paddingVertical: 12,
229
+ borderBottomWidth: 1,
230
+ borderBottomColor: '#E2E8F0',
231
+ },
232
+ readerSubTitle: {
233
+ flex: 1,
234
+ fontSize: 14,
235
+ marginRight: 16,
236
+ },
237
+ readerScroll: {
238
+ paddingHorizontal: 16,
239
+ paddingVertical: 16,
240
+ },
241
+ bulletRow: {
242
+ flexDirection: 'row',
243
+ alignItems: 'flex-start',
244
+ marginBottom: 16,
245
+ },
246
+ bulletPointDot: {
247
+ fontSize: 18,
248
+ marginRight: 10,
249
+ lineHeight: 20,
250
+ },
251
+ bulletText: {
252
+ flex: 1,
253
+ fontSize: 14,
254
+ lineHeight: 22,
255
+ },
256
+ checkboxBar: {
257
+ paddingHorizontal: 16,
258
+ paddingVertical: 14,
259
+ borderTopWidth: 1,
260
+ borderTopColor: '#E2E8F0',
261
+ backgroundColor: '#F8FAFC',
262
+ },
263
+ checkboxRow: {
264
+ flexDirection: 'row',
265
+ alignItems: 'center',
266
+ },
267
+ checkboxBox: {
268
+ width: 20,
269
+ height: 20,
270
+ borderWidth: 2,
271
+ borderRadius: 4,
272
+ justifyContent: 'center',
273
+ alignItems: 'center',
274
+ marginRight: 10,
275
+ },
276
+ checkboxInner: {
277
+ width: 10,
278
+ height: 10,
279
+ borderRadius: 2,
280
+ backgroundColor: '#FFFFFF',
281
+ },
282
+ footerRow: {
283
+ flexDirection: 'row',
284
+ alignItems: 'center',
285
+ paddingHorizontal: 16,
286
+ paddingVertical: 12,
287
+ backgroundColor: '#FFFFFF',
288
+ borderTopWidth: 1,
289
+ borderTopColor: '#E2E8F0',
290
+ justifyContent: 'space-between',
291
+ },
292
+ footerBtn: {
293
+ paddingVertical: 8,
294
+ paddingHorizontal: 12,
295
+ },
296
+ nextActionBtn: {
297
+ paddingHorizontal: 24,
298
+ paddingVertical: 10,
299
+ borderRadius: 8,
300
+ minWidth: 80,
301
+ justifyContent: 'center',
302
+ alignItems: 'center',
303
+ },
304
+ });