vorqard-ai-sdk 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.
@@ -0,0 +1,610 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ FlatList,
8
+ KeyboardAvoidingView,
9
+ Platform,
10
+ ActivityIndicator,
11
+ ScrollView,
12
+ Image,
13
+ StatusBar,
14
+ Dimensions,
15
+ Alert,
16
+ } from 'react-native';
17
+ import Ionicons from 'react-native-vector-icons/Ionicons';
18
+ import LinearGradient from 'react-native-linear-gradient';
19
+ import { SafeAreaView } from 'react-native-safe-area-context';
20
+
21
+ import { useHealthChat } from '../hooks/useHealthChat';
22
+ import { MessageBubble, InputPanel } from '../components/ChatComponents';
23
+
24
+ const { width: SW } = Dimensions.get('window');
25
+
26
+ const AI_ACTIONS = [
27
+ {
28
+ id: 'analyze_report',
29
+ title: 'Analyze Report',
30
+ desc: 'Upload and understand your medical reports',
31
+ icon: 'document-text',
32
+ colors: ['#EEF2FF', '#DBEAFE'],
33
+ iconColor: '#3B82F6',
34
+ },
35
+ {
36
+ id: 'explain_prescription',
37
+ title: 'Explain Prescription',
38
+ desc: 'Understand your medicines better',
39
+ icon: 'medical',
40
+ colors: ['#FFF7ED', '#FFEDD5'],
41
+ iconColor: '#F97316',
42
+ },
43
+ {
44
+ id: 'book_appointment',
45
+ title: 'Book Appointment',
46
+ desc: 'View and manage appointments',
47
+ icon: 'calendar',
48
+ colors: ['#FFF1F2', '#FFE4E6'],
49
+ iconColor: '#EF4444',
50
+ },
51
+ {
52
+ id: 'medical_history',
53
+ title: 'Medical History',
54
+ desc: 'View your health history',
55
+ icon: 'newspaper',
56
+ colors: ['#F0FDFA', '#CCFBF1'],
57
+ iconColor: '#14B8A6',
58
+ },
59
+ {
60
+ id: 'find_doctor',
61
+ title: 'Find Doctor',
62
+ desc: 'Find the right doctor for you',
63
+ icon: 'person',
64
+ colors: ['#F5F3FF', '#EDE9FE'],
65
+ iconColor: '#8B5CF6',
66
+ },
67
+ {
68
+ id: 'voice_assistant',
69
+ title: 'Voice Assistant',
70
+ desc: 'Talk to Vorqard AI with your voice',
71
+ icon: 'mic',
72
+ colors: ['#FFF7ED', '#FFEDD5'],
73
+ iconColor: '#F97316',
74
+ },
75
+ ];
76
+
77
+ export const AIHealthChatScreen = ({
78
+ patientName = '',
79
+ onClose,
80
+ aiLogo,
81
+ onAnalyzeReportPress,
82
+ }) => {
83
+ const {
84
+ messages,
85
+ inputText,
86
+ setInputText,
87
+ loading,
88
+ flatListRef,
89
+ loadChatContext,
90
+ sendMessage,
91
+ patientContext,
92
+ clearChat,
93
+ } = useHealthChat(patientName);
94
+
95
+ const [chatMode, setChatMode] = useState(false); // false = hub view, true = chat view
96
+
97
+ useEffect(() => {
98
+ loadChatContext();
99
+ // If there are existing messages, jump straight to chat mode
100
+ if (messages.length > 0) setChatMode(true);
101
+ }, []);
102
+
103
+ // When user sends a message, switch to chat mode
104
+ const handleSend = (text) => {
105
+ setChatMode(true);
106
+ sendMessage(text);
107
+ };
108
+
109
+ // Start a new conversation
110
+ const handleNewChat = () => {
111
+ clearChat();
112
+ setChatMode(false);
113
+ };
114
+
115
+ // ─── Welcome Hero Card ─────────────────────────────────────────────────────
116
+ const renderHeroCard = () => (
117
+ <View style={styles.heroCard}>
118
+ {/* Decorative blob */}
119
+ <View style={styles.heroBlobRight} />
120
+ <View style={styles.heroBlobLeft} />
121
+
122
+ <View style={styles.heroTopRow}>
123
+ <View style={styles.heroLeft}>
124
+ {aiLogo ? (
125
+ <Image source={aiLogo} style={styles.heroAvatar} />
126
+ ) : (
127
+ <View style={styles.heroAvatarFallback}>
128
+ <Ionicons name="sparkles" size={18} color="#FFF" />
129
+ </View>
130
+ )}
131
+ <View style={{ marginLeft: 10, flex: 1 }}>
132
+ <Text style={styles.heroGreeting}>
133
+ Hi {patientName || 'there'}! 👋
134
+ </Text>
135
+ <Text style={styles.heroBody}>
136
+ I see your last visit was for{'\n'}
137
+ <Text style={styles.heroHighlight}>
138
+ {patientContext?.diagnosis || '...'}
139
+ </Text>
140
+ {' '}on{' '}
141
+ <Text style={styles.heroHighlight}>
142
+ {patientContext?.date || '...'}
143
+ </Text>.
144
+ </Text>
145
+ <Text style={styles.heroSub}>How can I help you today?</Text>
146
+ </View>
147
+ </View>
148
+ {/* Medical clipboard icon */}
149
+ <View style={styles.heroIllustration}>
150
+ <Ionicons name="clipboard" size={42} color="#BFDBFE" />
151
+ </View>
152
+ </View>
153
+
154
+ {/* Snapshot row */}
155
+ <View style={styles.snapshotRow}>
156
+ <View style={styles.snapshotItem}>
157
+ <View style={[styles.snapshotIcon, { backgroundColor: '#EEF2FF' }]}>
158
+ <Ionicons name="calendar-outline" size={16} color="#3B82F6" />
159
+ </View>
160
+ <Text style={styles.snapshotLabel}>Last Visit</Text>
161
+ <Text style={styles.snapshotValue}>{patientContext?.date || '—'}</Text>
162
+ </View>
163
+ <View style={styles.snapshotDivider} />
164
+ <View style={styles.snapshotItem}>
165
+ <View style={[styles.snapshotIcon, { backgroundColor: '#F5F3FF' }]}>
166
+ <Ionicons name="medkit-outline" size={16} color="#8B5CF6" />
167
+ </View>
168
+ <Text style={styles.snapshotLabel}>Condition</Text>
169
+ <Text style={styles.snapshotValue} numberOfLines={1}>
170
+ {patientContext?.diagnosis || '—'}
171
+ </Text>
172
+ </View>
173
+ <View style={styles.snapshotDivider} />
174
+ <View style={styles.snapshotItem}>
175
+ <View style={[styles.snapshotIcon, { backgroundColor: '#ECFDF5' }]}>
176
+ <Ionicons name="shield-checkmark-outline" size={16} color="#10B981" />
177
+ </View>
178
+ <Text style={styles.snapshotLabel}>Status</Text>
179
+ <Text style={[styles.snapshotValue, { color: '#10B981' }]}>
180
+ {patientContext?.status || 'Completed'}
181
+ </Text>
182
+ </View>
183
+ </View>
184
+ </View>
185
+ );
186
+
187
+ // ─── Actions Grid ──────────────────────────────────────────────────────────
188
+ const renderActionsGrid = () => (
189
+ <View style={styles.actionsSection}>
190
+ <Text style={styles.actionsSectionTitle}>How can I help you?</Text>
191
+ <View style={styles.actionsGrid}>
192
+ {AI_ACTIONS.map((action) => (
193
+ <TouchableOpacity
194
+ key={action.id}
195
+ style={styles.actionCard}
196
+ onPress={() => {
197
+ if (action.id === 'analyze_report') {
198
+ if (onAnalyzeReportPress) {
199
+ onAnalyzeReportPress();
200
+ } else {
201
+ Alert.alert("Coming Soon", "Report Analysis Coming Soon");
202
+ }
203
+ } else if (action.id === 'find_doctor') {
204
+ Alert.alert("Coming Soon", "Coming Soon");
205
+ } else if (action.id === 'voice_assistant') {
206
+ Alert.alert("Coming Soon", "Voice Feature Coming Soon");
207
+ } else {
208
+ handleSend(action.title);
209
+ }
210
+ }}
211
+ activeOpacity={0.7}
212
+ >
213
+ <LinearGradient
214
+ colors={action.colors}
215
+ style={styles.actionIconCircle}
216
+ start={{ x: 0, y: 0 }}
217
+ end={{ x: 1, y: 1 }}
218
+ >
219
+ <Ionicons name={action.icon} size={24} color={action.iconColor} />
220
+ </LinearGradient>
221
+ <Text style={styles.actionTitle}>{action.title}</Text>
222
+ <Text style={styles.actionDesc}>{action.desc}</Text>
223
+ </TouchableOpacity>
224
+ ))}
225
+ </View>
226
+ </View>
227
+ );
228
+
229
+ // ─── Empty state / Today divider ──────────────────────────────────────────
230
+ const renderTodayState = () => (
231
+ <View style={styles.todayContainer}>
232
+ <View style={styles.todayDividerRow}>
233
+ <View style={styles.todayLine} />
234
+ <View style={styles.todayBadge}>
235
+ <Text style={styles.todayBadgeText}>Today</Text>
236
+ </View>
237
+ <View style={styles.todayLine} />
238
+ </View>
239
+ <View style={styles.emptyStateBox}>
240
+ <Text style={styles.emptyStateSparkle}>✨ ✦</Text>
241
+ <Text style={styles.emptyStateTitle}>
242
+ Your AI health assistant is here to help.
243
+ </Text>
244
+ <Text style={styles.emptyStateBody}>
245
+ Ask anything about your health, reports, medicines and more.
246
+ </Text>
247
+ </View>
248
+ </View>
249
+ );
250
+
251
+ // ─── Hub content (before any chat) ────────────────────────────────────────
252
+ const renderHubContent = () => (
253
+ <ScrollView
254
+ style={styles.hubScroll}
255
+ contentContainerStyle={styles.hubScrollContent}
256
+ showsVerticalScrollIndicator={false}
257
+ keyboardShouldPersistTaps="handled"
258
+ >
259
+ {renderHeroCard()}
260
+ {renderActionsGrid()}
261
+ {renderTodayState()}
262
+ </ScrollView>
263
+ );
264
+
265
+ // ─── Chat content (after first message) ───────────────────────────────────
266
+ const renderChatContent = () => (
267
+ <FlatList
268
+ ref={flatListRef}
269
+ data={messages}
270
+ keyExtractor={(_, i) => i.toString()}
271
+ renderItem={({ item }) => (
272
+ <MessageBubble
273
+ item={item}
274
+ aiLogo={aiLogo}
275
+ onOptionPress={(opt) => handleSend(opt.label)}
276
+ />
277
+ )}
278
+ contentContainerStyle={styles.flatListContent}
279
+ onContentSizeChange={() => flatListRef.current?.scrollToEnd({ animated: true })}
280
+ onLayout={() => flatListRef.current?.scrollToEnd({ animated: true })}
281
+ showsVerticalScrollIndicator={false}
282
+ ListEmptyComponent={
283
+ loading ? (
284
+ <ActivityIndicator style={{ marginTop: 60 }} color="#3B82F6" size="large" />
285
+ ) : null
286
+ }
287
+ />
288
+ );
289
+
290
+ return (
291
+ <SafeAreaView style={styles.safeArea} edges={['top', 'bottom']}>
292
+ <StatusBar barStyle="dark-content" backgroundColor="#EEF2FF" />
293
+
294
+ {/* ─── Header Bar ───────────────────────────────────────────────────── */}
295
+ <View style={styles.header}>
296
+ {onClose ? (
297
+ <TouchableOpacity onPress={onClose} style={styles.headerBtn} activeOpacity={0.7}>
298
+ <Ionicons name="arrow-back" size={22} color="#1E293B" />
299
+ </TouchableOpacity>
300
+ ) : <View style={styles.headerBtn} />}
301
+
302
+ <View style={styles.headerCenter}>
303
+ {aiLogo ? (
304
+ <Image source={aiLogo} style={styles.headerLogo} />
305
+ ) : (
306
+ <View style={styles.headerLogoFallback}>
307
+ <Ionicons name="sparkles" size={14} color="#FFF" />
308
+ </View>
309
+ )}
310
+ <Text style={styles.headerTitle}>VORQARD AI</Text>
311
+ </View>
312
+
313
+ <TouchableOpacity onPress={handleNewChat} style={styles.headerBtn} activeOpacity={0.7}>
314
+ <Ionicons name="add-circle-outline" size={26} color="#6366F1" />
315
+ </TouchableOpacity>
316
+ </View>
317
+
318
+ <KeyboardAvoidingView
319
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
320
+ style={styles.flex}
321
+ keyboardVerticalOffset={Platform.OS === 'ios' ? 90 : 0}
322
+ >
323
+ <LinearGradient
324
+ colors={['#EEF2FF', '#E8EFFE', '#F0F4FF']}
325
+ style={styles.flex}
326
+ start={{ x: 0, y: 0 }}
327
+ end={{ x: 1, y: 1 }}
328
+ >
329
+ {chatMode ? renderChatContent() : renderHubContent()}
330
+
331
+ <InputPanel
332
+ value={inputText}
333
+ onChangeText={setInputText}
334
+ onSend={handleSend}
335
+ loading={loading}
336
+ onVoicePress={() => {
337
+ setChatMode(true);
338
+ sendMessage('Launch Voice Assistant');
339
+ }}
340
+ aiLogo={aiLogo}
341
+ />
342
+ </LinearGradient>
343
+ </KeyboardAvoidingView>
344
+ </SafeAreaView>
345
+ );
346
+ };
347
+
348
+ const CARD_WIDTH = (SW - 52) / 3;
349
+
350
+ const styles = StyleSheet.create({
351
+ safeArea: {
352
+ flex: 1,
353
+ backgroundColor: '#EEF2FF',
354
+ },
355
+ flex: { flex: 1 },
356
+
357
+ // ── Header ─────────────────────────────────────────────────────────────────
358
+ header: {
359
+ flexDirection: 'row',
360
+ alignItems: 'center',
361
+ justifyContent: 'space-between',
362
+ paddingHorizontal: 12,
363
+ paddingVertical: 10,
364
+ backgroundColor: '#FFFFFF',
365
+ borderBottomWidth: 1,
366
+ borderBottomColor: '#EEF2FF',
367
+ elevation: 2,
368
+ shadowColor: '#C7D2FE',
369
+ shadowOffset: { width: 0, height: 2 },
370
+ shadowOpacity: 0.15,
371
+ shadowRadius: 4,
372
+ },
373
+ headerBtn: {
374
+ width: 40,
375
+ height: 40,
376
+ justifyContent: 'center',
377
+ alignItems: 'center',
378
+ },
379
+ headerCenter: {
380
+ flexDirection: 'row',
381
+ alignItems: 'center',
382
+ gap: 8,
383
+ },
384
+ headerLogo: { width: 28, height: 28, borderRadius: 8 },
385
+ headerLogoFallback: {
386
+ width: 28,
387
+ height: 28,
388
+ borderRadius: 8,
389
+ backgroundColor: '#6366F1',
390
+ justifyContent: 'center',
391
+ alignItems: 'center',
392
+ },
393
+ headerTitle: {
394
+ fontSize: 15,
395
+ fontWeight: '800',
396
+ color: '#1E293B',
397
+ letterSpacing: 0.3,
398
+ },
399
+
400
+ // ── Hub scroll ─────────────────────────────────────────────────────────────
401
+ hubScroll: { flex: 1 },
402
+ hubScrollContent: { padding: 16, paddingBottom: 8 },
403
+
404
+ // ── Hero Card ──────────────────────────────────────────────────────────────
405
+ heroCard: {
406
+ backgroundColor: '#FFFFFF',
407
+ borderRadius: 20,
408
+ padding: 18,
409
+ marginBottom: 16,
410
+ overflow: 'hidden',
411
+ shadowColor: '#C7D2FE',
412
+ shadowOffset: { width: 0, height: 4 },
413
+ shadowOpacity: 0.3,
414
+ shadowRadius: 12,
415
+ elevation: 4,
416
+ },
417
+ heroBlobRight: {
418
+ position: 'absolute',
419
+ width: 130,
420
+ height: 130,
421
+ borderRadius: 65,
422
+ backgroundColor: 'rgba(147,197,253,0.15)',
423
+ right: -30,
424
+ top: -30,
425
+ },
426
+ heroBlobLeft: {
427
+ position: 'absolute',
428
+ width: 80,
429
+ height: 80,
430
+ borderRadius: 40,
431
+ backgroundColor: 'rgba(196,181,253,0.12)',
432
+ left: -20,
433
+ bottom: 20,
434
+ },
435
+ heroTopRow: {
436
+ flexDirection: 'row',
437
+ alignItems: 'flex-start',
438
+ marginBottom: 16,
439
+ },
440
+ heroLeft: { flexDirection: 'row', flex: 1 },
441
+ heroAvatar: { width: 44, height: 44, borderRadius: 12 },
442
+ heroAvatarFallback: {
443
+ width: 44,
444
+ height: 44,
445
+ borderRadius: 12,
446
+ backgroundColor: '#6366F1',
447
+ justifyContent: 'center',
448
+ alignItems: 'center',
449
+ },
450
+ heroGreeting: {
451
+ fontSize: 17,
452
+ fontWeight: '800',
453
+ color: '#1E293B',
454
+ marginBottom: 4,
455
+ },
456
+ heroBody: {
457
+ fontSize: 13,
458
+ color: '#475569',
459
+ lineHeight: 20,
460
+ marginBottom: 4,
461
+ },
462
+ heroHighlight: {
463
+ fontWeight: '800',
464
+ color: '#1E293B',
465
+ },
466
+ heroSub: {
467
+ fontSize: 13,
468
+ color: '#64748B',
469
+ marginTop: 2,
470
+ },
471
+ heroIllustration: {
472
+ width: 60,
473
+ height: 60,
474
+ borderRadius: 16,
475
+ backgroundColor: '#EEF2FF',
476
+ justifyContent: 'center',
477
+ alignItems: 'center',
478
+ marginLeft: 8,
479
+ },
480
+
481
+ // ── Snapshot row ───────────────────────────────────────────────────────────
482
+ snapshotRow: {
483
+ flexDirection: 'row',
484
+ alignItems: 'center',
485
+ borderTopWidth: 1,
486
+ borderTopColor: '#F1F5F9',
487
+ paddingTop: 14,
488
+ gap: 0,
489
+ },
490
+ snapshotItem: {
491
+ flex: 1,
492
+ alignItems: 'center',
493
+ gap: 3,
494
+ },
495
+ snapshotIcon: {
496
+ width: 32,
497
+ height: 32,
498
+ borderRadius: 16,
499
+ justifyContent: 'center',
500
+ alignItems: 'center',
501
+ marginBottom: 2,
502
+ },
503
+ snapshotLabel: {
504
+ fontSize: 10,
505
+ color: '#94A3B8',
506
+ fontWeight: '600',
507
+ textTransform: 'uppercase',
508
+ letterSpacing: 0.4,
509
+ },
510
+ snapshotValue: {
511
+ fontSize: 12,
512
+ fontWeight: '800',
513
+ color: '#1E293B',
514
+ textAlign: 'center',
515
+ },
516
+ snapshotDivider: {
517
+ width: 1,
518
+ height: 40,
519
+ backgroundColor: '#F1F5F9',
520
+ },
521
+
522
+ // ── Actions Grid ───────────────────────────────────────────────────────────
523
+ actionsSection: { marginBottom: 16 },
524
+ actionsSectionTitle: {
525
+ fontSize: 16,
526
+ fontWeight: '800',
527
+ color: '#1E293B',
528
+ marginBottom: 12,
529
+ },
530
+ actionsGrid: {
531
+ flexDirection: 'row',
532
+ flexWrap: 'wrap',
533
+ gap: 10,
534
+ },
535
+ actionCard: {
536
+ width: CARD_WIDTH,
537
+ backgroundColor: '#FFFFFF',
538
+ borderRadius: 16,
539
+ padding: 12,
540
+ alignItems: 'center',
541
+ shadowColor: '#C7D2FE',
542
+ shadowOffset: { width: 0, height: 2 },
543
+ shadowOpacity: 0.2,
544
+ shadowRadius: 8,
545
+ elevation: 2,
546
+ },
547
+ actionIconCircle: {
548
+ width: 50,
549
+ height: 50,
550
+ borderRadius: 25,
551
+ justifyContent: 'center',
552
+ alignItems: 'center',
553
+ marginBottom: 8,
554
+ },
555
+ actionTitle: {
556
+ fontSize: 11,
557
+ fontWeight: '800',
558
+ color: '#1E293B',
559
+ textAlign: 'center',
560
+ marginBottom: 3,
561
+ },
562
+ actionDesc: {
563
+ fontSize: 9.5,
564
+ color: '#94A3B8',
565
+ textAlign: 'center',
566
+ lineHeight: 14,
567
+ fontWeight: '500',
568
+ },
569
+
570
+ // ── Today / Empty State ────────────────────────────────────────────────────
571
+ todayContainer: { marginBottom: 8 },
572
+ todayDividerRow: {
573
+ flexDirection: 'row',
574
+ alignItems: 'center',
575
+ marginBottom: 14,
576
+ },
577
+ todayLine: { flex: 1, height: 1, backgroundColor: '#E2E8F0' },
578
+ todayBadge: {
579
+ backgroundColor: '#FFFFFF',
580
+ borderWidth: 1,
581
+ borderColor: '#E2E8F0',
582
+ paddingHorizontal: 12,
583
+ paddingVertical: 4,
584
+ borderRadius: 12,
585
+ marginHorizontal: 8,
586
+ },
587
+ todayBadgeText: {
588
+ fontSize: 11,
589
+ fontWeight: '700',
590
+ color: '#64748B',
591
+ },
592
+ emptyStateBox: { alignItems: 'center', paddingVertical: 8 },
593
+ emptyStateSparkle: { fontSize: 20, marginBottom: 6, letterSpacing: 4 },
594
+ emptyStateTitle: {
595
+ fontSize: 13,
596
+ fontWeight: '700',
597
+ color: '#475569',
598
+ textAlign: 'center',
599
+ marginBottom: 4,
600
+ },
601
+ emptyStateBody: {
602
+ fontSize: 12,
603
+ color: '#94A3B8',
604
+ textAlign: 'center',
605
+ lineHeight: 18,
606
+ },
607
+
608
+ // ── Chat FlatList ──────────────────────────────────────────────────────────
609
+ flatListContent: { paddingVertical: 20, paddingHorizontal: 4 },
610
+ });
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import { View, StyleSheet, ScrollView, ActivityIndicator, TouchableOpacity, Text } from 'react-native';
3
+ import LinearGradient from 'react-native-linear-gradient';
4
+ import Ionicons from 'react-native-vector-icons/Ionicons';
5
+
6
+ import { useReportAnalysis } from '../hooks/useReportAnalysis';
7
+ import { UploadArea, ImagePreview, ResultsPanel } from '../components/ReportAnalysisComponents';
8
+
9
+ export const AIReportAnalysisScreen = ({ onClose, onChatWithAIPress }) => {
10
+ const {
11
+ selectedImage,
12
+ loading,
13
+ result,
14
+ fadeAnim,
15
+ pickFromGallery,
16
+ captureWithCamera,
17
+ analyzeReport,
18
+ clearImage,
19
+ } = useReportAnalysis();
20
+
21
+ return (
22
+ <View style={styles.container}>
23
+ <LinearGradient colors={['#071428', '#0D2248']} style={styles.header}>
24
+ {onClose && (
25
+ <TouchableOpacity onPress={onClose} style={styles.backBtn}>
26
+ <Ionicons name="arrow-back" size={22} color="#fff" />
27
+ </TouchableOpacity>
28
+ )}
29
+ <View style={{ flex: 1, alignItems: 'center', marginRight: onClose ? 36 : 0 }}>
30
+ <Text style={styles.headerTitle}>AI Report Analysis</Text>
31
+ <Text style={styles.headerSub}>Powered by Gemini Vision</Text>
32
+ </View>
33
+ </LinearGradient>
34
+
35
+ <ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.scroll}>
36
+ {!selectedImage ? (
37
+ <UploadArea captureWithCamera={captureWithCamera} pickFromGallery={pickFromGallery} />
38
+ ) : (
39
+ <ImagePreview
40
+ selectedImage={selectedImage}
41
+ clearImage={clearImage}
42
+ analyzeReport={analyzeReport}
43
+ loading={loading}
44
+ />
45
+ )}
46
+
47
+ {loading && (
48
+ <View style={styles.loadingCard}>
49
+ <ActivityIndicator size="large" color="#2563EB" />
50
+ <Text style={styles.loadingText}>Gemini AI is reading your report...</Text>
51
+ <Text style={styles.loadingSubText}>This may take a few seconds</Text>
52
+ </View>
53
+ )}
54
+
55
+ {result && !loading && (
56
+ <ResultsPanel
57
+ result={result}
58
+ fadeAnim={fadeAnim}
59
+ onChatWithAIPress={onChatWithAIPress}
60
+ />
61
+ )}
62
+ </ScrollView>
63
+ </View>
64
+ );
65
+ };
66
+
67
+ const styles = StyleSheet.create({
68
+ container: { flex: 1, backgroundColor: '#F8FAFC' },
69
+ header: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 20, paddingVertical: 16 },
70
+ backBtn: { width: 36, height: 36, justifyContent: 'center', alignItems: 'center' },
71
+ headerTitle: { color: '#fff', fontSize: 16, fontWeight: 'bold', textAlign: 'center' },
72
+ headerSub: { color: '#60A5FA', fontSize: 10, textAlign: 'center', marginTop: 2 },
73
+ scroll: { padding: 20, paddingBottom: 40 },
74
+ loadingCard: { backgroundColor: '#fff', borderRadius: 16, padding: 30, alignItems: 'center', marginBottom: 16, elevation: 3 },
75
+ loadingText: { fontSize: 15, fontWeight: '600', color: '#1E293B', marginTop: 16 },
76
+ loadingSubText: { fontSize: 13, color: '#94A3B8', marginTop: 4 },
77
+ });