react-native-elearn-ui 0.1.31 → 0.1.32

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 (29) hide show
  1. package/lib/module/components/Icon.js +9 -0
  2. package/lib/module/components/Icon.js.map +1 -1
  3. package/lib/module/index.js +1 -0
  4. package/lib/module/index.js.map +1 -1
  5. package/lib/module/screens/index.js +2 -0
  6. package/lib/module/screens/index.js.map +1 -1
  7. package/lib/module/screens/qbank/QBankOverviewScreen.js +435 -0
  8. package/lib/module/screens/qbank/QBankOverviewScreen.js.map +1 -0
  9. package/lib/module/screens/qbank/QBankSuccessScreen.js +336 -0
  10. package/lib/module/screens/qbank/QBankSuccessScreen.js.map +1 -0
  11. package/lib/typescript/src/components/Icon.d.ts +1 -1
  12. package/lib/typescript/src/components/Icon.d.ts.map +1 -1
  13. package/lib/typescript/src/index.d.ts +1 -0
  14. package/lib/typescript/src/index.d.ts.map +1 -1
  15. package/lib/typescript/src/screens/index.d.ts +2 -0
  16. package/lib/typescript/src/screens/index.d.ts.map +1 -1
  17. package/lib/typescript/src/screens/qbank/QBankOverviewScreen.d.ts +4 -0
  18. package/lib/typescript/src/screens/qbank/QBankOverviewScreen.d.ts.map +1 -0
  19. package/lib/typescript/src/screens/qbank/QBankSuccessScreen.d.ts +4 -0
  20. package/lib/typescript/src/screens/qbank/QBankSuccessScreen.d.ts.map +1 -0
  21. package/lib/typescript/src/types/index.d.ts +27 -0
  22. package/lib/typescript/src/types/index.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/components/Icon.tsx +6 -1
  25. package/src/index.tsx +1 -0
  26. package/src/screens/index.ts +2 -0
  27. package/src/screens/qbank/QBankOverviewScreen.tsx +392 -0
  28. package/src/screens/qbank/QBankSuccessScreen.tsx +292 -0
  29. package/src/types/index.ts +30 -0
