@mobileai/react-native 0.9.17 → 0.9.18

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 (213) hide show
  1. package/package.json +2 -5
  2. package/lib/module/__cli_tmp__.js.map +0 -1
  3. package/lib/module/components/AIAgent.js.map +0 -1
  4. package/lib/module/components/AIZone.js.map +0 -1
  5. package/lib/module/components/AgentChatBar.js.map +0 -1
  6. package/lib/module/components/AgentErrorBoundary.js.map +0 -1
  7. package/lib/module/components/AgentOverlay.js.map +0 -1
  8. package/lib/module/components/DiscoveryTooltip.js.map +0 -1
  9. package/lib/module/components/HighlightOverlay.js.map +0 -1
  10. package/lib/module/components/Icons.js.map +0 -1
  11. package/lib/module/components/ProactiveHint.js.map +0 -1
  12. package/lib/module/components/cards/InfoCard.js.map +0 -1
  13. package/lib/module/components/cards/ReviewSummary.js.map +0 -1
  14. package/lib/module/config/endpoints.js.map +0 -1
  15. package/lib/module/core/ActionRegistry.js.map +0 -1
  16. package/lib/module/core/AgentRuntime.js.map +0 -1
  17. package/lib/module/core/FiberTreeWalker.js.map +0 -1
  18. package/lib/module/core/IdleDetector.js.map +0 -1
  19. package/lib/module/core/MCPBridge.js.map +0 -1
  20. package/lib/module/core/ScreenDehydrator.js.map +0 -1
  21. package/lib/module/core/ZoneRegistry.js.map +0 -1
  22. package/lib/module/core/systemPrompt.js.map +0 -1
  23. package/lib/module/core/types.js.map +0 -1
  24. package/lib/module/hooks/useAction.js.map +0 -1
  25. package/lib/module/index.js.map +0 -1
  26. package/lib/module/plugin/withAppIntents.js.map +0 -1
  27. package/lib/module/providers/GeminiProvider.js.map +0 -1
  28. package/lib/module/providers/OpenAIProvider.js.map +0 -1
  29. package/lib/module/providers/ProviderFactory.js.map +0 -1
  30. package/lib/module/services/AudioInputService.js.map +0 -1
  31. package/lib/module/services/AudioOutputService.js.map +0 -1
  32. package/lib/module/services/KnowledgeBaseService.js.map +0 -1
  33. package/lib/module/services/VoiceService.js.map +0 -1
  34. package/lib/module/services/flags/FlagService.js.map +0 -1
  35. package/lib/module/services/telemetry/MobileAI.js.map +0 -1
  36. package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
  37. package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
  38. package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
  39. package/lib/module/services/telemetry/device.js.map +0 -1
  40. package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
  41. package/lib/module/services/telemetry/index.js.map +0 -1
  42. package/lib/module/services/telemetry/types.js.map +0 -1
  43. package/lib/module/support/CSATSurvey.js.map +0 -1
  44. package/lib/module/support/EscalationEventSource.js.map +0 -1
  45. package/lib/module/support/EscalationSocket.js.map +0 -1
  46. package/lib/module/support/SupportChatModal.js.map +0 -1
  47. package/lib/module/support/SupportGreeting.js.map +0 -1
  48. package/lib/module/support/TicketStore.js.map +0 -1
  49. package/lib/module/support/escalateTool.js.map +0 -1
  50. package/lib/module/support/index.js.map +0 -1
  51. package/lib/module/support/supportPrompt.js.map +0 -1
  52. package/lib/module/support/types.js.map +0 -1
  53. package/lib/module/tools/datePickerTool.js.map +0 -1
  54. package/lib/module/tools/guideTool.js.map +0 -1
  55. package/lib/module/tools/index.js.map +0 -1
  56. package/lib/module/tools/keyboardTool.js.map +0 -1
  57. package/lib/module/tools/longPressTool.js.map +0 -1
  58. package/lib/module/tools/pickerTool.js.map +0 -1
  59. package/lib/module/tools/restoreTool.js.map +0 -1
  60. package/lib/module/tools/scrollTool.js.map +0 -1
  61. package/lib/module/tools/simplifyTool.js.map +0 -1
  62. package/lib/module/tools/sliderTool.js.map +0 -1
  63. package/lib/module/tools/tapTool.js.map +0 -1
  64. package/lib/module/tools/typeTool.js.map +0 -1
  65. package/lib/module/tools/types.js.map +0 -1
  66. package/lib/module/types/jsx.d.js.map +0 -1
  67. package/lib/module/utils/audioUtils.js.map +0 -1
  68. package/lib/module/utils/logger.js.map +0 -1
  69. package/lib/typescript/babel.config.d.ts.map +0 -1
  70. package/lib/typescript/bin/generate-map.d.cts.map +0 -1
  71. package/lib/typescript/eslint.config.d.mts.map +0 -1
  72. package/lib/typescript/generate-map.d.ts.map +0 -1
  73. package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
  74. package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
  75. package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
  76. package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
  77. package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
  78. package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
  79. package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
  80. package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
  81. package/lib/typescript/src/components/Icons.d.ts.map +0 -1
  82. package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
  83. package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
  84. package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
  85. package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
  86. package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
  87. package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
  88. package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
  89. package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
  90. package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
  91. package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
  92. package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
  93. package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
  94. package/lib/typescript/src/core/types.d.ts.map +0 -1
  95. package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
  96. package/lib/typescript/src/index.d.ts.map +0 -1
  97. package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
  98. package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
  99. package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
  100. package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
  101. package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
  102. package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
  103. package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
  104. package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
  105. package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
  106. package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
  107. package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
  108. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
  109. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
  110. package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
  111. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
  112. package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
  113. package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
  114. package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
  115. package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
  116. package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
  117. package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
  118. package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
  119. package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
  120. package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
  121. package/lib/typescript/src/support/index.d.ts.map +0 -1
  122. package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
  123. package/lib/typescript/src/support/types.d.ts.map +0 -1
  124. package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
  125. package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
  126. package/lib/typescript/src/tools/index.d.ts.map +0 -1
  127. package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
  128. package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
  129. package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
  130. package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
  131. package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
  132. package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
  133. package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
  134. package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
  135. package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
  136. package/lib/typescript/src/tools/types.d.ts.map +0 -1
  137. package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
  138. package/lib/typescript/src/utils/logger.d.ts.map +0 -1
  139. package/src/__cli_tmp__.tsx +0 -9
  140. package/src/cli/analyzers/chain-analyzer.ts +0 -183
  141. package/src/cli/extractors/ai-extractor.ts +0 -6
  142. package/src/cli/extractors/ast-extractor.ts +0 -551
  143. package/src/cli/generate-intents.ts +0 -140
  144. package/src/cli/generate-map.ts +0 -121
  145. package/src/cli/generate-swift.ts +0 -116
  146. package/src/cli/scanners/expo-scanner.ts +0 -203
  147. package/src/cli/scanners/rn-scanner.ts +0 -445
  148. package/src/components/AIAgent.tsx +0 -1716
  149. package/src/components/AIZone.tsx +0 -147
  150. package/src/components/AgentChatBar.tsx +0 -1143
  151. package/src/components/AgentErrorBoundary.tsx +0 -78
  152. package/src/components/AgentOverlay.tsx +0 -73
  153. package/src/components/DiscoveryTooltip.tsx +0 -148
  154. package/src/components/HighlightOverlay.tsx +0 -136
  155. package/src/components/Icons.tsx +0 -253
  156. package/src/components/ProactiveHint.tsx +0 -145
  157. package/src/components/cards/InfoCard.tsx +0 -58
  158. package/src/components/cards/ReviewSummary.tsx +0 -76
  159. package/src/config/endpoints.ts +0 -22
  160. package/src/core/ActionRegistry.ts +0 -105
  161. package/src/core/AgentRuntime.ts +0 -1471
  162. package/src/core/FiberTreeWalker.ts +0 -930
  163. package/src/core/IdleDetector.ts +0 -72
  164. package/src/core/MCPBridge.ts +0 -163
  165. package/src/core/ScreenDehydrator.ts +0 -53
  166. package/src/core/ZoneRegistry.ts +0 -44
  167. package/src/core/systemPrompt.ts +0 -431
  168. package/src/core/types.ts +0 -521
  169. package/src/hooks/useAction.ts +0 -182
  170. package/src/index.ts +0 -83
  171. package/src/plugin/withAppIntents.ts +0 -98
  172. package/src/providers/GeminiProvider.ts +0 -357
  173. package/src/providers/OpenAIProvider.ts +0 -379
  174. package/src/providers/ProviderFactory.ts +0 -36
  175. package/src/services/AudioInputService.ts +0 -226
  176. package/src/services/AudioOutputService.ts +0 -236
  177. package/src/services/KnowledgeBaseService.ts +0 -156
  178. package/src/services/VoiceService.ts +0 -451
  179. package/src/services/flags/FlagService.ts +0 -137
  180. package/src/services/telemetry/MobileAI.ts +0 -66
  181. package/src/services/telemetry/PiiScrubber.ts +0 -17
  182. package/src/services/telemetry/TelemetryService.ts +0 -323
  183. package/src/services/telemetry/TouchAutoCapture.ts +0 -165
  184. package/src/services/telemetry/device.ts +0 -93
  185. package/src/services/telemetry/deviceMetadata.ts +0 -13
  186. package/src/services/telemetry/index.ts +0 -13
  187. package/src/services/telemetry/types.ts +0 -75
  188. package/src/support/CSATSurvey.tsx +0 -304
  189. package/src/support/EscalationEventSource.ts +0 -190
  190. package/src/support/EscalationSocket.ts +0 -152
  191. package/src/support/SupportChatModal.tsx +0 -563
  192. package/src/support/SupportGreeting.tsx +0 -161
  193. package/src/support/TicketStore.ts +0 -100
  194. package/src/support/escalateTool.ts +0 -174
  195. package/src/support/index.ts +0 -29
  196. package/src/support/supportPrompt.ts +0 -55
  197. package/src/support/types.ts +0 -155
  198. package/src/tools/datePickerTool.ts +0 -60
  199. package/src/tools/guideTool.ts +0 -76
  200. package/src/tools/index.ts +0 -20
  201. package/src/tools/keyboardTool.ts +0 -30
  202. package/src/tools/longPressTool.ts +0 -61
  203. package/src/tools/pickerTool.ts +0 -115
  204. package/src/tools/restoreTool.ts +0 -33
  205. package/src/tools/scrollTool.ts +0 -156
  206. package/src/tools/simplifyTool.ts +0 -33
  207. package/src/tools/sliderTool.ts +0 -65
  208. package/src/tools/tapTool.ts +0 -93
  209. package/src/tools/typeTool.ts +0 -113
  210. package/src/tools/types.ts +0 -58
  211. package/src/types/jsx.d.ts +0 -20
  212. package/src/utils/audioUtils.ts +0 -54
  213. package/src/utils/logger.ts +0 -38
