@arkesel/rn-kova-live-chat 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.
- package/LICENSE +21 -0
- package/README.md +994 -0
- package/package.json +46 -0
- package/src/ChatWidget.js +791 -0
- package/src/index.d.ts +85 -0
- package/src/index.js +3 -0
- package/src/styles.js +480 -0
package/README.md
ADDED
|
@@ -0,0 +1,994 @@
|
|
|
1
|
+
# React Native Chat Widget π¬
|
|
2
|
+
|
|
3
|
+
A powerful, production-ready React Native chat widget with real-time messaging, customer info collection, and zero native dependencies. Perfect for customer support, live chat, and messaging features in your React Native apps.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/rn-kova-live-chat)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://reactnative.dev/)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## β¨ Features
|
|
12
|
+
|
|
13
|
+
- β
**Real-time messaging** via Socket.IO
|
|
14
|
+
- β
**Zero native dependencies** - Works with Expo Go
|
|
15
|
+
- β
**Customer info collection** with smart form handling
|
|
16
|
+
- β
**6 position options** for floating action button
|
|
17
|
+
- β
**Full customization** - Colors, positions, themes
|
|
18
|
+
- β
**Message status indicators** (sent β, delivered ββ)
|
|
19
|
+
- β
**File attachment** display with download
|
|
20
|
+
- β
**Emoji picker** with 38 emojis
|
|
21
|
+
- β
**Optimistic updates** for instant message display
|
|
22
|
+
- β
**Auto-persistence** via AsyncStorage
|
|
23
|
+
- β
**30-second engagement alert** with animations
|
|
24
|
+
- β
**TypeScript support** with full type definitions
|
|
25
|
+
- β
**Pre-fill customer info** for logged-in users
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## π¦ Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install rn-kova-live-chat socket.io-client moment @react-native-async-storage/async-storage
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Expo Users:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx expo install rn-kova-live-chat socket.io-client moment @react-native-async-storage/async-storage
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## π Quick Start
|
|
44
|
+
|
|
45
|
+
### Basic Usage (Minimal Setup):
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
import React from 'react';
|
|
49
|
+
import { View } from 'react-native';
|
|
50
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
51
|
+
|
|
52
|
+
export default function App() {
|
|
53
|
+
return (
|
|
54
|
+
<View style={{ flex: 1 }}>
|
|
55
|
+
<YourAppContent />
|
|
56
|
+
|
|
57
|
+
<ChatWidget
|
|
58
|
+
apiKey="your-api-key"
|
|
59
|
+
organizationId="your-organization-id"
|
|
60
|
+
/>
|
|
61
|
+
</View>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
That's it! Your chat widget is ready with only 2 required props! π
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## π¨ Customization
|
|
71
|
+
|
|
72
|
+
### Custom Colors & Position:
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
<ChatWidget
|
|
76
|
+
apiKey="your-api-key"
|
|
77
|
+
organizationId="your-organization-id"
|
|
78
|
+
primaryColor="#8B5CF6" // Header, button, user messages
|
|
79
|
+
secondaryColor="#EC4899" // Send button accent
|
|
80
|
+
position="top-right" // FAB position
|
|
81
|
+
/>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Skip Form for Logged-In Users:
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
const { user } = useAuth();
|
|
88
|
+
|
|
89
|
+
<ChatWidget
|
|
90
|
+
apiKey="your-api-key"
|
|
91
|
+
organizationId="your-organization-id"
|
|
92
|
+
initialCustomerName={user?.name}
|
|
93
|
+
initialCustomerPhone={user?.phone}
|
|
94
|
+
// Form will be skipped automatically!
|
|
95
|
+
/>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## π Complete Props Documentation
|
|
101
|
+
|
|
102
|
+
### Required Props:
|
|
103
|
+
|
|
104
|
+
| Prop | Type | Description |
|
|
105
|
+
|------|------|-------------|
|
|
106
|
+
| `apiKey` | `string` | Your API authentication key From KOVA dashboard |
|
|
107
|
+
| `organizationId` | `string` | Your organization identifier From KOVA dashboard |
|
|
108
|
+
|
|
109
|
+
### Optional Props:
|
|
110
|
+
|
|
111
|
+
| Prop | Type | Default | Description |
|
|
112
|
+
|------|------|---------|-------------|
|
|
113
|
+
| `primaryColor` | `string` | `"#142444"` | Main color for header, FAB, user messages |
|
|
114
|
+
| `secondaryColor` | `string` | `"#13cc7c"` | Accent color for send button |
|
|
115
|
+
| `position` | `string` | `"bottom-right"` | FAB position: `"top-right"`, `"top-left"`, `"bottom-right"`, `"bottom-left"`, `"middle-right"`, `"middle-left"` |
|
|
116
|
+
| `initialCustomerName` | `string \| null` | `null` | Pre-fill customer name (skips form if both name and phone provided) |
|
|
117
|
+
| `initialCustomerPhone` | `string \| null` | `null` | Pre-fill customer phone (skips form if both name and phone provided) |
|
|
118
|
+
| `theme` | `object` | `{}` | Reserved for future theming options |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## π± Usage Examples
|
|
123
|
+
|
|
124
|
+
### 1. **E-commerce App**
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import React from 'react';
|
|
128
|
+
import { View } from 'react-native';
|
|
129
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
130
|
+
|
|
131
|
+
export default function ShoppingApp() {
|
|
132
|
+
return (
|
|
133
|
+
<View style={{ flex: 1 }}>
|
|
134
|
+
<ProductCatalog />
|
|
135
|
+
|
|
136
|
+
<ChatWidget
|
|
137
|
+
apiKey={Config.CHAT_API_KEY}
|
|
138
|
+
organizationId={Config.ORG_ID}
|
|
139
|
+
primaryColor="#FF6B6B"
|
|
140
|
+
position="bottom-left"
|
|
141
|
+
/>
|
|
142
|
+
</View>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 2. **Healthcare App with User Context**
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
import React from 'react';
|
|
151
|
+
import { View } from 'react-native';
|
|
152
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
153
|
+
import { usePatient } from './context/PatientContext';
|
|
154
|
+
|
|
155
|
+
export default function HealthcareApp() {
|
|
156
|
+
const { patient } = usePatient();
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<View style={{ flex: 1 }}>
|
|
160
|
+
<AppointmentScreen />
|
|
161
|
+
|
|
162
|
+
<ChatWidget
|
|
163
|
+
apiKey={Config.CHAT_API_KEY}
|
|
164
|
+
organizationId={Config.ORG_ID}
|
|
165
|
+
initialCustomerName={patient?.fullName}
|
|
166
|
+
initialCustomerPhone={patient?.phoneNumber}
|
|
167
|
+
primaryColor="#0EA5E9"
|
|
168
|
+
secondaryColor="#10B981"
|
|
169
|
+
/>
|
|
170
|
+
</View>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 3. **Multi-tenant SaaS App**
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
import React from 'react';
|
|
179
|
+
import { View } from 'react-native';
|
|
180
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
181
|
+
import { useTenant } from './hooks/useTenant';
|
|
182
|
+
|
|
183
|
+
export default function MultiTenantApp() {
|
|
184
|
+
const { tenant, user } = useTenant();
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<View style={{ flex: 1 }}>
|
|
188
|
+
<TenantDashboard />
|
|
189
|
+
|
|
190
|
+
<ChatWidget
|
|
191
|
+
apiKey={tenant.chatApiKey} // Tenant-specific API key
|
|
192
|
+
organizationId={tenant.organizationId}
|
|
193
|
+
initialCustomerName={user?.name}
|
|
194
|
+
initialCustomerPhone={user?.phone}
|
|
195
|
+
primaryColor={tenant.brandColor} // Tenant branding
|
|
196
|
+
secondaryColor={tenant.accentColor}
|
|
197
|
+
position="middle-right"
|
|
198
|
+
/>
|
|
199
|
+
</View>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 4. **Conditional Rendering by Screen**
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
import React from 'react';
|
|
208
|
+
import { View } from 'react-native';
|
|
209
|
+
import { useRoute } from '@react-navigation/native';
|
|
210
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
211
|
+
|
|
212
|
+
export default function App() {
|
|
213
|
+
const route = useRoute();
|
|
214
|
+
const showChat = ['Home', 'Products', 'Support'].includes(route.name);
|
|
215
|
+
|
|
216
|
+
return (
|
|
217
|
+
<View style={{ flex: 1 }}>
|
|
218
|
+
<Navigation />
|
|
219
|
+
|
|
220
|
+
{showChat && (
|
|
221
|
+
<ChatWidget
|
|
222
|
+
apiKey={Config.CHAT_API_KEY}
|
|
223
|
+
organizationId={Config.ORG_ID}
|
|
224
|
+
position={route.name === 'Support' ? 'middle-right' : 'bottom-right'}
|
|
225
|
+
/>
|
|
226
|
+
)}
|
|
227
|
+
</View>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 5. **With Redux State**
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
import React from 'react';
|
|
236
|
+
import { View } from 'react-native';
|
|
237
|
+
import { useSelector } from 'react-redux';
|
|
238
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
239
|
+
|
|
240
|
+
export default function App() {
|
|
241
|
+
const user = useSelector(state => state.auth.user);
|
|
242
|
+
const theme = useSelector(state => state.settings.theme);
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
<View style={{ flex: 1 }}>
|
|
246
|
+
<AppContent />
|
|
247
|
+
|
|
248
|
+
<ChatWidget
|
|
249
|
+
apiKey={Config.CHAT_API_KEY}
|
|
250
|
+
organizationId={Config.ORG_ID}
|
|
251
|
+
initialCustomerName={user?.displayName}
|
|
252
|
+
initialCustomerPhone={user?.phoneNumber}
|
|
253
|
+
primaryColor={theme.primaryColor}
|
|
254
|
+
secondaryColor={theme.secondaryColor}
|
|
255
|
+
/>
|
|
256
|
+
</View>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### 6. **Environment-based Configuration**
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
import React from 'react';
|
|
265
|
+
import { View } from 'react-native';
|
|
266
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
267
|
+
import Config from 'react-native-config';
|
|
268
|
+
|
|
269
|
+
export default function App() {
|
|
270
|
+
return (
|
|
271
|
+
<View style={{ flex: 1 }}>
|
|
272
|
+
<AppContent />
|
|
273
|
+
|
|
274
|
+
<ChatWidget
|
|
275
|
+
apiKey={Config.CHAT_API_KEY}
|
|
276
|
+
organizationId={Config.CHAT_ORG_ID}
|
|
277
|
+
primaryColor={Config.BRAND_PRIMARY}
|
|
278
|
+
secondaryColor={Config.BRAND_SECONDARY}
|
|
279
|
+
/>
|
|
280
|
+
</View>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## π¨ Position Options
|
|
288
|
+
|
|
289
|
+
The widget supports 6 different positions:
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
// Top positions
|
|
293
|
+
position="top-right" // Top right corner
|
|
294
|
+
position="top-left" // Top left corner
|
|
295
|
+
|
|
296
|
+
// Bottom positions (default)
|
|
297
|
+
position="bottom-right" // Bottom right corner (default)
|
|
298
|
+
position="bottom-left" // Bottom left corner
|
|
299
|
+
|
|
300
|
+
// Middle positions
|
|
301
|
+
position="middle-right" // Middle right edge
|
|
302
|
+
position="middle-left" // Middle left edge
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## π¨ Color Customization Examples
|
|
308
|
+
|
|
309
|
+
### Professional Blue:
|
|
310
|
+
```javascript
|
|
311
|
+
primaryColor="#2563EB"
|
|
312
|
+
secondaryColor="#3B82F6"
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Vibrant Purple:
|
|
316
|
+
```javascript
|
|
317
|
+
primaryColor="#8B5CF6"
|
|
318
|
+
secondaryColor="#A78BFA"
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Modern Green:
|
|
322
|
+
```javascript
|
|
323
|
+
primaryColor="#059669"
|
|
324
|
+
secondaryColor="#10B981"
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Elegant Dark:
|
|
328
|
+
```javascript
|
|
329
|
+
primaryColor="#1F2937"
|
|
330
|
+
secondaryColor="#6B7280"
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Bold Red:
|
|
334
|
+
```javascript
|
|
335
|
+
primaryColor="#DC2626"
|
|
336
|
+
secondaryColor="#EF4444"
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## π§ Features in Detail
|
|
342
|
+
|
|
343
|
+
### 1. **Customer Information Form**
|
|
344
|
+
|
|
345
|
+
The widget automatically shows a form to collect:
|
|
346
|
+
- Customer name (required)
|
|
347
|
+
- Customer phone (required)
|
|
348
|
+
- Customer email (optional)
|
|
349
|
+
|
|
350
|
+
**Skip the form:** Provide both `initialCustomerName` AND `initialCustomerPhone` props:
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
<ChatWidget
|
|
354
|
+
apiKey="your-api-key"
|
|
355
|
+
organizationId="your-org-id"
|
|
356
|
+
initialCustomerName="John Doe"
|
|
357
|
+
initialCustomerPhone="+233 24 123 4567"
|
|
358
|
+
// Form is automatically skipped! β
|
|
359
|
+
/>
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Priority logic:**
|
|
363
|
+
1. If both props provided β Use props, skip form
|
|
364
|
+
2. If data in AsyncStorage β Use stored data, skip form
|
|
365
|
+
3. Otherwise β Show form
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
### 2. **Real-time Messaging**
|
|
370
|
+
|
|
371
|
+
- Instant message delivery via Socket.IO
|
|
372
|
+
- Optimistic updates (messages appear immediately)
|
|
373
|
+
- Message status indicators (β sent, ββ delivered)
|
|
374
|
+
- Auto-scroll to latest message
|
|
375
|
+
- Support for text and file attachments
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
### 3. **Message Status**
|
|
380
|
+
|
|
381
|
+
```
|
|
382
|
+
β - Message sent
|
|
383
|
+
ββ - Message delivered (echoed by server)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
### 4. **Engagement Alert**
|
|
389
|
+
|
|
390
|
+
After 30 seconds of inactivity, an alert bubble appears:
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
π¬ [Need help? Chat with us!] [β]
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
- Auto-hides when chat is opened
|
|
397
|
+
- Can be manually dismissed
|
|
398
|
+
- Smooth fade animations
|
|
399
|
+
- Shows only once per session
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### 5. **Emoji Picker**
|
|
404
|
+
|
|
405
|
+
Built-in emoji picker with 38 popular emojis:
|
|
406
|
+
- π π π π€£ π π π π π π
|
|
407
|
+
- π π π π΄ π€ π€ π± π π
π
|
|
408
|
+
- π π π π₯ π β€οΈ π β¨ β π
|
|
409
|
+
- π‘ β
β π π· πΌοΈ π π
|
|
410
|
+
|
|
411
|
+
Toggle with the π button in the input area.
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
### 6. **File Attachments**
|
|
416
|
+
|
|
417
|
+
Display file attachments from agent messages:
|
|
418
|
+
- Shows file name with download icon (β¬οΈ)
|
|
419
|
+
- Click to open/download file
|
|
420
|
+
- Supports various file types
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
### 7. **Data Persistence**
|
|
425
|
+
|
|
426
|
+
Automatically stores in AsyncStorage:
|
|
427
|
+
- Chat ID (UUID)
|
|
428
|
+
- Customer name
|
|
429
|
+
- Customer phone
|
|
430
|
+
- Customer email
|
|
431
|
+
|
|
432
|
+
Data persists across app sessions.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## π Server Integration (Socket.IO)
|
|
437
|
+
|
|
438
|
+
### Events Emitted by Widget:
|
|
439
|
+
|
|
440
|
+
#### 1. `join_chat`
|
|
441
|
+
Emitted when widget connects:
|
|
442
|
+
```javascript
|
|
443
|
+
{
|
|
444
|
+
chatId: "uuid-v4-string",
|
|
445
|
+
apiKey: "your-api-key",
|
|
446
|
+
organizationId: "your-org-id",
|
|
447
|
+
customerName?: "John Doe" // If available
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
#### 2. `send_message`
|
|
452
|
+
Emitted when user sends a message:
|
|
453
|
+
```javascript
|
|
454
|
+
{
|
|
455
|
+
chatId: "uuid-v4-string",
|
|
456
|
+
message: "Hello, I need help",
|
|
457
|
+
sender: "user",
|
|
458
|
+
customerName?: "John Doe" // If available
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
#### 3. `update_customer_info`
|
|
463
|
+
Emitted when customer submits info form:
|
|
464
|
+
```javascript
|
|
465
|
+
{
|
|
466
|
+
chatId: "uuid-v4-string",
|
|
467
|
+
customerName: "John Doe",
|
|
468
|
+
customerPhone: "+233 24 123 4567",
|
|
469
|
+
customerEmail?: "john@example.com" // If provided
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
### Events Received by Widget:
|
|
476
|
+
|
|
477
|
+
#### 1. `connect`
|
|
478
|
+
Connection established.
|
|
479
|
+
|
|
480
|
+
#### 2. `chat_history`
|
|
481
|
+
Receives previous messages:
|
|
482
|
+
```javascript
|
|
483
|
+
[
|
|
484
|
+
{
|
|
485
|
+
_id: "msg-id",
|
|
486
|
+
text: "Hello!",
|
|
487
|
+
sender: "agent",
|
|
488
|
+
sender_name: "Support Agent",
|
|
489
|
+
createdAt: "2024-01-15T10:30:00Z",
|
|
490
|
+
status: "delivered"
|
|
491
|
+
},
|
|
492
|
+
// ... more messages
|
|
493
|
+
]
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
#### 3. `new_message`
|
|
497
|
+
Receives new message from agent:
|
|
498
|
+
```javascript
|
|
499
|
+
{
|
|
500
|
+
_id: "msg-id",
|
|
501
|
+
text: "How can I help you?",
|
|
502
|
+
sender: "agent",
|
|
503
|
+
sender_name: "Sarah from Support",
|
|
504
|
+
createdAt: "2024-01-15T10:32:00Z",
|
|
505
|
+
status: "delivered",
|
|
506
|
+
file?: {
|
|
507
|
+
url: "https://cdn.example.com/file.pdf",
|
|
508
|
+
name: "Invoice.pdf",
|
|
509
|
+
mime: "application/pdf",
|
|
510
|
+
size: 1024000
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
#### 4. `name_update`
|
|
516
|
+
Confirmation of customer info update:
|
|
517
|
+
```javascript
|
|
518
|
+
"success" // or error message string
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
#### 5. `disconnect`
|
|
522
|
+
Connection lost.
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
### Message Object Schema:
|
|
527
|
+
|
|
528
|
+
```typescript
|
|
529
|
+
interface Message {
|
|
530
|
+
_id: string; // Unique message ID
|
|
531
|
+
text: string; // Message content
|
|
532
|
+
sender: 'user' | 'agent'; // Who sent the message
|
|
533
|
+
sender_name?: string; // Agent name (for agent messages)
|
|
534
|
+
customerName?: string; // Customer name (for user messages)
|
|
535
|
+
createdAt: string; // ISO 8601 timestamp
|
|
536
|
+
status?: 'sent' | 'delivered'; // Message status
|
|
537
|
+
file?: { // Optional file attachment
|
|
538
|
+
url: string; // File URL
|
|
539
|
+
name: string; // File name
|
|
540
|
+
mime?: string; // MIME type
|
|
541
|
+
size?: number; // File size in bytes
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## πΎ AsyncStorage Keys
|
|
549
|
+
|
|
550
|
+
The widget uses these AsyncStorage keys:
|
|
551
|
+
|
|
552
|
+
| Key | Description | Example Value |
|
|
553
|
+
|-----|-------------|---------------|
|
|
554
|
+
| `chatId` | Unique chat session ID | `"a1b2c3d4-e5f6-7890-abcd-ef1234567890"` |
|
|
555
|
+
| `customerName_{chatId}` | Customer name for this chat | `"John Doe"` |
|
|
556
|
+
| `customerPhone_{chatId}` | Customer phone for this chat | `"+233 24 123 4567"` |
|
|
557
|
+
| `customerEmail_{chatId}` | Customer email for this chat | `"john@example.com"` |
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## π§Ή Clearing Chat Data
|
|
562
|
+
|
|
563
|
+
To clear stored chat data (e.g., on logout):
|
|
564
|
+
|
|
565
|
+
```javascript
|
|
566
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
567
|
+
|
|
568
|
+
// Clear all chat data
|
|
569
|
+
const clearChatData = async () => {
|
|
570
|
+
try {
|
|
571
|
+
const chatId = await AsyncStorage.getItem('chatId');
|
|
572
|
+
if (chatId) {
|
|
573
|
+
await AsyncStorage.multiRemove([
|
|
574
|
+
'chatId',
|
|
575
|
+
`customerName_${chatId}`,
|
|
576
|
+
`customerPhone_${chatId}`,
|
|
577
|
+
`customerEmail_${chatId}`,
|
|
578
|
+
]);
|
|
579
|
+
console.log('Chat data cleared');
|
|
580
|
+
}
|
|
581
|
+
} catch (error) {
|
|
582
|
+
console.error('Error clearing chat data:', error);
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
// Use on logout
|
|
587
|
+
const handleLogout = async () => {
|
|
588
|
+
await clearChatData();
|
|
589
|
+
// ... rest of logout logic
|
|
590
|
+
};
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## π Troubleshooting
|
|
596
|
+
|
|
597
|
+
### 1. **Widget not appearing**
|
|
598
|
+
|
|
599
|
+
**Cause:** Widget is positioned off-screen or behind other elements.
|
|
600
|
+
|
|
601
|
+
**Solution:**
|
|
602
|
+
- Ensure parent View has `flex: 1`
|
|
603
|
+
- Try different `position` prop values
|
|
604
|
+
- Check z-index of other components
|
|
605
|
+
|
|
606
|
+
```javascript
|
|
607
|
+
<View style={{ flex: 1 }}> {/* β
flex: 1 required */}
|
|
608
|
+
<YourContent />
|
|
609
|
+
<ChatWidget {...props} />
|
|
610
|
+
</View>
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
### 2. **Form keeps showing**
|
|
616
|
+
|
|
617
|
+
**Cause:** Both `initialCustomerName` and `initialCustomerPhone` not provided.
|
|
618
|
+
|
|
619
|
+
**Solution:** Provide BOTH props to skip form:
|
|
620
|
+
|
|
621
|
+
```javascript
|
|
622
|
+
// β Won't skip form (only one prop)
|
|
623
|
+
<ChatWidget
|
|
624
|
+
apiKey="key"
|
|
625
|
+
organizationId="org"
|
|
626
|
+
initialCustomerName="John"
|
|
627
|
+
/>
|
|
628
|
+
|
|
629
|
+
// β
Skips form (both props)
|
|
630
|
+
<ChatWidget
|
|
631
|
+
apiKey="key"
|
|
632
|
+
organizationId="org"
|
|
633
|
+
initialCustomerName="John"
|
|
634
|
+
initialCustomerPhone="+233241234567"
|
|
635
|
+
/>
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
### 3. **Messages not sending**
|
|
641
|
+
|
|
642
|
+
**Cause:** Not connected to Socket.IO server or server not responding.
|
|
643
|
+
|
|
644
|
+
**Solution:**
|
|
645
|
+
- Check connection status in widget header
|
|
646
|
+
- Verify server is running and accessible
|
|
647
|
+
- Check console logs for connection errors
|
|
648
|
+
- Ensure firewall allows WebSocket connections
|
|
649
|
+
|
|
650
|
+
```javascript
|
|
651
|
+
// Debug logs in console:
|
|
652
|
+
[ChatWidget] Socket connected with ID: abc123...
|
|
653
|
+
[ChatWidget] Emitted join_chat
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
### 4. **TypeScript errors**
|
|
659
|
+
|
|
660
|
+
**Cause:** Missing or outdated type definitions.
|
|
661
|
+
|
|
662
|
+
**Solution:**
|
|
663
|
+
```bash
|
|
664
|
+
# Reinstall package
|
|
665
|
+
npm install rn-kova-live-chat@latest
|
|
666
|
+
|
|
667
|
+
# Or manually add types
|
|
668
|
+
npm install --save-dev @types/rn-kova-live-chat
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## π Security Best Practices
|
|
674
|
+
|
|
675
|
+
### 1. **API Key Storage**
|
|
676
|
+
|
|
677
|
+
Never hardcode API keys in your code:
|
|
678
|
+
|
|
679
|
+
```javascript
|
|
680
|
+
// β Bad - Hardcoded
|
|
681
|
+
<ChatWidget apiKey="sk_live_12345" />
|
|
682
|
+
|
|
683
|
+
// β
Good - Environment variable
|
|
684
|
+
import Config from 'react-native-config';
|
|
685
|
+
<ChatWidget apiKey={Config.CHAT_API_KEY} />
|
|
686
|
+
|
|
687
|
+
// β
Good - Secure storage
|
|
688
|
+
import * as SecureStore from 'expo-secure-store';
|
|
689
|
+
const apiKey = await SecureStore.getItemAsync('chat_api_key');
|
|
690
|
+
<ChatWidget apiKey={apiKey} />
|
|
691
|
+
|
|
692
|
+
// β
Good - From backend
|
|
693
|
+
const apiKey = user.chatCredentials.apiKey;
|
|
694
|
+
<ChatWidget apiKey={apiKey} />
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
---
|
|
698
|
+
|
|
699
|
+
### 2. **User Data**
|
|
700
|
+
|
|
701
|
+
- Never log sensitive user information
|
|
702
|
+
- Use secure storage for credentials
|
|
703
|
+
- Clear data on logout
|
|
704
|
+
- Implement proper authentication
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
### 3. **Network Security**
|
|
709
|
+
|
|
710
|
+
- Always use WSS (WebSocket Secure) in production
|
|
711
|
+
- Validate SSL certificates
|
|
712
|
+
- Implement rate limiting on your server
|
|
713
|
+
- Use HTTPS for all API endpoints
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## π Advanced Usage
|
|
718
|
+
|
|
719
|
+
### Custom Theme Object (Future)
|
|
720
|
+
|
|
721
|
+
The `theme` prop is reserved for future customization:
|
|
722
|
+
|
|
723
|
+
```javascript
|
|
724
|
+
<ChatWidget
|
|
725
|
+
apiKey="key"
|
|
726
|
+
organizationId="org"
|
|
727
|
+
theme={{
|
|
728
|
+
// Future theme options will go here
|
|
729
|
+
fontFamily: 'CustomFont',
|
|
730
|
+
borderRadius: 12,
|
|
731
|
+
// etc.
|
|
732
|
+
}}
|
|
733
|
+
/>
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
---
|
|
737
|
+
|
|
738
|
+
### Multiple Widgets
|
|
739
|
+
|
|
740
|
+
You can render multiple widgets for different purposes:
|
|
741
|
+
|
|
742
|
+
```javascript
|
|
743
|
+
function App() {
|
|
744
|
+
return (
|
|
745
|
+
<View style={{ flex: 1 }}>
|
|
746
|
+
<AppContent />
|
|
747
|
+
|
|
748
|
+
{/* Sales chat */}
|
|
749
|
+
<ChatWidget
|
|
750
|
+
apiKey={Config.SALES_API_KEY}
|
|
751
|
+
organizationId="sales-team"
|
|
752
|
+
primaryColor="#059669"
|
|
753
|
+
position="bottom-right"
|
|
754
|
+
/>
|
|
755
|
+
|
|
756
|
+
{/* Support chat */}
|
|
757
|
+
<ChatWidget
|
|
758
|
+
apiKey={Config.SUPPORT_API_KEY}
|
|
759
|
+
organizationId="support-team"
|
|
760
|
+
primaryColor="#2563EB"
|
|
761
|
+
position="bottom-left"
|
|
762
|
+
/>
|
|
763
|
+
</View>
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
---
|
|
769
|
+
|
|
770
|
+
### Programmatic Control
|
|
771
|
+
|
|
772
|
+
Control widget state from parent component:
|
|
773
|
+
|
|
774
|
+
```javascript
|
|
775
|
+
import React, { useRef } from 'react';
|
|
776
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
777
|
+
|
|
778
|
+
function App() {
|
|
779
|
+
const chatRef = useRef(null);
|
|
780
|
+
|
|
781
|
+
const openChat = () => {
|
|
782
|
+
// Future API (not yet available)
|
|
783
|
+
chatRef.current?.open();
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
return (
|
|
787
|
+
<View style={{ flex: 1 }}>
|
|
788
|
+
<Button title="Open Chat" onPress={openChat} />
|
|
789
|
+
|
|
790
|
+
<ChatWidget
|
|
791
|
+
ref={chatRef}
|
|
792
|
+
apiKey="key"
|
|
793
|
+
organizationId="org"
|
|
794
|
+
/>
|
|
795
|
+
</View>
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
802
|
+
## π¦ Dependencies
|
|
803
|
+
|
|
804
|
+
The widget requires these peer dependencies:
|
|
805
|
+
|
|
806
|
+
| Package | Version | Purpose |
|
|
807
|
+
|---------|---------|---------|
|
|
808
|
+
| `react` | `>=16.8.0` | React framework |
|
|
809
|
+
| `react-native` | `>=0.60.0` | React Native framework |
|
|
810
|
+
| `socket.io-client` | `>=4.5.0` | Real-time communication |
|
|
811
|
+
| `@react-native-async-storage/async-storage` | `>=1.17.0` | Data persistence |
|
|
812
|
+
| `moment` | `>=2.29.0` | Date/time formatting |
|
|
813
|
+
|
|
814
|
+
All dependencies are installed automatically with the package.
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
## π Platform Support
|
|
819
|
+
|
|
820
|
+
| Platform | Support | Notes |
|
|
821
|
+
|----------|---------|-------|
|
|
822
|
+
| iOS | β
Full | iOS 11+ |
|
|
823
|
+
| Android | β
Full | Android 5.0+ (API 21+) |
|
|
824
|
+
| Expo Go | β
Full | No native code required |
|
|
825
|
+
| Web | β οΈ Partial | Works but not optimized |
|
|
826
|
+
|
|
827
|
+
---
|
|
828
|
+
|
|
829
|
+
## π§ͺ Testing
|
|
830
|
+
|
|
831
|
+
### Test Basic Integration:
|
|
832
|
+
|
|
833
|
+
```javascript
|
|
834
|
+
import React from 'react';
|
|
835
|
+
import { render } from '@testing-library/react-native';
|
|
836
|
+
import ChatWidget from 'rn-kova-live-chat';
|
|
837
|
+
|
|
838
|
+
describe('ChatWidget', () => {
|
|
839
|
+
it('renders without crashing', () => {
|
|
840
|
+
const { getByText } = render(
|
|
841
|
+
<ChatWidget
|
|
842
|
+
apiKey="test-key"
|
|
843
|
+
organizationId="test-org"
|
|
844
|
+
/>
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
expect(getByText).toBeDefined();
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
## π Performance
|
|
855
|
+
|
|
856
|
+
The widget is optimized for performance:
|
|
857
|
+
|
|
858
|
+
- **Bundle size:** ~7.8KB (minified + gzipped)
|
|
859
|
+
- **Dependencies:** Only peer dependencies required
|
|
860
|
+
- **Memory:** Minimal footprint (~2-5MB)
|
|
861
|
+
- **Native modules:** Zero (pure JavaScript)
|
|
862
|
+
- **Render performance:** 60 FPS animations
|
|
863
|
+
|
|
864
|
+
---
|
|
865
|
+
|
|
866
|
+
## π Migration Guide
|
|
867
|
+
|
|
868
|
+
### From v1.0.x to v1.1.x:
|
|
869
|
+
|
|
870
|
+
**Breaking Changes:** None! Version 1.1.x simplifies the API by moving backend configuration internal.
|
|
871
|
+
|
|
872
|
+
**Old code (still works):**
|
|
873
|
+
```javascript
|
|
874
|
+
<ChatWidget
|
|
875
|
+
apiKey="key"
|
|
876
|
+
organizationId="org"
|
|
877
|
+
webSocketUrl="wss://server.com" // Ignored in v1.1.x
|
|
878
|
+
cdnBaseUrl="https://cdn.com" // Ignored in v1.1.x
|
|
879
|
+
crmWebsiteUrl="https://crm.com" // Ignored in v1.1.x
|
|
880
|
+
/>
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
**New code (recommended):**
|
|
884
|
+
```javascript
|
|
885
|
+
<ChatWidget
|
|
886
|
+
apiKey="key"
|
|
887
|
+
organizationId="org"
|
|
888
|
+
// Backend URLs are now internal - no need to provide!
|
|
889
|
+
/>
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
---
|
|
893
|
+
|
|
894
|
+
## πΊοΈ Roadmap
|
|
895
|
+
|
|
896
|
+
Upcoming features:
|
|
897
|
+
|
|
898
|
+
- [ ] Voice message support
|
|
899
|
+
- [ ] Image/video upload
|
|
900
|
+
- [ ] Push notifications
|
|
901
|
+
- [ ] Typing indicators
|
|
902
|
+
- [ ] Read receipts
|
|
903
|
+
- [ ] Message reactions
|
|
904
|
+
- [ ] File upload from device
|
|
905
|
+
- [ ] Chat history export
|
|
906
|
+
- [ ] Custom message templates
|
|
907
|
+
- [ ] Multi-language support
|
|
908
|
+
|
|
909
|
+
---
|
|
910
|
+
|
|
911
|
+
## π€ Contributing
|
|
912
|
+
|
|
913
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
914
|
+
|
|
915
|
+
### Development Setup:
|
|
916
|
+
|
|
917
|
+
```bash
|
|
918
|
+
# Clone the repository
|
|
919
|
+
git clone https://github.com/yourusername/rn-kova-live-chat.git
|
|
920
|
+
cd rn-kova-live-chat
|
|
921
|
+
|
|
922
|
+
# Install dependencies
|
|
923
|
+
npm install
|
|
924
|
+
|
|
925
|
+
# Run tests
|
|
926
|
+
npm test
|
|
927
|
+
|
|
928
|
+
# Build package
|
|
929
|
+
npm run build
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
---
|
|
933
|
+
|
|
934
|
+
## π License
|
|
935
|
+
|
|
936
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
937
|
+
|
|
938
|
+
---
|
|
939
|
+
|
|
940
|
+
## π Support
|
|
941
|
+
|
|
942
|
+
- **GitHub Issues:** [Report bugs or request features](https://github.com/yourusername/rn-kova-live-chat/issues)
|
|
943
|
+
- **Documentation:** [Full API documentation](https://github.com/yourusername/rn-kova-live-chat/wiki)
|
|
944
|
+
- **Stack Overflow:** Tag questions with `rn-kova-live-chat`
|
|
945
|
+
|
|
946
|
+
---
|
|
947
|
+
|
|
948
|
+
## π Changelog
|
|
949
|
+
|
|
950
|
+
### v1.1.0 (2024-01-15)
|
|
951
|
+
- β¨ Simplified API - only 2 required props
|
|
952
|
+
- β¨ Backend URLs now internal (no configuration needed)
|
|
953
|
+
- π Fixed message display with optimistic updates
|
|
954
|
+
- π Fixed 30-second alert timer
|
|
955
|
+
- π Fixed customer form visibility
|
|
956
|
+
- π Removed crypto dependency (UUID generator)
|
|
957
|
+
|
|
958
|
+
### v1.0.0 (2024-01-10)
|
|
959
|
+
- π Initial release
|
|
960
|
+
- β
Real-time messaging
|
|
961
|
+
- β
Customer info collection
|
|
962
|
+
- β
6 position options
|
|
963
|
+
- β
Color customization
|
|
964
|
+
- β
Emoji picker
|
|
965
|
+
- β
File attachments
|
|
966
|
+
- β
TypeScript support
|
|
967
|
+
|
|
968
|
+
---
|
|
969
|
+
|
|
970
|
+
## β Show Your Support
|
|
971
|
+
|
|
972
|
+
If you find this package helpful, please give it a β on [GitHub](https://github.com/yourusername/rn-kova-live-chat)!
|
|
973
|
+
|
|
974
|
+
---
|
|
975
|
+
|
|
976
|
+
## π¨βπ» Author
|
|
977
|
+
|
|
978
|
+
**Your Name**
|
|
979
|
+
- GitHub: [@yourusername](https://github.com/yourusername)
|
|
980
|
+
- Email: your.email@example.com
|
|
981
|
+
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
## π Acknowledgments
|
|
985
|
+
|
|
986
|
+
Built with:
|
|
987
|
+
- [Socket.IO](https://socket.io/) - Real-time communication
|
|
988
|
+
- [React Native](https://reactnative.dev/) - Mobile framework
|
|
989
|
+
- [AsyncStorage](https://react-native-async-storage.github.io/async-storage/) - Data persistence
|
|
990
|
+
- [Moment.js](https://momentjs.com/) - Date/time handling
|
|
991
|
+
|
|
992
|
+
---
|
|
993
|
+
|
|
994
|
+
**Made with β€οΈ for the React Native community**
|