@@ -0,0 +1,392 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ ScrollView,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ Animated,
8
+ Dimensions,
9
+ Platform,
10
+ } from 'react-native';
11
+ import { SafeAreaView } from 'react-native-safe-area-context';
12
+ import { useTheme } from '../../context/ThemeContext';
13
+ import { Typography, Icon } from '../../components';
14
+ import type { QBankOverviewScreenProps, QBankOverviewQuestion } from '../../types';
15
+
16
+ const { height: SCREEN_HEIGHT } = Dimensions.get('window');
17
+
18
+ type FilterType = 'all' | 'correct' | 'incorrect' | 'missed';
19
+
20
+ export const QBankOverviewScreen: React.FC<QBankOverviewScreenProps> = ({
21
+ topicTitle,
22
+ moduleTitle,
23
+ totalQuestions,
24
+ correctCount,
25
+ incorrectCount,
26
+ missedCount,
27
+ questions,
28
+ onBack,
29
+ onPressQuestion,
30
+ }) => {
31
+ const theme = useTheme();
32
+ const [filter, setFilter] = useState<FilterType>('all');
33
+ const [isSheetOpen, setIsSheetOpen] = useState(false);
34
+
35
+ // Animation value for Bottom Sheet
36
+ const translateY = useRef(new Animated.Value(SCREEN_HEIGHT)).current;
37
+ const fadeAnim = useRef(new Animated.Value(0)).current;
38
+
39
+ const percentage = Math.round((correctCount / totalQuestions) * 100) || 0;
40
+
41
+ const correctWidth = (correctCount / totalQuestions) * 100;
42
+ const incorrectWidth = (incorrectCount / totalQuestions) * 100;
43
+ const missedWidth = (missedCount / totalQuestions) * 100;
44
+
45
+ const filteredQuestions = questions.filter(q => filter === 'all' || q.status === filter);
46
+
47
+ useEffect(() => {
48
+ if (isSheetOpen) {
49
+ Animated.parallel([
50
+ Animated.timing(translateY, {
51
+ toValue: 0,
52
+ duration: 300,
53
+ useNativeDriver: true,
54
+ }),
55
+ Animated.timing(fadeAnim, {
56
+ toValue: 0.5,
57
+ duration: 300,
58
+ useNativeDriver: true,
59
+ }),
60
+ ]).start();
61
+ } else {
62
+ Animated.parallel([
63
+ Animated.timing(translateY, {
64
+ toValue: SCREEN_HEIGHT,
65
+ duration: 250,
66
+ useNativeDriver: true,
67
+ }),
68
+ Animated.timing(fadeAnim, {
69
+ toValue: 0,
70
+ duration: 250,
71
+ useNativeDriver: true,
72
+ }),
73
+ ]).start();
74
+ }
75
+ }, [isSheetOpen, translateY, fadeAnim]);
76
+
77
+ const renderStatusBadge = (status: QBankOverviewQuestion['status']) => {
78
+ let color = '';
79
+ let text = '';
80
+
81
+ switch (status) {
82
+ case 'correct':
83
+ color = theme.success;
84
+ text = 'Correct';
85
+ break;
86
+ case 'incorrect':
87
+ color = '#EF4444';
88
+ text = 'InCorrect';
89
+ break;
90
+ case 'missed':
91
+ color = '#F59E0B';
92
+ text = 'Missed';
93
+ break;
94
+ }
95
+
96
+ return (
97
+ <View style={[styles.statusBadge, { borderColor: color }]}>
98
+ <Typography variant="caption" color={color} style={{ fontSize: 10, fontWeight: '600' }}>
99
+ {text}
100
+ </Typography>
101
+ </View>
102
+ );
103
+ };
104
+
105
+ return (
106
+ <SafeAreaView style={styles.container} edges={['top', 'bottom']}>
107
+ {/* Header */}
108
+ <View style={styles.header}>
109
+ <TouchableOpacity onPress={onBack} style={styles.headerBtn}>
110
+ <Icon name="chevron-left" size={24} color={theme.textPrimary} />
111
+ </TouchableOpacity>
112
+ <Typography variant="h3" bold color={theme.textPrimary} style={styles.headerTitle}>
113
+ Overview
114
+ </Typography>
115
+ <View style={styles.headerBtn} />
116
+ </View>
117
+
118
+ <ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
119
+ {/* Sub Header */}
120
+ <View style={styles.subHeader}>
121
+ <Typography variant="h3" bold color={theme.textPrimary}>
122
+ {topicTitle} <Typography variant="body" color={theme.textSecondary}>• {moduleTitle}</Typography>
123
+ </Typography>
124
+ <TouchableOpacity onPress={() => setIsSheetOpen(true)} style={styles.filterBtn}>
125
+ <Icon name="filter" size={20} color={theme.textSecondary} />
126
+ </TouchableOpacity>
127
+ </View>
128
+
129
+ {/* Summary Card */}
130
+ <View style={styles.card}>
131
+ <Typography variant="caption" color={theme.textSecondary} style={styles.totalText}>
132
+ Total Question {totalQuestions}
133
+ </Typography>
134
+
135
+ <View style={styles.statsRow}>
136
+ <View style={styles.statsLabels}>
137
+ <Typography variant="caption" color={theme.success} style={styles.statLabel}>
138
+ {String(correctCount).padStart(2, '0')} Correct
139
+ </Typography>
140
+ <Typography variant="caption" color="#EF4444" style={styles.statLabel}>
141
+ {String(incorrectCount).padStart(2, '0')} Incorrect
142
+ </Typography>
143
+ <Typography variant="caption" color="#F59E0B" style={styles.statLabel}>
144
+ {String(missedCount).padStart(2, '0')} Missed
145
+ </Typography>
146
+ </View>
147
+
148
+ <View style={styles.percentageBlock}>
149
+ <Typography variant="h3" bold color={theme.textPrimary}>
150
+ {percentage}%
151
+ </Typography>
152
+ <Typography variant="caption" color={theme.textSecondary} style={{fontSize: 10}}>
153
+ Correct
154
+ </Typography>
155
+ </View>
156
+ </View>
157
+
158
+ <View style={styles.progressBarContainer}>
159
+ {correctWidth > 0 && <View style={[styles.progressSegment, { width: `${correctWidth}%`, backgroundColor: theme.success }]} />}
160
+ {incorrectWidth > 0 && <View style={[styles.progressSegment, { width: `${incorrectWidth}%`, backgroundColor: '#EF4444' }]} />}
161
+ {missedWidth > 0 && <View style={[styles.progressSegment, { width: `${missedWidth}%`, backgroundColor: '#F59E0B' }]} />}
162
+ {totalQuestions === 0 && <View style={[styles.progressSegment, { width: '100%', backgroundColor: '#E5E7EB' }]} />}
163
+ </View>
164
+ </View>
165
+
166
+ {/* Question List */}
167
+ <View style={styles.listContainer}>
168
+ {filteredQuestions.map((q) => (
169
+ <TouchableOpacity
170
+ key={q.id}
171
+ style={styles.listItem}
172
+ onPress={() => onPressQuestion?.(q.id)}
173
+ >
174
+ <View style={styles.listTextContainer}>
175
+ <Typography variant="body" bold color={theme.textPrimary} style={styles.listText}>
176
+ {q.number}. {q.title}
177
+ </Typography>
178
+ </View>
179
+ {renderStatusBadge(q.status)}
180
+ </TouchableOpacity>
181
+ ))}
182
+ </View>
183
+ </ScrollView>
184
+
185
+ {/* Bottom Sheet Backdrop */}
186
+ {isSheetOpen && (
187
+ <Animated.View
188
+ style={[styles.backdrop, { opacity: fadeAnim }]}
189
+ pointerEvents="auto"
190
+ >
191
+ <TouchableOpacity
192
+ style={StyleSheet.absoluteFill}
193
+ activeOpacity={1}
194
+ onPress={() => setIsSheetOpen(false)}
195
+ />
196
+ </Animated.View>
197
+ )}
198
+
199
+ {/* Bottom Sheet Modal */}
200
+ <Animated.View
201
+ style={[
202
+ styles.bottomSheet,
203
+ { transform: [{ translateY }] }
204
+ ]}
205
+ >
206
+ <View style={styles.sheetHandle} />
207
+ <Typography variant="h3" bold color={theme.textPrimary} style={styles.sheetTitle}>
208
+ Filter Questions
209
+ </Typography>
210
+
211
+ {(['all', 'correct', 'incorrect', 'missed'] as FilterType[]).map((type) => (
212
+ <TouchableOpacity
213
+ key={type}
214
+ style={styles.sheetOption}
215
+ onPress={() => {
216
+ setFilter(type);
217
+ setIsSheetOpen(false);
218
+ }}
219
+ >
220
+ <Typography variant="body" color={filter === type ? theme.primary : theme.textPrimary} style={{textTransform: 'capitalize'}}>
221
+ {type}
222
+ </Typography>
223
+ {filter === type && <Icon name="check" size={20} color={theme.primary} />}
224
+ </TouchableOpacity>
225
+ ))}
226
+ </Animated.View>
227
+ </SafeAreaView>
228
+ );
229
+ };
230
+
231
+ const styles = StyleSheet.create({
232
+ container: {
233
+ flex: 1,
234
+ backgroundColor: '#F9FAFB',
235
+ },
236
+ header: {
237
+ flexDirection: 'row',
238
+ alignItems: 'center',
239
+ paddingHorizontal: 16,
240
+ paddingVertical: 12,
241
+ backgroundColor: '#FFFFFF',
242
+ },
243
+ headerBtn: {
244
+ width: 40,
245
+ height: 40,
246
+ justifyContent: 'center',
247
+ },
248
+ headerTitle: {
249
+ flex: 1,
250
+ textAlign: 'center',
251
+ fontSize: 18,
252
+ },
253
+ scrollContent: {
254
+ padding: 16,
255
+ paddingBottom: 40,
256
+ },
257
+ subHeader: {
258
+ flexDirection: 'row',
259
+ alignItems: 'center',
260
+ justifyContent: 'space-between',
261
+ marginBottom: 20,
262
+ marginTop: 8,
263
+ },
264
+ filterBtn: {
265
+ width: 32,
266
+ height: 32,
267
+ borderRadius: 16,
268
+ borderWidth: 1,
269
+ borderColor: '#D1D5DB',
270
+ justifyContent: 'center',
271
+ alignItems: 'center',
272
+ backgroundColor: '#FFFFFF',
273
+ },
274
+ card: {
275
+ backgroundColor: '#FFFFFF',
276
+ borderRadius: 12,
277
+ padding: 16,
278
+ marginBottom: 24,
279
+ shadowColor: '#000',
280
+ shadowOffset: { width: 0, height: 2 },
281
+ shadowOpacity: 0.05,
282
+ shadowRadius: 4,
283
+ elevation: 2,
284
+ },
285
+ totalText: {
286
+ marginBottom: 12,
287
+ },
288
+ statsRow: {
289
+ flexDirection: 'row',
290
+ justifyContent: 'space-between',
291
+ alignItems: 'flex-end',
292
+ marginBottom: 12,
293
+ },
294
+ statsLabels: {
295
+ flexDirection: 'row',
296
+ alignItems: 'center',
297
+ flex: 1,
298
+ flexWrap: 'wrap',
299
+ },
300
+ statLabel: {
301
+ marginRight: 16,
302
+ fontSize: 12,
303
+ marginBottom: 4,
304
+ },
305
+ percentageBlock: {
306
+ alignItems: 'center',
307
+ justifyContent: 'center',
308
+ },
309
+ progressBarContainer: {
310
+ height: 8,
311
+ backgroundColor: '#E5E7EB',
312
+ borderRadius: 4,
313
+ flexDirection: 'row',
314
+ overflow: 'hidden',
315
+ },
316
+ progressSegment: {
317
+ height: '100%',
318
+ },
319
+ listContainer: {
320
+ gap: 12,
321
+ },
322
+ listItem: {
323
+ backgroundColor: '#FFFFFF',
324
+ borderRadius: 8,
325
+ padding: 16,
326
+ flexDirection: 'row',
327
+ alignItems: 'center',
328
+ justifyContent: 'space-between',
329
+ shadowColor: '#000',
330
+ shadowOffset: { width: 0, height: 1 },
331
+ shadowOpacity: 0.02,
332
+ shadowRadius: 2,
333
+ elevation: 1,
334
+ },
335
+ listTextContainer: {
336
+ flex: 1,
337
+ paddingRight: 12,
338
+ },
339
+ listText: {
340
+ fontSize: 14,
341
+ lineHeight: 20,
342
+ },
343
+ statusBadge: {
344
+ paddingHorizontal: 12,
345
+ paddingVertical: 4,
346
+ borderRadius: 12,
347
+ borderWidth: 1,
348
+ },
349
+
350
+ // Bottom Sheet Styles
351
+ backdrop: {
352
+ ...StyleSheet.absoluteFillObject,
353
+ backgroundColor: '#000',
354
+ zIndex: 10,
355
+ },
356
+ bottomSheet: {
357
+ position: 'absolute',
358
+ bottom: 0,
359
+ left: 0,
360
+ right: 0,
361
+ backgroundColor: '#FFFFFF',
362
+ borderTopLeftRadius: 24,
363
+ borderTopRightRadius: 24,
364
+ padding: 24,
365
+ paddingBottom: Platform.OS === 'ios' ? 40 : 24,
366
+ zIndex: 20,
367
+ shadowColor: '#000',
368
+ shadowOffset: { width: 0, height: -4 },
369
+ shadowOpacity: 0.1,
370
+ shadowRadius: 8,
371
+ elevation: 10,
372
+ },
373
+ sheetHandle: {
374
+ width: 40,
375
+ height: 4,
376
+ backgroundColor: '#D1D5DB',
377
+ borderRadius: 2,
378
+ alignSelf: 'center',
379
+ marginBottom: 20,
380
+ },
381
+ sheetTitle: {
382
+ marginBottom: 16,
383
+ },
384
+ sheetOption: {
385
+ flexDirection: 'row',
386
+ alignItems: 'center',
387
+ justifyContent: 'space-between',
388
+ paddingVertical: 16,
389
+ borderBottomWidth: 1,
390
+ borderBottomColor: '#F3F4F6',
391
+ },
392
+ });
@@ -0,0 +1,292 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ View,
4
+ ScrollView,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ TextInput,
8
+ KeyboardAvoidingView,
9
+ Platform,
10
+ } from 'react-native';
11
+ import { SafeAreaView } from 'react-native-safe-area-context';
12
+ import { useTheme } from '../../context/ThemeContext';
13
+ import { Typography, Icon, Button } from '../../components';
14
+ import type { QBankSuccessScreenProps } from '../../types';
15
+
16
+ export const QBankSuccessScreen: React.FC<QBankSuccessScreenProps> = ({
17
+ moduleTitle,
18
+ completedDate,
19
+ totalQuestions,
20
+ correctCount,
21
+ incorrectCount,
22
+ missedCount,
23
+ onBack,
24
+ onSubmitFeedback,
25
+ }) => {
26
+ const theme = useTheme();
27
+ const [rating, setRating] = useState(0);
28
+ const [feedback, setFeedback] = useState('');
29
+
30
+ const percentage = Math.round((correctCount / totalQuestions) * 100) || 0;
31
+
32
+ // Calculate segments for the progress bar (percentages of the width)
33
+ const correctWidth = (correctCount / totalQuestions) * 100;
34
+ const incorrectWidth = (incorrectCount / totalQuestions) * 100;
35
+ const missedWidth = (missedCount / totalQuestions) * 100;
36
+
37
+ return (
38
+ <SafeAreaView style={styles.container} edges={['top', 'bottom']}>
39
+ <KeyboardAvoidingView
40
+ style={styles.container}
41
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
42
+ >
43
+ <ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
44
+ {/* Header */}
45
+ <View style={styles.header}>
46
+ <TouchableOpacity onPress={onBack} style={styles.headerIconBtnLeft}>
47
+ <Icon name="chevron-left" size={24} color={theme.textPrimary} />
48
+ </TouchableOpacity>
49
+ </View>
50
+
51
+ {/* Success Icon & Title */}
52
+ <View style={styles.successHeader}>
53
+ <View style={styles.iconCircle}>
54
+ <Icon name="check" size={40} color="#FFFFFF" />
55
+ </View>
56
+ <Typography variant="h2" bold color={theme.textPrimary} style={styles.successTitle}>
57
+ Module Completed
58
+ </Typography>
59
+ </View>
60
+
61
+ {/* Summary Card */}
62
+ <View style={styles.card}>
63
+ <View style={styles.cardHeader}>
64
+ <Typography variant="h3" bold color={theme.textPrimary}>
65
+ {moduleTitle}
66
+ </Typography>
67
+ <Typography variant="caption" color={theme.textSecondary} style={styles.dateText}>
68
+ Completed on {completedDate}
69
+ </Typography>
70
+ </View>
71
+
72
+ <View style={styles.divider} />
73
+
74
+ <View style={styles.statsSection}>
75
+ <Typography variant="caption" color={theme.textSecondary} style={styles.totalText}>
76
+ Total Question {totalQuestions}
77
+ </Typography>
78
+
79
+ <View style={styles.statsRow}>
80
+ <View style={styles.statsLabels}>
81
+ <Typography variant="caption" color={theme.success} style={styles.statLabel}>
82
+ {String(correctCount).padStart(2, '0')} Correct
83
+ </Typography>
84
+ <Typography variant="caption" color="#EF4444" style={styles.statLabel}>
85
+ {String(incorrectCount).padStart(2, '0')} Incorrect
86
+ </Typography>
87
+ <Typography variant="caption" color="#F59E0B" style={styles.statLabel}>
88
+ {String(missedCount).padStart(2, '0')} Missed
89
+ </Typography>
90
+ </View>
91
+
92
+ <View style={styles.percentageBlock}>
93
+ <Typography variant="h3" bold color={theme.textPrimary}>
94
+ {percentage}%
95
+ </Typography>
96
+ <Typography variant="caption" color={theme.textSecondary} style={{fontSize: 10}}>
97
+ Correct
98
+ </Typography>
99
+ </View>
100
+ </View>
101
+
102
+ {/* Multi-color Progress Bar */}
103
+ <View style={styles.progressBarContainer}>
104
+ {correctWidth > 0 && <View style={[styles.progressSegment, { width: `${correctWidth}%`, backgroundColor: theme.success }]} />}
105
+ {incorrectWidth > 0 && <View style={[styles.progressSegment, { width: `${incorrectWidth}%`, backgroundColor: '#EF4444' }]} />}
106
+ {missedWidth > 0 && <View style={[styles.progressSegment, { width: `${missedWidth}%`, backgroundColor: '#F59E0B' }]} />}
107
+ {/* Fallback empty bar if no questions */}
108
+ {totalQuestions === 0 && <View style={[styles.progressSegment, { width: '100%', backgroundColor: '#E5E7EB' }]} />}
109
+ </View>
110
+ </View>
111
+ </View>
112
+
113
+ {/* Feedback Section */}
114
+ <View style={styles.feedbackSection}>
115
+ <Typography variant="h3" bold color={theme.textPrimary} style={styles.feedbackTitle}>
116
+ How was your QBank{'\n'}taking experience?
117
+ </Typography>
118
+ <Typography variant="body" color={theme.textSecondary} style={styles.feedbackSubtitle}>
119
+ Your feedback will help us improve your QBank experience
120
+ </Typography>
121
+
122
+ <View style={styles.starsContainer}>
123
+ {[1, 2, 3, 4, 5].map((star) => (
124
+ <TouchableOpacity key={star} onPress={() => setRating(star)}>
125
+ <Icon
126
+ name="star"
127
+ size={36}
128
+ color={star <= rating ? '#EAB308' : '#D1D5DB'}
129
+ />
130
+ </TouchableOpacity>
131
+ ))}
132
+ </View>
133
+
134
+ <TextInput
135
+ style={styles.textInput}
136
+ placeholder="Type Your Feedback Here"
137
+ placeholderTextColor="#9CA3AF"
138
+ multiline
139
+ numberOfLines={4}
140
+ value={feedback}
141
+ onChangeText={setFeedback}
142
+ />
143
+
144
+ <Button
145
+ title="Submit"
146
+ onPress={() => onSubmitFeedback?.(rating, feedback)}
147
+ style={styles.submitBtn}
148
+ />
149
+ </View>
150
+ </ScrollView>
151
+ </KeyboardAvoidingView>
152
+ </SafeAreaView>
153
+ );
154
+ };
155
+
156
+ const styles = StyleSheet.create({
157
+ container: {
158
+ flex: 1,
159
+ backgroundColor: '#F9FAFB',
160
+ },
161
+ scrollContent: {
162
+ padding: 20,
163
+ paddingBottom: 40,
164
+ },
165
+ header: {
166
+ marginBottom: 20,
167
+ },
168
+ headerIconBtnLeft: {
169
+ width: 40,
170
+ height: 40,
171
+ justifyContent: 'center',
172
+ alignItems: 'flex-start',
173
+ },
174
+ successHeader: {
175
+ alignItems: 'center',
176
+ marginBottom: 32,
177
+ },
178
+ iconCircle: {
179
+ width: 80,
180
+ height: 80,
181
+ borderRadius: 40,
182
+ backgroundColor: '#10B981', // Success green
183
+ justifyContent: 'center',
184
+ alignItems: 'center',
185
+ shadowColor: '#10B981',
186
+ shadowOffset: { width: 0, height: 4 },
187
+ shadowOpacity: 0.3,
188
+ shadowRadius: 8,
189
+ elevation: 8,
190
+ marginBottom: 16,
191
+ },
192
+ successTitle: {
193
+ fontSize: 20,
194
+ },
195
+ card: {
196
+ backgroundColor: '#FFFFFF',
197
+ borderRadius: 12,
198
+ borderWidth: 1,
199
+ borderColor: '#F3F4F6',
200
+ shadowColor: '#000',
201
+ shadowOffset: { width: 0, height: 2 },
202
+ shadowOpacity: 0.05,
203
+ shadowRadius: 8,
204
+ elevation: 2,
205
+ marginBottom: 40,
206
+ },
207
+ cardHeader: {
208
+ padding: 16,
209
+ },
210
+ dateText: {
211
+ marginTop: 4,
212
+ },
213
+ divider: {
214
+ height: 1,
215
+ backgroundColor: '#F3F4F6',
216
+ },
217
+ statsSection: {
218
+ padding: 16,
219
+ },
220
+ totalText: {
221
+ marginBottom: 8,
222
+ },
223
+ statsRow: {
224
+ flexDirection: 'row',
225
+ justifyContent: 'space-between',
226
+ alignItems: 'flex-end',
227
+ marginBottom: 12,
228
+ },
229
+ statsLabels: {
230
+ flexDirection: 'row',
231
+ alignItems: 'center',
232
+ flex: 1,
233
+ flexWrap: 'wrap',
234
+ },
235
+ statLabel: {
236
+ marginRight: 16,
237
+ fontSize: 12,
238
+ marginBottom: 4,
239
+ },
240
+ percentageBlock: {
241
+ alignItems: 'center',
242
+ justifyContent: 'center',
243
+ },
244
+ progressBarContainer: {
245
+ height: 8,
246
+ backgroundColor: '#E5E7EB',
247
+ borderRadius: 4,
248
+ flexDirection: 'row',
249
+ overflow: 'hidden',
250
+ },
251
+ progressSegment: {
252
+ height: '100%',
253
+ },
254
+ feedbackSection: {
255
+ alignItems: 'center',
256
+ },
257
+ feedbackTitle: {
258
+ textAlign: 'center',
259
+ fontSize: 18,
260
+ marginBottom: 8,
261
+ lineHeight: 26,
262
+ },
263
+ feedbackSubtitle: {
264
+ textAlign: 'center',
265
+ fontSize: 12,
266
+ marginBottom: 24,
267
+ paddingHorizontal: 20,
268
+ },
269
+ starsContainer: {
270
+ flexDirection: 'row',
271
+ justifyContent: 'center',
272
+ gap: 12, // Space between stars
273
+ marginBottom: 32,
274
+ },
275
+ textInput: {
276
+ width: '100%',
277
+ height: 120,
278
+ backgroundColor: '#FFFFFF',
279
+ borderWidth: 1,
280
+ borderColor: '#10B981', // Green border as in design
281
+ borderRadius: 8,
282
+ padding: 16,
283
+ fontSize: 14,
284
+ color: '#1F2937',
285
+ marginBottom: 24,
286
+ },
287
+ submitBtn: {
288
+ backgroundColor: '#10B981',
289
+ paddingHorizontal: 40,
290
+ borderRadius: 8,
291
+ },
292
+ });