@@ -1,563 +0,0 @@
1
- /**
2
- * SupportChatModal — full-screen chat modal for human support conversations.
3
- * Shows message history (bubbles with timestamps/avatars), typing indicator, and reply input.
4
- * Supports native swipe-down-to-dismiss on iOS pageSheet.
5
- */
6
-
7
- import { useState, useEffect, useRef } from 'react';
8
- import {
9
- Modal,
10
- View,
11
- Text,
12
- TextInput,
13
- Pressable,
14
- ScrollView,
15
- StyleSheet,
16
- Platform,
17
- StatusBar,
18
- Keyboard,
19
- } from 'react-native';
20
- import type { AIMessage } from '../core/types';
21
- import { CloseIcon, SendArrowIcon, LoadingDots } from '../components/Icons';
22
-
23
- // ─── Props ─────────────────────────────────────────────────────
24
-
25
- interface SupportChatModalProps {
26
- visible: boolean;
27
- messages: AIMessage[];
28
- onSend: (message: string) => void;
29
- onClose: () => void;
30
- isAgentTyping?: boolean;
31
- isThinking?: boolean;
32
- /** Optional: externally controlled scroll trigger. Pass when messages update externally. */
33
- scrollToEndTrigger?: number;
34
- /** Ticket status — when 'closed' or 'resolved', input is hidden and a banner is shown. */
35
- ticketStatus?: string;
36
- }
37
-
38
- // ─── Helpers ───────────────────────────────────────────────────
39
-
40
- function formatRelativeTime(timestamp: number): string {
41
- const diff = Date.now() - timestamp;
42
- if (diff < 60000) return 'just now';
43
- if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
44
- if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
45
- return new Date(timestamp).toLocaleDateString();
46
- }
47
-
48
- function shouldShowDateSeparator(prev: AIMessage | undefined, curr: AIMessage): boolean {
49
- if (!prev) return true;
50
- const prevDay = new Date(prev.timestamp).toDateString();
51
- const currDay = new Date(curr.timestamp).toDateString();
52
- return prevDay !== currDay;
53
- }
54
-
55
- function formatDateSeparator(timestamp: number): string {
56
- const now = new Date();
57
- const date = new Date(timestamp);
58
- if (date.toDateString() === now.toDateString()) return 'Today';
59
- const yesterday = new Date(now);
60
- yesterday.setDate(yesterday.getDate() - 1);
61
- if (date.toDateString() === yesterday.toDateString()) return 'Yesterday';
62
- return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
63
- }
64
-
65
- // ─── Agent Avatar ──────────────────────────────────────────────
66
-
67
- function AgentAvatar() {
68
- return (
69
- <View style={s.agentAvatar}>
70
- <View style={s.avatarHead} />
71
- <View style={s.avatarBody} />
72
- </View>
73
- );
74
- }
75
-
76
- // ─── Main Component ────────────────────────────────────────────
77
-
78
- const CLOSED_STATUSES = ['closed', 'resolved'];
79
-
80
- export function SupportChatModal({
81
- visible,
82
- messages,
83
- onSend,
84
- onClose,
85
- isAgentTyping = false,
86
- isThinking = false,
87
- scrollToEndTrigger = 0,
88
- ticketStatus,
89
- }: SupportChatModalProps) {
90
- const isClosed = !!ticketStatus && CLOSED_STATUSES.includes(ticketStatus);
91
- const [text, setText] = useState('');
92
- const [keyboardHeight, setKeyboardHeight] = useState(0);
93
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
- const scrollRef = useRef<any>(null);
95
-
96
- // Scroll to bottom when new messages arrive or typing indicator changes
97
- useEffect(() => {
98
- if (messages.length > 0 || isAgentTyping) {
99
- setTimeout(() => scrollRef.current?.scrollToEnd?.({ animated: true }), 150);
100
- }
101
- }, [messages.length, isAgentTyping]);
102
-
103
- // Scroll when externally triggered (e.g., after message update in parent)
104
- useEffect(() => {
105
- if (scrollToEndTrigger && scrollToEndTrigger > 0) {
106
- setTimeout(() => scrollRef.current?.scrollToEnd?.({ animated: true }), 200);
107
- }
108
- }, [scrollToEndTrigger]);
109
-
110
- // Manually track keyboard height — reliable inside iOS pageSheet modals
111
- // where KeyboardAvoidingView miscalculates the offset from screen origin.
112
- useEffect(() => {
113
- const showSub = Keyboard.addListener('keyboardWillShow', (e) => {
114
- setKeyboardHeight(e.endCoordinates.height);
115
- setTimeout(() => scrollRef.current?.scrollToEnd?.({ animated: true }), 100);
116
- });
117
- const hideSub = Keyboard.addListener('keyboardWillHide', () => {
118
- setKeyboardHeight(0);
119
- });
120
- return () => {
121
- showSub.remove();
122
- hideSub.remove();
123
- };
124
- }, []);
125
-
126
- const handleSend = () => {
127
- if (!text.trim() || isThinking) return;
128
- onSend(text.trim());
129
- setText('');
130
- };
131
-
132
- const isEmpty = messages.length === 0 && !isAgentTyping;
133
-
134
- return (
135
- <Modal
136
- visible={visible}
137
- animationType="slide"
138
- presentationStyle="pageSheet"
139
- onRequestClose={onClose}
140
- >
141
- <StatusBar barStyle="light-content" />
142
- <View style={[s.container, keyboardHeight > 0 && { paddingBottom: keyboardHeight }]}>
143
- {/* Drag grip indicator */}
144
- <View style={s.dragHandle}>
145
- <View style={s.dragGrip} />
146
- </View>
147
-
148
- {/* ── Header ── */}
149
- <View style={s.header}>
150
- <Pressable onPress={onClose} style={s.headerBtn} hitSlop={12}>
151
- <CloseIcon size={20} color="rgba(255,255,255,0.7)" />
152
- </Pressable>
153
- <View style={s.headerCenter}>
154
- <Text style={s.headerTitle}>Support Chat</Text>
155
- <View style={s.headerStatus}>
156
- <View style={[s.statusDot, isClosed && s.statusDotClosed]} />
157
- <Text style={s.headerSubtitle}>
158
- {isClosed ? 'Conversation closed' : 'Agent online'}
159
- </Text>
160
- </View>
161
- </View>
162
- <View style={s.headerBtn} />
163
- </View>
164
-
165
- {/* ── Messages ── */}
166
- {isEmpty ? (
167
- <View style={s.emptyState}>
168
- <View style={s.emptyIcon}>
169
- <View style={s.emptyBubble} />
170
- <View style={s.emptyTail} />
171
- </View>
172
- <Text style={s.emptyTitle}>No messages yet</Text>
173
- <Text style={s.emptySubtitle}>Start the conversation below</Text>
174
- </View>
175
- ) : (
176
- <ScrollView
177
- ref={scrollRef}
178
- style={s.messagesList}
179
- contentContainerStyle={s.messagesContent}
180
- showsVerticalScrollIndicator={false}
181
- keyboardShouldPersistTaps="handled"
182
- >
183
- {messages.map((msg, i) => {
184
- const isUser = msg.role === 'user';
185
- const prev = messages[i - 1];
186
- const showDate = shouldShowDateSeparator(prev, msg);
187
-
188
- return (
189
- <View key={msg.id}>
190
- {/* Date separator */}
191
- {showDate && (
192
- <View style={s.dateSeparator}>
193
- <View style={s.dateLine} />
194
- <Text style={s.dateText}>{formatDateSeparator(msg.timestamp)}</Text>
195
- <View style={s.dateLine} />
196
- </View>
197
- )}
198
-
199
- {/* Message row */}
200
- <View style={[s.messageRow, isUser && s.messageRowUser]}>
201
- {/* Agent avatar (left side) */}
202
- {!isUser && <AgentAvatar />}
203
-
204
- <View style={s.bubbleColumn}>
205
- <View
206
- style={[
207
- s.bubble,
208
- isUser ? s.bubbleUser : s.bubbleAgent,
209
- ]}
210
- >
211
- <Text style={[s.bubbleText, !isUser && s.bubbleTextAgent]}>
212
- {msg.content}
213
- </Text>
214
- </View>
215
- <Text style={[s.timestamp, isUser && s.timestampUser]}>
216
- {formatRelativeTime(msg.timestamp)}
217
- </Text>
218
- </View>
219
- </View>
220
- </View>
221
- );
222
- })}
223
-
224
- {/* Typing indicator */}
225
- {isAgentTyping && (
226
- <View style={s.messageRow}>
227
- <AgentAvatar />
228
- <View style={s.bubbleColumn}>
229
- <View style={[s.bubble, s.bubbleAgent, s.typingBubble]}>
230
- <LoadingDots size={20} color="rgba(255,255,255,0.6)" />
231
- </View>
232
- </View>
233
- </View>
234
- )}
235
- </ScrollView>
236
- )}
237
-
238
- {/* ── Input Row or Closed Banner ── */}
239
- {isClosed ? (
240
- <View style={s.closedBanner}>
241
- <Text style={s.closedBannerText}>
242
- This conversation has been closed. Start a new request to get help.
243
- </Text>
244
- </View>
245
- ) : (
246
- <View style={s.inputRow}>
247
- <TextInput
248
- style={s.input}
249
- placeholder="Type a message..."
250
- placeholderTextColor="rgba(255,255,255,0.35)"
251
- value={text}
252
- onChangeText={setText}
253
- onSubmitEditing={handleSend}
254
- returnKeyType="send"
255
- editable={!isThinking}
256
- />
257
- <Pressable
258
- style={[s.sendBtn, text.trim() && !isThinking ? s.sendBtnActive : s.sendBtnInactive]}
259
- onPress={handleSend}
260
- disabled={!text.trim() || isThinking}
261
- >
262
- <SendArrowIcon size={18} color={text.trim() && !isThinking ? '#fff' : 'rgba(255,255,255,0.3)'} />
263
- </Pressable>
264
- </View>
265
- )}
266
- </View>
267
- </Modal>
268
- );
269
- }
270
-
271
- // ─── Styles ────────────────────────────────────────────────────
272
-
273
- const s = StyleSheet.create({
274
- container: {
275
- flex: 1,
276
- backgroundColor: '#0f0f1e',
277
- },
278
-
279
- // ── Drag Handle ──
280
- dragHandle: {
281
- alignItems: 'center',
282
- paddingTop: Platform.OS === 'ios' ? 52 : 16,
283
- paddingBottom: 6,
284
- },
285
- dragGrip: {
286
- width: 36,
287
- height: 5,
288
- borderRadius: 3,
289
- backgroundColor: 'rgba(255,255,255,0.2)',
290
- },
291
-
292
- // ── Header ──
293
- header: {
294
- flexDirection: 'row',
295
- alignItems: 'center',
296
- justifyContent: 'space-between',
297
- paddingHorizontal: 12,
298
- paddingTop: 10,
299
- paddingBottom: 14,
300
- backgroundColor: 'rgba(255,255,255,0.03)',
301
- borderBottomWidth: StyleSheet.hairlineWidth,
302
- borderBottomColor: 'rgba(255,255,255,0.08)',
303
- },
304
- headerBtn: {
305
- width: 36,
306
- height: 36,
307
- alignItems: 'center',
308
- justifyContent: 'center',
309
- },
310
- headerCenter: {
311
- alignItems: 'center',
312
- },
313
- headerTitle: {
314
- color: '#fff',
315
- fontSize: 17,
316
- fontWeight: '700',
317
- letterSpacing: 0.3,
318
- },
319
- headerStatus: {
320
- flexDirection: 'row',
321
- alignItems: 'center',
322
- gap: 5,
323
- marginTop: 3,
324
- },
325
- statusDot: {
326
- width: 7,
327
- height: 7,
328
- borderRadius: 4,
329
- backgroundColor: '#34C759',
330
- },
331
- statusDotClosed: {
332
- backgroundColor: '#8E8E93',
333
- },
334
- headerSubtitle: {
335
- color: 'rgba(255,255,255,0.5)',
336
- fontSize: 12,
337
- fontWeight: '500',
338
- },
339
-
340
- // ── Messages ──
341
- messagesList: {
342
- flex: 1,
343
- },
344
- messagesContent: {
345
- paddingHorizontal: 16,
346
- paddingVertical: 12,
347
- paddingBottom: 16,
348
- },
349
-
350
- // ── Date Separator ──
351
- dateSeparator: {
352
- flexDirection: 'row',
353
- alignItems: 'center',
354
- paddingVertical: 16,
355
- gap: 12,
356
- },
357
- dateLine: {
358
- flex: 1,
359
- height: StyleSheet.hairlineWidth,
360
- backgroundColor: 'rgba(255,255,255,0.08)',
361
- },
362
- dateText: {
363
- color: 'rgba(255,255,255,0.3)',
364
- fontSize: 11,
365
- fontWeight: '600',
366
- textTransform: 'uppercase',
367
- letterSpacing: 0.5,
368
- },
369
-
370
- // ── Message Row ──
371
- messageRow: {
372
- flexDirection: 'row',
373
- alignItems: 'flex-end',
374
- marginBottom: 4,
375
- gap: 8,
376
- },
377
- messageRowUser: {
378
- justifyContent: 'flex-end',
379
- },
380
- bubbleColumn: {
381
- maxWidth: '72%',
382
- },
383
-
384
- // ── Bubble ──
385
- bubble: {
386
- borderRadius: 18,
387
- paddingHorizontal: 14,
388
- paddingVertical: 10,
389
- },
390
- bubbleUser: {
391
- backgroundColor: '#7B68EE',
392
- borderBottomRightRadius: 6,
393
- elevation: 2,
394
- shadowColor: '#7B68EE',
395
- shadowOffset: { width: 0, height: 2 },
396
- shadowOpacity: 0.25,
397
- shadowRadius: 4,
398
- },
399
- bubbleAgent: {
400
- backgroundColor: 'rgba(255,255,255,0.08)',
401
- borderBottomLeftRadius: 6,
402
- },
403
- bubbleText: {
404
- fontSize: 15,
405
- lineHeight: 21,
406
- color: '#fff',
407
- },
408
- bubbleTextAgent: {
409
- color: 'rgba(255,255,255,0.9)',
410
- },
411
-
412
- // ── Timestamp ──
413
- timestamp: {
414
- color: 'rgba(255,255,255,0.25)',
415
- fontSize: 11,
416
- marginTop: 4,
417
- marginLeft: 4,
418
- marginBottom: 6,
419
- },
420
- timestampUser: {
421
- textAlign: 'right',
422
- marginRight: 4,
423
- marginLeft: 0,
424
- },
425
-
426
- // ── Agent Avatar ──
427
- agentAvatar: {
428
- width: 30,
429
- height: 30,
430
- borderRadius: 15,
431
- backgroundColor: '#7B68EE',
432
- alignItems: 'center',
433
- justifyContent: 'center',
434
- marginBottom: 14,
435
- },
436
- avatarHead: {
437
- width: 10,
438
- height: 10,
439
- borderRadius: 5,
440
- backgroundColor: 'rgba(255,255,255,0.9)',
441
- marginTop: 2,
442
- },
443
- avatarBody: {
444
- width: 16,
445
- height: 6,
446
- borderTopLeftRadius: 8,
447
- borderTopRightRadius: 8,
448
- backgroundColor: 'rgba(255,255,255,0.9)',
449
- marginTop: 1,
450
- },
451
-
452
- // ── Typing Indicator ──
453
- typingBubble: {
454
- flexDirection: 'row',
455
- alignItems: 'center',
456
- paddingVertical: 12,
457
- paddingHorizontal: 16,
458
- minWidth: 60,
459
- },
460
-
461
- // ── Empty State ──
462
- emptyState: {
463
- flex: 1,
464
- alignItems: 'center',
465
- justifyContent: 'center',
466
- paddingBottom: 60,
467
- },
468
- emptyIcon: {
469
- width: 64,
470
- height: 64,
471
- alignItems: 'center',
472
- justifyContent: 'center',
473
- marginBottom: 20,
474
- },
475
- emptyBubble: {
476
- width: 48,
477
- height: 36,
478
- borderRadius: 12,
479
- backgroundColor: 'rgba(255,255,255,0.08)',
480
- borderWidth: 1,
481
- borderColor: 'rgba(255,255,255,0.12)',
482
- },
483
- emptyTail: {
484
- position: 'absolute',
485
- bottom: 10,
486
- left: 16,
487
- width: 0,
488
- height: 0,
489
- borderTopWidth: 8,
490
- borderTopColor: 'rgba(255,255,255,0.08)',
491
- borderRightWidth: 8,
492
- borderRightColor: 'transparent',
493
- },
494
- emptyTitle: {
495
- color: 'rgba(255,255,255,0.5)',
496
- fontSize: 17,
497
- fontWeight: '600',
498
- marginBottom: 6,
499
- },
500
- emptySubtitle: {
501
- color: 'rgba(255,255,255,0.25)',
502
- fontSize: 14,
503
- },
504
-
505
- // ── Closed Banner ──
506
- closedBanner: {
507
- paddingHorizontal: 16,
508
- paddingVertical: 16,
509
- paddingBottom: Platform.OS === 'ios' ? 36 : 16,
510
- backgroundColor: 'rgba(255,255,255,0.03)',
511
- borderTopWidth: StyleSheet.hairlineWidth,
512
- borderTopColor: 'rgba(255,255,255,0.06)',
513
- alignItems: 'center',
514
- },
515
- closedBannerText: {
516
- color: 'rgba(255,255,255,0.35)',
517
- fontSize: 13,
518
- textAlign: 'center',
519
- lineHeight: 19,
520
- },
521
-
522
- // ── Input Row ──
523
- inputRow: {
524
- flexDirection: 'row',
525
- alignItems: 'center',
526
- gap: 10,
527
- paddingHorizontal: 16,
528
- paddingVertical: 12,
529
- paddingBottom: Platform.OS === 'ios' ? 36 : 16,
530
- backgroundColor: 'rgba(255,255,255,0.02)',
531
- borderTopWidth: StyleSheet.hairlineWidth,
532
- borderTopColor: 'rgba(255,255,255,0.06)',
533
- },
534
- input: {
535
- flex: 1,
536
- backgroundColor: 'rgba(255,255,255,0.06)',
537
- borderWidth: 1,
538
- borderColor: 'rgba(255,255,255,0.08)',
539
- borderRadius: 24,
540
- paddingHorizontal: 18,
541
- paddingVertical: 11,
542
- color: '#fff',
543
- fontSize: 16,
544
- },
545
- sendBtn: {
546
- width: 42,
547
- height: 42,
548
- borderRadius: 21,
549
- justifyContent: 'center',
550
- alignItems: 'center',
551
- },
552
- sendBtnActive: {
553
- backgroundColor: '#7B68EE',
554
- elevation: 3,
555
- shadowColor: '#7B68EE',
556
- shadowOffset: { width: 0, height: 2 },
557
- shadowOpacity: 0.3,
558
- shadowRadius: 4,
559
- },
560
- sendBtnInactive: {
561
- backgroundColor: 'rgba(255,255,255,0.06)',
562
- },
563
- });
@@ -1,161 +0,0 @@
1
- /**
2
- * Support Greeting & Quick Replies — shown when chat opens in support mode.
3
- *
4
- * Renders a welcome message with an avatar and quick reply buttons
5
- * that pre-fill the user's first message.
6
- */
7
-
8
-
9
- import {
10
- View,
11
- Text,
12
- TouchableOpacity,
13
- Image,
14
- StyleSheet,
15
- ScrollView,
16
- } from 'react-native';
17
- import type { SupportModeConfig } from './types';
18
-
19
- interface SupportGreetingProps {
20
- config: SupportModeConfig;
21
- onQuickReply: (message: string) => void;
22
- theme?: {
23
- primaryColor?: string;
24
- textColor?: string;
25
- backgroundColor?: string;
26
- };
27
- }
28
-
29
- export function SupportGreeting({
30
- config,
31
- onQuickReply,
32
- theme,
33
- }: SupportGreetingProps) {
34
- const greeting = config.greeting;
35
- const quickReplies = config.quickReplies ?? [];
36
-
37
- if (!greeting) return null;
38
-
39
- const primary = theme?.primaryColor ?? '#8b5cf6';
40
- const textColor = theme?.textColor ?? '#ffffff';
41
- const bgColor = theme?.backgroundColor ?? 'rgba(26, 26, 46, 0.95)';
42
-
43
- return (
44
- <View style={styles.container}>
45
- {/* Avatar + Agent Name */}
46
- <View style={styles.header}>
47
- {greeting.avatarUrl ? (
48
- <Image
49
- source={{ uri: greeting.avatarUrl }}
50
- style={styles.avatar}
51
- />
52
- ) : (
53
- <View style={[styles.avatarPlaceholder, { backgroundColor: primary }]}>
54
- <Text style={styles.avatarEmoji}>🤖</Text>
55
- </View>
56
- )}
57
- {greeting.agentName && (
58
- <Text style={[styles.agentName, { color: textColor }]}>
59
- {greeting.agentName}
60
- </Text>
61
- )}
62
- </View>
63
-
64
- {/* Greeting Message */}
65
- <View style={[styles.messageBubble, { backgroundColor: bgColor }]}>
66
- <Text style={[styles.messageText, { color: textColor }]}>
67
- {greeting.message}
68
- </Text>
69
- </View>
70
-
71
- {/* Quick Replies */}
72
- {quickReplies.length > 0 && (
73
- <ScrollView
74
- horizontal
75
- showsHorizontalScrollIndicator={false}
76
- contentContainerStyle={styles.quickRepliesContainer}
77
- >
78
- {quickReplies.map((reply, index) => (
79
- <TouchableOpacity
80
- key={`qr-${index}`}
81
- style={[styles.quickReplyButton, { borderColor: primary }]}
82
- onPress={() => onQuickReply(reply.message ?? reply.label)}
83
- activeOpacity={0.7}
84
- >
85
- {reply.icon && (
86
- <Text style={styles.quickReplyIcon}>{reply.icon}</Text>
87
- )}
88
- <Text style={[styles.quickReplyText, { color: primary }]}>
89
- {reply.label}
90
- </Text>
91
- </TouchableOpacity>
92
- ))}
93
- </ScrollView>
94
- )}
95
- </View>
96
- );
97
- }
98
-
99
- const styles = StyleSheet.create({
100
- container: {
101
- paddingHorizontal: 16,
102
- paddingVertical: 12,
103
- },
104
- header: {
105
- flexDirection: 'row',
106
- alignItems: 'center',
107
- gap: 10,
108
- marginBottom: 12,
109
- },
110
- avatar: {
111
- width: 36,
112
- height: 36,
113
- borderRadius: 18,
114
- },
115
- avatarPlaceholder: {
116
- width: 36,
117
- height: 36,
118
- borderRadius: 18,
119
- alignItems: 'center',
120
- justifyContent: 'center',
121
- },
122
- avatarEmoji: {
123
- fontSize: 18,
124
- },
125
- agentName: {
126
- fontSize: 14,
127
- fontWeight: '600',
128
- },
129
- messageBubble: {
130
- borderRadius: 16,
131
- borderTopLeftRadius: 4,
132
- paddingHorizontal: 14,
133
- paddingVertical: 10,
134
- marginBottom: 12,
135
- maxWidth: '85%',
136
- },
137
- messageText: {
138
- fontSize: 14,
139
- lineHeight: 20,
140
- },
141
- quickRepliesContainer: {
142
- gap: 8,
143
- paddingVertical: 4,
144
- },
145
- quickReplyButton: {
146
- flexDirection: 'row',
147
- alignItems: 'center',
148
- gap: 6,
149
- paddingHorizontal: 14,
150
- paddingVertical: 8,
151
- borderRadius: 20,
152
- borderWidth: 1,
153
- },
154
- quickReplyIcon: {
155
- fontSize: 14,
156
- },
157
- quickReplyText: {
158
- fontSize: 13,
159
- fontWeight: '500',
160
- },
161
- });