vorqard-ai-sdk 1.0.4 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vorqard-ai-sdk",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Standalone React Native SDK for VORQARD AI Health Assistant and Report Analyzer",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -19,7 +19,6 @@
19
19
  "react-native-linear-gradient": "*",
20
20
  "react-native-safe-area-context": "*",
21
21
  "react-native-vector-icons": "*",
22
- "react-native-vision-camera": "*",
23
22
  "react-native-webrtc": "*"
24
23
  },
25
24
  "keywords": [
@@ -30,8 +29,5 @@
30
29
  "healthcare"
31
30
  ],
32
31
  "author": "VORQARD Developer",
33
- "license": "Abhivorn Technologies",
34
- "dependencies": {
35
- "react-native-live-audio-stream": "^1.1.1"
36
- }
37
- }
32
+ "license": "Abhivorn Technologies"
33
+ }
@@ -233,11 +233,11 @@ export const InputPanel = ({ value = '', onChangeText, onSend, onVoicePress, loa
233
233
  </TouchableOpacity>
234
234
  )}
235
235
 
236
- {!hasText && (
237
- <TouchableOpacity style={styles.iconBtn} onPress={onVoicePress} activeOpacity={0.7}>
236
+ {/* {!hasText && (
237
+ <View style={styles.iconBtn}>
238
238
  <Ionicons name="mic" size={20} color="#94A3B8" />
239
- </TouchableOpacity>
240
- )}
239
+ </View>
240
+ )} */}
241
241
 
242
242
  <TouchableOpacity
243
243
  onPress={() => onSend(value)}
@@ -1,94 +1,367 @@
1
- import React from 'react';
2
- import { View, Text, TouchableOpacity, StyleSheet, Image } from 'react-native';
1
+ import React, { useState } from 'react';
2
+ import { View, Text, TouchableOpacity, StyleSheet, Image, Linking, ScrollView } from 'react-native';
3
3
  import Ionicons from 'react-native-vector-icons/Ionicons';
4
4
 
5
+ // Rich card components (already built for the chat UI, reused here)
6
+ import { SpecialtySelectionCard } from './cards/SpecialtySelectionCard';
7
+ import { DoctorSelectionList } from './cards/DoctorCards';
8
+ import { SlotSelectionCard } from './cards/SlotSelectionCard';
9
+ import { BookingConfirmationCard } from './cards/BookingConfirmationCard';
10
+
11
+ /**
12
+ * UICardContainer — renders the backend-driven ui_action payload.
13
+ *
14
+ * Interaction text conventions (sent via sendUIInteraction → DataChannel):
15
+ * specialty_cards → opt.id e.g. "Cardiology"
16
+ * doctor_cards → "doctor:<id>" e.g. "doctor:5"
17
+ * provider_selection → "doctor:<id>" VORQARD tap
18
+ * → "nearby:<id>" Nearby tap
19
+ * nearby_details → navigation via Linking (no DataChannel)
20
+ * slot_cards (slot) → opt.label e.g. "10:30"
21
+ * slot_cards (date) → "date:YYYY-MM-DD" from date picker
22
+ * payment_card → opt.id "cash" | "upi" | "card"
23
+ * booking_success → no interaction
24
+ */
5
25
  export const UICardContainer = ({ action, onAction }) => {
6
26
  if (!action) return null;
7
27
 
8
28
  switch (action.type) {
29
+
30
+ // ── Phase 3/4: existing cards ─────────────────────────────────────────────
31
+
32
+ case 'specialty_cards':
33
+ return (
34
+ <SpecialtySelectionCard
35
+ options={action.items}
36
+ onOptionPress={(opt) => onAction(opt.id)}
37
+ />
38
+ );
39
+
40
+ case 'doctor_cards':
41
+ return (
42
+ <DoctorSelectionList
43
+ options={action.items}
44
+ onOptionPress={(opt) => onAction(`doctor:${opt.id}`)}
45
+ />
46
+ );
47
+
48
+ case 'slot_cards':
49
+ return (
50
+ <SlotSelectionCard
51
+ doctor={action.doctor}
52
+ selectedDate={action.date}
53
+ options={action.items}
54
+ onOptionPress={(opt) => onAction(opt.label)}
55
+ />
56
+ );
57
+
58
+ case 'confirmation_card':
59
+ return (
60
+ <BookingConfirmationCard
61
+ ui={{
62
+ doctor: action.doctor,
63
+ date: action.date,
64
+ slot: action.slot,
65
+ options: action.items,
66
+ }}
67
+ onOptionPress={(opt) => onAction(opt.id)}
68
+ />
69
+ );
70
+
71
+ case 'booking_success':
72
+ return <BookingSuccessCard action={action} />;
73
+
74
+ // ── Phase 5: two-category provider selection ──────────────────────────────
75
+
76
+ case 'provider_selection':
77
+ return (
78
+ <ProviderSelectionCard
79
+ action={action}
80
+ onVorqardPress={(doc) => onAction(`doctor:${doc.id}`)}
81
+ onNearbyPress={(p) => onAction(`nearby:${p.id}`)}
82
+ />
83
+ );
84
+
85
+ case 'nearby_details':
86
+ return <NearbyDetailsCard action={action} />;
87
+
88
+ // ── Phase 6: payment ──────────────────────────────────────────────────────
89
+
90
+ case 'payment_card':
91
+ return (
92
+ <PaymentCard
93
+ action={action}
94
+ onMethodPress={(opt) => onAction(opt.id)}
95
+ />
96
+ );
97
+
98
+ // ── Legacy / Gemini-path cards (backwards compat) ─────────────────────────
99
+
9
100
  case 'selection':
10
- return <SelectionCard action={action} onAction={onAction} />;
101
+ return <LegacySelectionCard action={action} onAction={onAction} />;
102
+
11
103
  case 'slot_selection':
12
- return <SlotSelectionCard action={action} onAction={onAction} />;
13
- case 'booking_success':
14
- return <BookingSuccessCard action={action} onAction={onAction} />;
104
+ return <LegacySlotCard action={action} onAction={onAction} />;
105
+
15
106
  case 'appointments_list':
16
107
  return <AppointmentsListCard action={action} onAction={onAction} />;
108
+
17
109
  default:
18
110
  return null;
19
111
  }
20
112
  };
21
113
 
22
- const SelectionCard = ({ action, onAction }) => {
114
+ // ── Booking success (shared by both paths) ────────────────────────────────────
115
+
116
+ const BookingSuccessCard = ({ action }) => (
117
+ <View style={styles.successCard}>
118
+ <View style={styles.successIcon}>
119
+ <Ionicons name="checkmark-circle" size={48} color="#10B981" />
120
+ </View>
121
+ <Text style={styles.successTitle}>Booking Confirmed!</Text>
122
+ <View style={styles.detailRow}>
123
+ <Ionicons name="person-outline" size={16} color="rgba(255,255,255,0.7)" />
124
+ <Text style={styles.detailText}>{action.doctor}</Text>
125
+ </View>
126
+ <View style={styles.detailRow}>
127
+ <Ionicons name="calendar-outline" size={16} color="rgba(255,255,255,0.7)" />
128
+ <Text style={styles.detailText}>{action.date} at {action.slot}</Text>
129
+ </View>
130
+ </View>
131
+ );
132
+
133
+ // ── Phase 5: Provider Selection (Our Services + Nearby) ──────────────────────
134
+
135
+ const ProviderSelectionCard = ({ action, onVorqardPress, onNearbyPress }) => {
136
+ const [tab, setTab] = useState('our_services');
137
+ const vorqardList = action.our_services || [];
138
+ const nearbyList = action.nearby || [];
139
+
23
140
  return (
24
141
  <View style={styles.card}>
25
- <Text style={styles.title}>{action.title || 'Please Select'}</Text>
26
- {action.options?.map((opt, i) => (
142
+ <Text style={styles.title}>{action.title || 'Find a Provider'}</Text>
143
+
144
+ {/* Tab strip */}
145
+ <View style={styles.tabRow}>
27
146
  <TouchableOpacity
28
- key={opt.id || i}
29
- style={styles.doctorItem}
30
- onPress={() => onAction(opt.label || opt.name)}
147
+ style={[styles.tab, tab === 'our_services' && styles.tabActive]}
148
+ onPress={() => setTab('our_services')}
31
149
  >
32
- {opt.profile_picture ? (
33
- <Image source={{ uri: opt.profile_picture }} style={styles.docImg} />
34
- ) : (
35
- <View style={styles.docAvatar}>
36
- <Ionicons name="person" size={20} color="#fff" />
37
- </View>
38
- )}
39
- <View style={styles.docInfo}>
40
- <Text style={styles.docName}>{opt.name || opt.label}</Text>
41
- {opt.specialty && <Text style={styles.docSpec}>{opt.specialty}</Text>}
42
- <View style={styles.docMetaRow}>
43
- {opt.experience && <Text style={styles.docMeta}>{opt.experience} yrs exp</Text>}
44
- {opt.consultation_fee && <Text style={styles.docMeta}> • ₹{opt.consultation_fee}</Text>}
45
- </View>
46
- </View>
150
+ <Ionicons name="shield-checkmark-outline" size={14} color={tab === 'our_services' ? '#818CF8' : 'rgba(255,255,255,0.5)'} />
151
+ <Text style={[styles.tabText, tab === 'our_services' && styles.tabTextActive]}>
152
+ Our Services ({vorqardList.length})
153
+ </Text>
47
154
  </TouchableOpacity>
48
- ))}
155
+ <TouchableOpacity
156
+ style={[styles.tab, tab === 'nearby' && styles.tabActive]}
157
+ onPress={() => setTab('nearby')}
158
+ >
159
+ <Ionicons name="location-outline" size={14} color={tab === 'nearby' ? '#818CF8' : 'rgba(255,255,255,0.5)'} />
160
+ <Text style={[styles.tabText, tab === 'nearby' && styles.tabTextActive]}>
161
+ Nearby ({nearbyList.length})
162
+ </Text>
163
+ </TouchableOpacity>
164
+ </View>
165
+
166
+ {tab === 'our_services' ? (
167
+ vorqardList.length === 0 ? (
168
+ <Text style={styles.emptyText}>No VORQARD specialists found in this area.</Text>
169
+ ) : (
170
+ vorqardList.map((doc, i) => (
171
+ <TouchableOpacity key={doc.id || i} style={styles.doctorItem} onPress={() => onVorqardPress(doc)}>
172
+ {doc.profile_picture
173
+ ? <Image source={{ uri: doc.profile_picture }} style={styles.docImg} />
174
+ : <View style={styles.docAvatar}><Ionicons name="person" size={20} color="#fff" /></View>
175
+ }
176
+ <View style={styles.docInfo}>
177
+ <Text style={styles.docName}>{doc.name}</Text>
178
+ <Text style={styles.docSpec}>{doc.specialty}</Text>
179
+ <View style={styles.docMetaRow}>
180
+ {doc.consultation_fee > 0 && <Text style={styles.docMeta}>₹{doc.consultation_fee}</Text>}
181
+ {doc.distance != null && <Text style={styles.docMeta}> • {doc.distance} km</Text>}
182
+ {doc.rating > 0 && <Text style={styles.docMeta}> • ⭐ {doc.rating}</Text>}
183
+ </View>
184
+ </View>
185
+ <View style={styles.bookBadge}>
186
+ <Text style={styles.bookBadgeText}>Book</Text>
187
+ </View>
188
+ </TouchableOpacity>
189
+ ))
190
+ )
191
+ ) : (
192
+ nearbyList.length === 0 ? (
193
+ <Text style={styles.emptyText}>No nearby clinics found in this area.</Text>
194
+ ) : (
195
+ nearbyList.map((p, i) => (
196
+ <TouchableOpacity key={p.id || i} style={styles.nearbyItem} onPress={() => onNearbyPress(p)}>
197
+ <View style={styles.nearbyIcon}>
198
+ <Ionicons name="business-outline" size={22} color="#818CF8" />
199
+ </View>
200
+ <View style={styles.docInfo}>
201
+ <Text style={styles.docName}>{p.name}</Text>
202
+ {p.address ? <Text style={styles.docSpec} numberOfLines={1}>{p.address}</Text> : null}
203
+ <View style={styles.docMetaRow}>
204
+ {p.distance != null && <Text style={styles.docMeta}>{p.distance} km away</Text>}
205
+ {p.phone ? <Text style={styles.docMeta}> • {p.phone}</Text> : null}
206
+ </View>
207
+ </View>
208
+ <Ionicons name="chevron-forward" size={16} color="rgba(255,255,255,0.4)" />
209
+ </TouchableOpacity>
210
+ ))
211
+ )
212
+ )}
49
213
  </View>
50
214
  );
51
215
  };
52
216
 
53
- const SlotSelectionCard = ({ action, onAction }) => {
217
+ // ── Phase 5: Nearby Details (info-only, no booking) ───────────────────────────
218
+
219
+ const NearbyDetailsCard = ({ action }) => {
220
+ const p = action.provider || {};
221
+ const openMaps = () => {
222
+ if (p.maps_url) Linking.openURL(p.maps_url).catch(() => {});
223
+ };
224
+ const callPhone = () => {
225
+ if (p.phone) Linking.openURL(`tel:${p.phone}`).catch(() => {});
226
+ };
227
+
54
228
  return (
55
- <View style={styles.card}>
56
- <Text style={styles.title}>{action.title || 'Select Time'}</Text>
57
- <Text style={styles.subtitle}>{action.selected_date}</Text>
58
- <View style={styles.slotGrid}>
59
- {action.options?.map((opt, i) => (
60
- <TouchableOpacity
61
- key={opt.id || i}
62
- style={styles.slotBtn}
63
- onPress={() => onAction(opt.label)}
64
- >
65
- <Text style={styles.slotText}>{opt.label}</Text>
229
+ <View style={[styles.card, styles.nearbyDetailCard]}>
230
+ <View style={styles.nearbyDetailHeader}>
231
+ <Ionicons name="business" size={28} color="#818CF8" />
232
+ <Text style={[styles.title, { marginLeft: 10 }]}>{p.name || 'Nearby Clinic'}</Text>
233
+ </View>
234
+
235
+ {p.address ? (
236
+ <View style={styles.detailRow}>
237
+ <Ionicons name="location-outline" size={16} color="rgba(255,255,255,0.6)" />
238
+ <Text style={styles.detailText}>{p.address}</Text>
239
+ </View>
240
+ ) : null}
241
+
242
+ {p.distance != null ? (
243
+ <View style={styles.detailRow}>
244
+ <Ionicons name="navigate-outline" size={16} color="rgba(255,255,255,0.6)" />
245
+ <Text style={styles.detailText}>{p.distance} km away</Text>
246
+ </View>
247
+ ) : null}
248
+
249
+ {p.phone ? (
250
+ <View style={styles.detailRow}>
251
+ <Ionicons name="call-outline" size={16} color="rgba(255,255,255,0.6)" />
252
+ <Text style={styles.detailText}>{p.phone}</Text>
253
+ </View>
254
+ ) : null}
255
+
256
+ <View style={styles.nearbyBtnRow}>
257
+ {p.phone ? (
258
+ <TouchableOpacity style={styles.nearbyBtn} onPress={callPhone}>
259
+ <Ionicons name="call" size={16} color="#fff" />
260
+ <Text style={styles.nearbyBtnText}>Call</Text>
66
261
  </TouchableOpacity>
67
- ))}
262
+ ) : null}
263
+ {p.maps_url ? (
264
+ <TouchableOpacity style={[styles.nearbyBtn, styles.navBtn]} onPress={openMaps}>
265
+ <Ionicons name="navigate" size={16} color="#fff" />
266
+ <Text style={styles.nearbyBtnText}>Navigate</Text>
267
+ </TouchableOpacity>
268
+ ) : null}
269
+ </View>
270
+
271
+ <View style={styles.nearbyNoBookNotice}>
272
+ <Ionicons name="information-circle-outline" size={14} color="rgba(255,255,255,0.4)" />
273
+ <Text style={styles.nearbyNoBookText}>Booking not available — visit or call directly.</Text>
68
274
  </View>
69
275
  </View>
70
276
  );
71
277
  };
72
278
 
73
- const BookingSuccessCard = ({ action, onAction }) => {
279
+ // ── Phase 6: Payment Card ─────────────────────────────────────────────────────
280
+
281
+ const PaymentCard = ({ action, onMethodPress }) => {
282
+ const doc = action.doctor || {};
74
283
  return (
75
- <View style={styles.successCard}>
76
- <View style={styles.successIcon}>
77
- <Ionicons name="checkmark-circle" size={48} color="#10B981" />
78
- </View>
79
- <Text style={styles.successTitle}>Booking Confirmed!</Text>
80
- <View style={styles.detailRow}>
81
- <Ionicons name="person-outline" size={16} color="rgba(255,255,255,0.7)" />
82
- <Text style={styles.detailText}>{action.doctor}</Text>
83
- </View>
84
- <View style={styles.detailRow}>
85
- <Ionicons name="calendar-outline" size={16} color="rgba(255,255,255,0.7)" />
86
- <Text style={styles.detailText}>{action.date} at {action.slot}</Text>
284
+ <View style={[styles.card, styles.paymentCard]}>
285
+ <Text style={styles.title}>{action.title || 'Payment'}</Text>
286
+
287
+ {/* Appointment summary */}
288
+ <View style={styles.paymentSummary}>
289
+ <View style={styles.detailRow}>
290
+ <Ionicons name="person-outline" size={15} color="rgba(255,255,255,0.6)" />
291
+ <Text style={styles.detailText}>{doc.name || 'Doctor'}</Text>
292
+ </View>
293
+ <View style={styles.detailRow}>
294
+ <Ionicons name="calendar-outline" size={15} color="rgba(255,255,255,0.6)" />
295
+ <Text style={styles.detailText}>{action.date} at {action.slot}</Text>
296
+ </View>
297
+ <View style={[styles.detailRow, styles.amountRow]}>
298
+ <Ionicons name="cash-outline" size={15} color="#10B981" />
299
+ <Text style={styles.amountText}>₹{action.amount || 0}</Text>
300
+ </View>
87
301
  </View>
302
+
303
+ {/* Payment options */}
304
+ <Text style={styles.subtitle}>Choose payment method</Text>
305
+ {(action.items || []).map((opt, i) => (
306
+ <TouchableOpacity key={opt.id || i} style={styles.paymentBtn} onPress={() => onMethodPress(opt)}>
307
+ <Ionicons name={opt.icon || 'card-outline'} size={20} color="#818CF8" />
308
+ <Text style={styles.paymentBtnText}>{opt.label}</Text>
309
+ <Ionicons name="chevron-forward" size={16} color="rgba(255,255,255,0.4)" />
310
+ </TouchableOpacity>
311
+ ))}
88
312
  </View>
89
313
  );
90
314
  };
91
315
 
316
+ // ── Legacy cards (kept for Gemini-routed queries) ─────────────────────────────
317
+
318
+ const LegacySelectionCard = ({ action, onAction }) => (
319
+ <View style={styles.card}>
320
+ <Text style={styles.title}>{action.title || 'Please Select'}</Text>
321
+ {action.options?.map((opt, i) => (
322
+ <TouchableOpacity
323
+ key={opt.id || i}
324
+ style={styles.doctorItem}
325
+ onPress={() => onAction(opt.label || opt.name)}
326
+ >
327
+ {opt.profile_picture ? (
328
+ <Image source={{ uri: opt.profile_picture }} style={styles.docImg} />
329
+ ) : (
330
+ <View style={styles.docAvatar}>
331
+ <Ionicons name="person" size={20} color="#fff" />
332
+ </View>
333
+ )}
334
+ <View style={styles.docInfo}>
335
+ <Text style={styles.docName}>{opt.name || opt.label}</Text>
336
+ {opt.specialty && <Text style={styles.docSpec}>{opt.specialty}</Text>}
337
+ <View style={styles.docMetaRow}>
338
+ {opt.experience && <Text style={styles.docMeta}>{opt.experience} yrs exp</Text>}
339
+ {opt.consultation_fee && <Text style={styles.docMeta}> • ₹{opt.consultation_fee}</Text>}
340
+ </View>
341
+ </View>
342
+ </TouchableOpacity>
343
+ ))}
344
+ </View>
345
+ );
346
+
347
+ const LegacySlotCard = ({ action, onAction }) => (
348
+ <View style={styles.card}>
349
+ <Text style={styles.title}>{action.title || 'Select Time'}</Text>
350
+ <Text style={styles.subtitle}>{action.selected_date}</Text>
351
+ <View style={styles.slotGrid}>
352
+ {action.options?.map((opt, i) => (
353
+ <TouchableOpacity
354
+ key={opt.id || i}
355
+ style={styles.slotBtn}
356
+ onPress={() => onAction(opt.label)}
357
+ >
358
+ <Text style={styles.slotText}>{opt.label}</Text>
359
+ </TouchableOpacity>
360
+ ))}
361
+ </View>
362
+ </View>
363
+ );
364
+
92
365
  const AppointmentsListCard = ({ action, onAction }) => {
93
366
  if (!action.appointments || action.appointments.length === 0) {
94
367
  return (
@@ -115,6 +388,8 @@ const AppointmentsListCard = ({ action, onAction }) => {
115
388
  );
116
389
  };
117
390
 
391
+ // ── Styles ────────────────────────────────────────────────────────────────────
392
+
118
393
  const styles = StyleSheet.create({
119
394
  card: {
120
395
  backgroundColor: 'rgba(255,255,255,0.08)',
@@ -160,32 +435,12 @@ const styles = StyleSheet.create({
160
435
  alignItems: 'center',
161
436
  marginRight: 12,
162
437
  },
163
- docInfo: {
164
- flex: 1,
165
- },
166
- docName: {
167
- fontSize: 15,
168
- fontWeight: 'bold',
169
- color: '#fff',
170
- },
171
- docSpec: {
172
- fontSize: 12,
173
- color: '#818CF8',
174
- marginTop: 2,
175
- },
176
- docMetaRow: {
177
- flexDirection: 'row',
178
- marginTop: 4,
179
- },
180
- docMeta: {
181
- fontSize: 11,
182
- color: 'rgba(255,255,255,0.5)',
183
- },
184
- slotGrid: {
185
- flexDirection: 'row',
186
- flexWrap: 'wrap',
187
- gap: 8,
188
- },
438
+ docInfo: { flex: 1 },
439
+ docName: { fontSize: 15, fontWeight: 'bold', color: '#fff' },
440
+ docSpec: { fontSize: 12, color: '#818CF8', marginTop: 2 },
441
+ docMetaRow: { flexDirection: 'row', marginTop: 4 },
442
+ docMeta: { fontSize: 11, color: 'rgba(255,255,255,0.5)' },
443
+ slotGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 },
189
444
  slotBtn: {
190
445
  backgroundColor: 'rgba(99,102,241,0.2)',
191
446
  paddingVertical: 8,
@@ -194,11 +449,7 @@ const styles = StyleSheet.create({
194
449
  borderWidth: 1,
195
450
  borderColor: 'rgba(99,102,241,0.4)',
196
451
  },
197
- slotText: {
198
- color: '#E0E7FF',
199
- fontSize: 13,
200
- fontWeight: '600',
201
- },
452
+ slotText: { color: '#E0E7FF', fontSize: 13, fontWeight: '600' },
202
453
  successCard: {
203
454
  backgroundColor: 'rgba(16,185,129,0.1)',
204
455
  borderRadius: 16,
@@ -208,15 +459,8 @@ const styles = StyleSheet.create({
208
459
  borderColor: 'rgba(16,185,129,0.3)',
209
460
  alignItems: 'center',
210
461
  },
211
- successIcon: {
212
- marginBottom: 8,
213
- },
214
- successTitle: {
215
- fontSize: 18,
216
- fontWeight: 'bold',
217
- color: '#34D399',
218
- marginBottom: 16,
219
- },
462
+ successIcon: { marginBottom: 8 },
463
+ successTitle: { fontSize: 18, fontWeight: 'bold', color: '#34D399', marginBottom: 16 },
220
464
  detailRow: {
221
465
  flexDirection: 'row',
222
466
  alignItems: 'center',
@@ -224,10 +468,7 @@ const styles = StyleSheet.create({
224
468
  gap: 6,
225
469
  width: '100%',
226
470
  },
227
- detailText: {
228
- fontSize: 14,
229
- color: 'rgba(255,255,255,0.8)',
230
- },
471
+ detailText: { fontSize: 14, color: 'rgba(255,255,255,0.8)' },
231
472
  apptItem: {
232
473
  backgroundColor: 'rgba(0,0,0,0.2)',
233
474
  padding: 12,
@@ -236,4 +477,123 @@ const styles = StyleSheet.create({
236
477
  borderLeftWidth: 3,
237
478
  borderLeftColor: '#818CF8',
238
479
  },
480
+
481
+ // ── Provider Selection ────────────────────────────────────────────────────
482
+ tabRow: {
483
+ flexDirection: 'row',
484
+ marginBottom: 12,
485
+ gap: 8,
486
+ },
487
+ tab: {
488
+ flex: 1,
489
+ flexDirection: 'row',
490
+ alignItems: 'center',
491
+ justifyContent: 'center',
492
+ gap: 4,
493
+ paddingVertical: 8,
494
+ borderRadius: 10,
495
+ backgroundColor: 'rgba(255,255,255,0.06)',
496
+ borderWidth: 1,
497
+ borderColor: 'rgba(255,255,255,0.08)',
498
+ },
499
+ tabActive: {
500
+ backgroundColor: 'rgba(99,102,241,0.2)',
501
+ borderColor: 'rgba(99,102,241,0.5)',
502
+ },
503
+ tabText: { fontSize: 12, color: 'rgba(255,255,255,0.5)', fontWeight: '600' },
504
+ tabTextActive: { color: '#818CF8' },
505
+ nearbyItem: {
506
+ flexDirection: 'row',
507
+ backgroundColor: 'rgba(0,0,0,0.2)',
508
+ padding: 12,
509
+ borderRadius: 12,
510
+ marginTop: 8,
511
+ alignItems: 'center',
512
+ gap: 10,
513
+ borderWidth: 1,
514
+ borderColor: 'rgba(255,255,255,0.05)',
515
+ },
516
+ nearbyIcon: {
517
+ width: 44,
518
+ height: 44,
519
+ borderRadius: 22,
520
+ backgroundColor: 'rgba(99,102,241,0.15)',
521
+ justifyContent: 'center',
522
+ alignItems: 'center',
523
+ },
524
+ bookBadge: {
525
+ backgroundColor: 'rgba(99,102,241,0.3)',
526
+ paddingHorizontal: 10,
527
+ paddingVertical: 5,
528
+ borderRadius: 8,
529
+ borderWidth: 1,
530
+ borderColor: 'rgba(99,102,241,0.5)',
531
+ },
532
+ bookBadgeText: { color: '#A5B4FC', fontSize: 12, fontWeight: '700' },
533
+ emptyText: { color: 'rgba(255,255,255,0.4)', fontSize: 13, textAlign: 'center', marginTop: 12 },
534
+
535
+ // ── Nearby Details ────────────────────────────────────────────────────────
536
+ nearbyDetailCard: {
537
+ borderColor: 'rgba(99,102,241,0.3)',
538
+ },
539
+ nearbyDetailHeader: {
540
+ flexDirection: 'row',
541
+ alignItems: 'center',
542
+ marginBottom: 12,
543
+ },
544
+ nearbyBtnRow: {
545
+ flexDirection: 'row',
546
+ gap: 10,
547
+ marginTop: 14,
548
+ },
549
+ nearbyBtn: {
550
+ flex: 1,
551
+ flexDirection: 'row',
552
+ alignItems: 'center',
553
+ justifyContent: 'center',
554
+ gap: 6,
555
+ backgroundColor: 'rgba(99,102,241,0.25)',
556
+ paddingVertical: 10,
557
+ borderRadius: 10,
558
+ borderWidth: 1,
559
+ borderColor: 'rgba(99,102,241,0.4)',
560
+ },
561
+ navBtn: {
562
+ backgroundColor: 'rgba(16,185,129,0.2)',
563
+ borderColor: 'rgba(16,185,129,0.4)',
564
+ },
565
+ nearbyBtnText: { color: '#fff', fontSize: 14, fontWeight: '600' },
566
+ nearbyNoBookNotice: {
567
+ flexDirection: 'row',
568
+ alignItems: 'center',
569
+ gap: 5,
570
+ marginTop: 12,
571
+ },
572
+ nearbyNoBookText: { color: 'rgba(255,255,255,0.35)', fontSize: 11 },
573
+
574
+ // ── Payment Card ──────────────────────────────────────────────────────────
575
+ paymentCard: {
576
+ borderColor: 'rgba(16,185,129,0.25)',
577
+ },
578
+ paymentSummary: {
579
+ backgroundColor: 'rgba(0,0,0,0.2)',
580
+ borderRadius: 10,
581
+ padding: 12,
582
+ marginBottom: 14,
583
+ gap: 6,
584
+ },
585
+ amountRow: { marginTop: 4 },
586
+ amountText: { fontSize: 20, fontWeight: 'bold', color: '#34D399', marginLeft: 6 },
587
+ paymentBtn: {
588
+ flexDirection: 'row',
589
+ alignItems: 'center',
590
+ gap: 12,
591
+ backgroundColor: 'rgba(255,255,255,0.06)',
592
+ padding: 14,
593
+ borderRadius: 12,
594
+ marginTop: 8,
595
+ borderWidth: 1,
596
+ borderColor: 'rgba(255,255,255,0.08)',
597
+ },
598
+ paymentBtnText: { flex: 1, color: '#fff', fontSize: 15, fontWeight: '600' },
239
599
  });