@mobileai/react-native 0.9.16 → 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 (214) hide show
  1. package/README.md +2 -2
  2. package/package.json +5 -8
  3. package/lib/module/__cli_tmp__.js.map +0 -1
  4. package/lib/module/components/AIAgent.js.map +0 -1
  5. package/lib/module/components/AIZone.js.map +0 -1
  6. package/lib/module/components/AgentChatBar.js.map +0 -1
  7. package/lib/module/components/AgentErrorBoundary.js.map +0 -1
  8. package/lib/module/components/AgentOverlay.js.map +0 -1
  9. package/lib/module/components/DiscoveryTooltip.js.map +0 -1
  10. package/lib/module/components/HighlightOverlay.js.map +0 -1
  11. package/lib/module/components/Icons.js.map +0 -1
  12. package/lib/module/components/ProactiveHint.js.map +0 -1
  13. package/lib/module/components/cards/InfoCard.js.map +0 -1
  14. package/lib/module/components/cards/ReviewSummary.js.map +0 -1
  15. package/lib/module/config/endpoints.js.map +0 -1
  16. package/lib/module/core/ActionRegistry.js.map +0 -1
  17. package/lib/module/core/AgentRuntime.js.map +0 -1
  18. package/lib/module/core/FiberTreeWalker.js.map +0 -1
  19. package/lib/module/core/IdleDetector.js.map +0 -1
  20. package/lib/module/core/MCPBridge.js.map +0 -1
  21. package/lib/module/core/ScreenDehydrator.js.map +0 -1
  22. package/lib/module/core/ZoneRegistry.js.map +0 -1
  23. package/lib/module/core/systemPrompt.js.map +0 -1
  24. package/lib/module/core/types.js.map +0 -1
  25. package/lib/module/hooks/useAction.js.map +0 -1
  26. package/lib/module/index.js.map +0 -1
  27. package/lib/module/plugin/withAppIntents.js.map +0 -1
  28. package/lib/module/providers/GeminiProvider.js.map +0 -1
  29. package/lib/module/providers/OpenAIProvider.js.map +0 -1
  30. package/lib/module/providers/ProviderFactory.js.map +0 -1
  31. package/lib/module/services/AudioInputService.js.map +0 -1
  32. package/lib/module/services/AudioOutputService.js.map +0 -1
  33. package/lib/module/services/KnowledgeBaseService.js.map +0 -1
  34. package/lib/module/services/VoiceService.js.map +0 -1
  35. package/lib/module/services/flags/FlagService.js.map +0 -1
  36. package/lib/module/services/telemetry/MobileAI.js.map +0 -1
  37. package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
  38. package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
  39. package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
  40. package/lib/module/services/telemetry/device.js.map +0 -1
  41. package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
  42. package/lib/module/services/telemetry/index.js.map +0 -1
  43. package/lib/module/services/telemetry/types.js.map +0 -1
  44. package/lib/module/support/CSATSurvey.js.map +0 -1
  45. package/lib/module/support/EscalationEventSource.js.map +0 -1
  46. package/lib/module/support/EscalationSocket.js.map +0 -1
  47. package/lib/module/support/SupportChatModal.js.map +0 -1
  48. package/lib/module/support/SupportGreeting.js.map +0 -1
  49. package/lib/module/support/TicketStore.js.map +0 -1
  50. package/lib/module/support/escalateTool.js.map +0 -1
  51. package/lib/module/support/index.js.map +0 -1
  52. package/lib/module/support/supportPrompt.js.map +0 -1
  53. package/lib/module/support/types.js.map +0 -1
  54. package/lib/module/tools/datePickerTool.js.map +0 -1
  55. package/lib/module/tools/guideTool.js.map +0 -1
  56. package/lib/module/tools/index.js.map +0 -1
  57. package/lib/module/tools/keyboardTool.js.map +0 -1
  58. package/lib/module/tools/longPressTool.js.map +0 -1
  59. package/lib/module/tools/pickerTool.js.map +0 -1
  60. package/lib/module/tools/restoreTool.js.map +0 -1
  61. package/lib/module/tools/scrollTool.js.map +0 -1
  62. package/lib/module/tools/simplifyTool.js.map +0 -1
  63. package/lib/module/tools/sliderTool.js.map +0 -1
  64. package/lib/module/tools/tapTool.js.map +0 -1
  65. package/lib/module/tools/typeTool.js.map +0 -1
  66. package/lib/module/tools/types.js.map +0 -1
  67. package/lib/module/types/jsx.d.js.map +0 -1
  68. package/lib/module/utils/audioUtils.js.map +0 -1
  69. package/lib/module/utils/logger.js.map +0 -1
  70. package/lib/typescript/babel.config.d.ts.map +0 -1
  71. package/lib/typescript/bin/generate-map.d.cts.map +0 -1
  72. package/lib/typescript/eslint.config.d.mts.map +0 -1
  73. package/lib/typescript/generate-map.d.ts.map +0 -1
  74. package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
  75. package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
  76. package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
  77. package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
  78. package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
  79. package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
  80. package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
  81. package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
  82. package/lib/typescript/src/components/Icons.d.ts.map +0 -1
  83. package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
  84. package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
  85. package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
  86. package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
  87. package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
  88. package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
  89. package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
  90. package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
  91. package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
  92. package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
  93. package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
  94. package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
  95. package/lib/typescript/src/core/types.d.ts.map +0 -1
  96. package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
  97. package/lib/typescript/src/index.d.ts.map +0 -1
  98. package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
  99. package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
  100. package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
  101. package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
  102. package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
  103. package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
  104. package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
  105. package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
  106. package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
  107. package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
  108. package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
  109. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
  110. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
  111. package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
  112. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
  113. package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
  114. package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
  115. package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
  116. package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
  117. package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
  118. package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
  119. package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
  120. package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
  121. package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
  122. package/lib/typescript/src/support/index.d.ts.map +0 -1
  123. package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
  124. package/lib/typescript/src/support/types.d.ts.map +0 -1
  125. package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
  126. package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
  127. package/lib/typescript/src/tools/index.d.ts.map +0 -1
  128. package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
  129. package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
  130. package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
  131. package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
  132. package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
  133. package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
  134. package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
  135. package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
  136. package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
  137. package/lib/typescript/src/tools/types.d.ts.map +0 -1
  138. package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
  139. package/lib/typescript/src/utils/logger.d.ts.map +0 -1
  140. package/src/__cli_tmp__.tsx +0 -9
  141. package/src/cli/analyzers/chain-analyzer.ts +0 -183
  142. package/src/cli/extractors/ai-extractor.ts +0 -6
  143. package/src/cli/extractors/ast-extractor.ts +0 -551
  144. package/src/cli/generate-intents.ts +0 -140
  145. package/src/cli/generate-map.ts +0 -121
  146. package/src/cli/generate-swift.ts +0 -116
  147. package/src/cli/scanners/expo-scanner.ts +0 -203
  148. package/src/cli/scanners/rn-scanner.ts +0 -445
  149. package/src/components/AIAgent.tsx +0 -1716
  150. package/src/components/AIZone.tsx +0 -147
  151. package/src/components/AgentChatBar.tsx +0 -1143
  152. package/src/components/AgentErrorBoundary.tsx +0 -78
  153. package/src/components/AgentOverlay.tsx +0 -73
  154. package/src/components/DiscoveryTooltip.tsx +0 -148
  155. package/src/components/HighlightOverlay.tsx +0 -136
  156. package/src/components/Icons.tsx +0 -253
  157. package/src/components/ProactiveHint.tsx +0 -145
  158. package/src/components/cards/InfoCard.tsx +0 -58
  159. package/src/components/cards/ReviewSummary.tsx +0 -76
  160. package/src/config/endpoints.ts +0 -22
  161. package/src/core/ActionRegistry.ts +0 -105
  162. package/src/core/AgentRuntime.ts +0 -1471
  163. package/src/core/FiberTreeWalker.ts +0 -930
  164. package/src/core/IdleDetector.ts +0 -72
  165. package/src/core/MCPBridge.ts +0 -163
  166. package/src/core/ScreenDehydrator.ts +0 -53
  167. package/src/core/ZoneRegistry.ts +0 -44
  168. package/src/core/systemPrompt.ts +0 -431
  169. package/src/core/types.ts +0 -521
  170. package/src/hooks/useAction.ts +0 -182
  171. package/src/index.ts +0 -83
  172. package/src/plugin/withAppIntents.ts +0 -98
  173. package/src/providers/GeminiProvider.ts +0 -357
  174. package/src/providers/OpenAIProvider.ts +0 -379
  175. package/src/providers/ProviderFactory.ts +0 -36
  176. package/src/services/AudioInputService.ts +0 -226
  177. package/src/services/AudioOutputService.ts +0 -236
  178. package/src/services/KnowledgeBaseService.ts +0 -156
  179. package/src/services/VoiceService.ts +0 -451
  180. package/src/services/flags/FlagService.ts +0 -137
  181. package/src/services/telemetry/MobileAI.ts +0 -66
  182. package/src/services/telemetry/PiiScrubber.ts +0 -17
  183. package/src/services/telemetry/TelemetryService.ts +0 -323
  184. package/src/services/telemetry/TouchAutoCapture.ts +0 -165
  185. package/src/services/telemetry/device.ts +0 -93
  186. package/src/services/telemetry/deviceMetadata.ts +0 -13
  187. package/src/services/telemetry/index.ts +0 -13
  188. package/src/services/telemetry/types.ts +0 -75
  189. package/src/support/CSATSurvey.tsx +0 -304
  190. package/src/support/EscalationEventSource.ts +0 -190
  191. package/src/support/EscalationSocket.ts +0 -152
  192. package/src/support/SupportChatModal.tsx +0 -563
  193. package/src/support/SupportGreeting.tsx +0 -161
  194. package/src/support/TicketStore.ts +0 -100
  195. package/src/support/escalateTool.ts +0 -174
  196. package/src/support/index.ts +0 -29
  197. package/src/support/supportPrompt.ts +0 -55
  198. package/src/support/types.ts +0 -155
  199. package/src/tools/datePickerTool.ts +0 -60
  200. package/src/tools/guideTool.ts +0 -76
  201. package/src/tools/index.ts +0 -20
  202. package/src/tools/keyboardTool.ts +0 -30
  203. package/src/tools/longPressTool.ts +0 -61
  204. package/src/tools/pickerTool.ts +0 -115
  205. package/src/tools/restoreTool.ts +0 -33
  206. package/src/tools/scrollTool.ts +0 -156
  207. package/src/tools/simplifyTool.ts +0 -33
  208. package/src/tools/sliderTool.ts +0 -65
  209. package/src/tools/tapTool.ts +0 -93
  210. package/src/tools/typeTool.ts +0 -113
  211. package/src/tools/types.ts +0 -58
  212. package/src/types/jsx.d.ts +0 -20
  213. package/src/utils/audioUtils.ts +0 -54
  214. 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
- });