call-control-sdk 5.3.3 → 5.3.4
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/README.md +266 -1179
- package/dist/index.d.mts +12 -21
- package/dist/index.d.ts +12 -21
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,1179 +1,266 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
```tsx
|
|
268
|
-
import { useEndCall } from 'call-control-sdk';
|
|
269
|
-
|
|
270
|
-
function EndCallComponent() {
|
|
271
|
-
const { handleEndCall, isLoading } = useEndCall();
|
|
272
|
-
|
|
273
|
-
const endCall = () => {
|
|
274
|
-
handleEndCall({
|
|
275
|
-
disposition: "RES",
|
|
276
|
-
followUp: "N",
|
|
277
|
-
callbackDate: "",
|
|
278
|
-
callbackHrs: "",
|
|
279
|
-
callbackMins: ""
|
|
280
|
-
});
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
return (
|
|
284
|
-
<button onClick={endCall} disabled={isLoading}>
|
|
285
|
-
End Call
|
|
286
|
-
</button>
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
### 4. useLogout
|
|
292
|
-
|
|
293
|
-
Handles agent logout functionality.
|
|
294
|
-
|
|
295
|
-
```tsx
|
|
296
|
-
import { useLogout } from 'call-control-sdk';
|
|
297
|
-
|
|
298
|
-
function LogoutComponent() {
|
|
299
|
-
const { logout, isLoading } = useLogout();
|
|
300
|
-
|
|
301
|
-
return (
|
|
302
|
-
<button onClick={logout} disabled={isLoading}>
|
|
303
|
-
{isLoading ? 'Logging out...' : 'Logout'}
|
|
304
|
-
</button>
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### 5. useDraggable
|
|
310
|
-
|
|
311
|
-
Provides drag-and-drop functionality for UI elements.
|
|
312
|
-
|
|
313
|
-
```tsx
|
|
314
|
-
import { useDraggable } from 'call-control-sdk';
|
|
315
|
-
|
|
316
|
-
function DraggablePanel() {
|
|
317
|
-
const { position, isDragging, dragRef, handleMouseDown, handleTouchStart } =
|
|
318
|
-
useDraggable({ x: 100, y: 100 }, (newPosition) => {
|
|
319
|
-
console.log('Moved to:', newPosition);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
return (
|
|
323
|
-
<div
|
|
324
|
-
ref={dragRef}
|
|
325
|
-
onMouseDown={handleMouseDown}
|
|
326
|
-
onTouchStart={handleTouchStart}
|
|
327
|
-
style={{
|
|
328
|
-
position: 'fixed',
|
|
329
|
-
left: position.x,
|
|
330
|
-
top: position.y,
|
|
331
|
-
cursor: isDragging ? 'grabbing' : 'grab'
|
|
332
|
-
}}
|
|
333
|
-
>
|
|
334
|
-
Drag me
|
|
335
|
-
</div>
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
---
|
|
341
|
-
|
|
342
|
-
## Services & APIs
|
|
343
|
-
|
|
344
|
-
### 1. HTTP Client (axios.ts)
|
|
345
|
-
|
|
346
|
-
Configured Axios instance with:
|
|
347
|
-
- Base URL configuration
|
|
348
|
-
- Authorization headers
|
|
349
|
-
- Request/response interceptors
|
|
350
|
-
- Error handling
|
|
351
|
-
- Retry logic for 401 errors
|
|
352
|
-
|
|
353
|
-
```tsx
|
|
354
|
-
// Automatic token injection
|
|
355
|
-
axiosInstance.interceptors.request.use((config) => {
|
|
356
|
-
const token = getAuthToken();
|
|
357
|
-
if (token && config.headers) {
|
|
358
|
-
config.headers.Authorization = `Bearer ${token}`;
|
|
359
|
-
}
|
|
360
|
-
return config;
|
|
361
|
-
});
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### 2. API Request Hooks (request.ts)
|
|
365
|
-
|
|
366
|
-
Custom hooks for different HTTP methods:
|
|
367
|
-
|
|
368
|
-
#### useGetRequest
|
|
369
|
-
```tsx
|
|
370
|
-
const [getData, { isLoading, isSuccess, error, data }] = useGetRequest<User>({
|
|
371
|
-
onSuccess: (response) => console.log('Success:', response),
|
|
372
|
-
onError: (error) => console.error('Error:', error)
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
// Usage
|
|
376
|
-
getData('/api/users');
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
#### usePostRequest
|
|
380
|
-
```tsx
|
|
381
|
-
const [createUser, { isLoading, isSuccess, error }] = usePostRequest<User>({
|
|
382
|
-
onSuccess: (response) => console.log('User created:', response)
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
// Usage
|
|
386
|
-
createUser('/api/users', userData);
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
### 3. API Endpoints (endPoint.ts)
|
|
390
|
-
|
|
391
|
-
Centralized endpoint configuration:
|
|
392
|
-
|
|
393
|
-
```tsx
|
|
394
|
-
export const END_POINT = {
|
|
395
|
-
LOGIN: `${BASE_URL}/api/v1/cti/login?provider=convox`,
|
|
396
|
-
READY_AGENT: `${BASE_URL}/api/v1/cti/ready-agent?provider=convox`,
|
|
397
|
-
CLICK_TO_CALL: `${BASE_URL}/api/v1/cti/calls?provider=convox`,
|
|
398
|
-
HOLD_CALL: `${BASE_URL}/api/v1/cti/calls/hold?provider=convox`,
|
|
399
|
-
MUTE_CALL: `${BASE_URL}/api/v1/cti/calls/mute?provider=convox`,
|
|
400
|
-
END_CALL: `${BASE_URL}/api/v1/cti/calls/end?provider=convox`,
|
|
401
|
-
CONFERENCE_CALL: `${BASE_URL}/api/v1/cti/calls/conference?provider=convox`,
|
|
402
|
-
TRANSFER_CALL: `${BASE_URL}/api/v1/cti/calls/transfer?provider=convox`,
|
|
403
|
-
// ... more endpoints
|
|
404
|
-
};
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
### 4. WebSocket Integration
|
|
408
|
-
|
|
409
|
-
Real-time communication for call events:
|
|
410
|
-
|
|
411
|
-
```tsx
|
|
412
|
-
// WebSocket connection setup
|
|
413
|
-
useEffect(() => {
|
|
414
|
-
if (state.agentId) {
|
|
415
|
-
const ws = new WebSocket(`${WS_END_POINT.WS}?agent_id=${state.agentId}`);
|
|
416
|
-
|
|
417
|
-
ws.onmessage = (event) => {
|
|
418
|
-
const data = JSON.parse(event.data);
|
|
419
|
-
sdkStateManager.updateCallData(data);
|
|
420
|
-
|
|
421
|
-
if (data.status === "ONCALL") {
|
|
422
|
-
sdkStateManager.startCall();
|
|
423
|
-
}
|
|
424
|
-
if (data.status === "WRAPUP") {
|
|
425
|
-
sdkStateManager.endCall();
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
return () => ws.close();
|
|
430
|
-
}
|
|
431
|
-
}, [state.agentId]);
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
---
|
|
435
|
-
|
|
436
|
-
## TypeScript Types
|
|
437
|
-
|
|
438
|
-
### Core Types
|
|
439
|
-
|
|
440
|
-
```tsx
|
|
441
|
-
// Call data structure
|
|
442
|
-
interface CallData {
|
|
443
|
-
mobileNumber?: string;
|
|
444
|
-
callReferenceId?: string;
|
|
445
|
-
convoxId?: string;
|
|
446
|
-
type?: string;
|
|
447
|
-
status?: string;
|
|
448
|
-
agent_id?: string;
|
|
449
|
-
phone_number?: string;
|
|
450
|
-
event_time?: string;
|
|
451
|
-
convox_id?: string;
|
|
452
|
-
process_id?: string;
|
|
453
|
-
process_name?: string;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Agent status types
|
|
457
|
-
type CallStatus =
|
|
458
|
-
| "idle"
|
|
459
|
-
| "ready"
|
|
460
|
-
| "break"
|
|
461
|
-
| "on call"
|
|
462
|
-
| "wrap up"
|
|
463
|
-
| "dial"
|
|
464
|
-
| "hold"
|
|
465
|
-
| "mute";
|
|
466
|
-
|
|
467
|
-
// Conference line configuration
|
|
468
|
-
type ConferenceLineTypes = {
|
|
469
|
-
line: number;
|
|
470
|
-
status: string;
|
|
471
|
-
type: "external" | "internal" | "";
|
|
472
|
-
phone: string;
|
|
473
|
-
isMute: boolean;
|
|
474
|
-
isHold: boolean;
|
|
475
|
-
isCallStart: boolean;
|
|
476
|
-
isMergeCall: boolean;
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
// SDK state interface
|
|
480
|
-
interface SDKState {
|
|
481
|
-
apiKey: string | null;
|
|
482
|
-
process?: { process_id: number; process_name: string } | null;
|
|
483
|
-
agentId: string;
|
|
484
|
-
isInitialized: boolean;
|
|
485
|
-
isHolding: boolean;
|
|
486
|
-
isMuted: boolean;
|
|
487
|
-
status: CallStatus;
|
|
488
|
-
convox_id?: string;
|
|
489
|
-
process_id?: number;
|
|
490
|
-
callStartTime: number | null;
|
|
491
|
-
position?: { x: number; y: number };
|
|
492
|
-
controlPanelPosition: { x: number; y: number };
|
|
493
|
-
iframePosition: { x: number; y: number };
|
|
494
|
-
callData: CallData;
|
|
495
|
-
conferenceLine: ConferenceLineTypes[];
|
|
496
|
-
}
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
### API Request Types
|
|
500
|
-
|
|
501
|
-
```tsx
|
|
502
|
-
// Request result interface
|
|
503
|
-
interface RequestResult<T> {
|
|
504
|
-
isLoading: boolean;
|
|
505
|
-
isSuccess: boolean;
|
|
506
|
-
isError: boolean;
|
|
507
|
-
error: AxiosError | null;
|
|
508
|
-
data: AxiosResponse<T> | null;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Request options
|
|
512
|
-
interface RequestOptions {
|
|
513
|
-
onSuccess?: (response: AxiosResponse, request: any) => void;
|
|
514
|
-
onError?: (error: any, request: any) => void;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// Hook signatures
|
|
518
|
-
type UseGetRequest<T = UseApiRequest> = [
|
|
519
|
-
(url: string, config?: AxiosRequestConfig) => void,
|
|
520
|
-
RequestResult<T>
|
|
521
|
-
];
|
|
522
|
-
|
|
523
|
-
type UsePostRequest<T = UseApiRequest> = [
|
|
524
|
-
(url: string, payload: T, config?: AxiosRequestConfig) => void,
|
|
525
|
-
RequestResult<T>
|
|
526
|
-
];
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
---
|
|
530
|
-
|
|
531
|
-
## Usage Examples
|
|
532
|
-
|
|
533
|
-
### 1. Complete Agent Dashboard
|
|
534
|
-
|
|
535
|
-
```tsx
|
|
536
|
-
import React, { useEffect, useState } from 'react';
|
|
537
|
-
import {
|
|
538
|
-
initSDK,
|
|
539
|
-
CallControlPanel,
|
|
540
|
-
useClickToCall,
|
|
541
|
-
useEndCall,
|
|
542
|
-
useLogout
|
|
543
|
-
} from 'call-control-sdk';
|
|
544
|
-
|
|
545
|
-
function AgentDashboard() {
|
|
546
|
-
const [callData, setCallData] = useState(null);
|
|
547
|
-
|
|
548
|
-
// Initialize SDK
|
|
549
|
-
useEffect(() => {
|
|
550
|
-
initSDK({
|
|
551
|
-
apiKey: process.env.REACT_APP_API_KEY,
|
|
552
|
-
tenantId: process.env.REACT_APP_TENANT_ID,
|
|
553
|
-
agentId: process.env.REACT_APP_AGENT_ID
|
|
554
|
-
});
|
|
555
|
-
}, []);
|
|
556
|
-
|
|
557
|
-
// Call management hooks
|
|
558
|
-
const { handleStartCall, isLoading: calling } = useClickToCall();
|
|
559
|
-
const { handleEndCall, isLoading: ending } = useEndCall();
|
|
560
|
-
const { logout, isLoading: loggingOut } = useLogout();
|
|
561
|
-
|
|
562
|
-
const handleCallDataChange = (data) => {
|
|
563
|
-
setCallData(data);
|
|
564
|
-
// Update dashboard metrics
|
|
565
|
-
updateDashboardMetrics(data);
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
return (
|
|
569
|
-
<div className="agent-dashboard">
|
|
570
|
-
<header className="dashboard-header">
|
|
571
|
-
<h1>Agent Dashboard</h1>
|
|
572
|
-
<button onClick={logout} disabled={loggingOut}>
|
|
573
|
-
{loggingOut ? 'Logging out...' : 'Logout'}
|
|
574
|
-
</button>
|
|
575
|
-
</header>
|
|
576
|
-
|
|
577
|
-
<main className="dashboard-content">
|
|
578
|
-
<div className="call-controls">
|
|
579
|
-
<CallControlPanel onDataChange={handleCallDataChange} />
|
|
580
|
-
</div>
|
|
581
|
-
|
|
582
|
-
<div className="dashboard-widgets">
|
|
583
|
-
<CallMetricsWidget data={callData} />
|
|
584
|
-
<CustomerInfoWidget data={callData} />
|
|
585
|
-
<CallHistoryWidget />
|
|
586
|
-
</div>
|
|
587
|
-
</main>
|
|
588
|
-
</div>
|
|
589
|
-
);
|
|
590
|
-
}
|
|
591
|
-
```
|
|
592
|
-
|
|
593
|
-
### 2. Custom Call Controls
|
|
594
|
-
|
|
595
|
-
```tsx
|
|
596
|
-
import React from 'react';
|
|
597
|
-
import { useSDKState, useClickToCall, useEndCall } from 'call-control-sdk';
|
|
598
|
-
|
|
599
|
-
function CustomCallControls() {
|
|
600
|
-
const state = useSDKState();
|
|
601
|
-
const { handleStartCall } = useClickToCall();
|
|
602
|
-
const { handleEndCall } = useEndCall();
|
|
603
|
-
|
|
604
|
-
const isOnCall = state.callData?.status === "ONCALL";
|
|
605
|
-
const callDuration = state.callStartTime
|
|
606
|
-
? Math.floor((Date.now() - state.callStartTime) / 1000)
|
|
607
|
-
: 0;
|
|
608
|
-
|
|
609
|
-
const formatDuration = (seconds) => {
|
|
610
|
-
const mins = Math.floor(seconds / 60);
|
|
611
|
-
const secs = seconds % 60;
|
|
612
|
-
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
return (
|
|
616
|
-
<div className="custom-controls">
|
|
617
|
-
<div className="call-status">
|
|
618
|
-
<span className="status">{state.status}</span>
|
|
619
|
-
{isOnCall && (
|
|
620
|
-
<span className="duration">{formatDuration(callDuration)}</span>
|
|
621
|
-
)}
|
|
622
|
-
</div>
|
|
623
|
-
|
|
624
|
-
<div className="control-buttons">
|
|
625
|
-
{!isOnCall && (
|
|
626
|
-
<button onClick={() => handleStartCall({ mobileNumber: "1234567890" })}>
|
|
627
|
-
Start Call
|
|
628
|
-
</button>
|
|
629
|
-
)}
|
|
630
|
-
|
|
631
|
-
{isOnCall && (
|
|
632
|
-
<>
|
|
633
|
-
<button
|
|
634
|
-
onClick={() => handleEndCall({ disposition: "RES" })}
|
|
635
|
-
className="end-call"
|
|
636
|
-
>
|
|
637
|
-
End Call
|
|
638
|
-
</button>
|
|
639
|
-
</>
|
|
640
|
-
)}
|
|
641
|
-
</div>
|
|
642
|
-
</div>
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
### 3. Conference Call Management
|
|
648
|
-
|
|
649
|
-
```tsx
|
|
650
|
-
import React, { useState } from 'react';
|
|
651
|
-
import { useSDKState } from 'call-control-sdk';
|
|
652
|
-
|
|
653
|
-
function ConferenceManager() {
|
|
654
|
-
const state = useSDKState();
|
|
655
|
-
const [showConference, setShowConference] = useState(false);
|
|
656
|
-
|
|
657
|
-
const addParticipant = (phoneNumber) => {
|
|
658
|
-
// Find available conference line
|
|
659
|
-
const availableLine = state.conferenceLine.find(
|
|
660
|
-
line => line.line !== 1 && line.status === "IDLE"
|
|
661
|
-
);
|
|
662
|
-
|
|
663
|
-
if (availableLine) {
|
|
664
|
-
// Initiate conference call
|
|
665
|
-
handleConferenceCall(availableLine.line, phoneNumber);
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
|
|
669
|
-
return (
|
|
670
|
-
<div className="conference-manager">
|
|
671
|
-
<button onClick={() => setShowConference(true)}>
|
|
672
|
-
Manage Conference
|
|
673
|
-
</button>
|
|
674
|
-
|
|
675
|
-
{showConference && (
|
|
676
|
-
<div className="conference-dialog">
|
|
677
|
-
<h3>Conference Lines</h3>
|
|
678
|
-
{state.conferenceLine.map(line => (
|
|
679
|
-
<div key={line.line} className="conference-line">
|
|
680
|
-
<span>Line {line.line}: {line.status}</span>
|
|
681
|
-
{line.line !== 1 && (
|
|
682
|
-
<input
|
|
683
|
-
placeholder="Phone number"
|
|
684
|
-
onBlur={(e) => addParticipant(e.target.value)}
|
|
685
|
-
/>
|
|
686
|
-
)}
|
|
687
|
-
</div>
|
|
688
|
-
))}
|
|
689
|
-
</div>
|
|
690
|
-
)}
|
|
691
|
-
</div>
|
|
692
|
-
);
|
|
693
|
-
}
|
|
694
|
-
```
|
|
695
|
-
|
|
696
|
-
---
|
|
697
|
-
|
|
698
|
-
## Best Practices
|
|
699
|
-
|
|
700
|
-
### 1. Initialization
|
|
701
|
-
|
|
702
|
-
```tsx
|
|
703
|
-
// ✅ Good: Initialize SDK early in app lifecycle
|
|
704
|
-
function App() {
|
|
705
|
-
useEffect(() => {
|
|
706
|
-
try {
|
|
707
|
-
initSDK({
|
|
708
|
-
apiKey: process.env.REACT_APP_API_KEY,
|
|
709
|
-
tenantId: process.env.REACT_APP_TENANT_ID,
|
|
710
|
-
agentId: process.env.REACT_APP_AGENT_ID
|
|
711
|
-
});
|
|
712
|
-
} catch (error) {
|
|
713
|
-
console.error('SDK initialization failed:', error);
|
|
714
|
-
// Handle initialization error
|
|
715
|
-
}
|
|
716
|
-
}, []);
|
|
717
|
-
|
|
718
|
-
return <YourApp />;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
// ❌ Bad: Initializing in component that might unmount
|
|
722
|
-
function SomeComponent() {
|
|
723
|
-
useEffect(() => {
|
|
724
|
-
initSDK(config); // This might be called multiple times
|
|
725
|
-
}, []);
|
|
726
|
-
}
|
|
727
|
-
```
|
|
728
|
-
|
|
729
|
-
### 2. State Management
|
|
730
|
-
|
|
731
|
-
```tsx
|
|
732
|
-
// ✅ Good: Use the provided state hook
|
|
733
|
-
function MyComponent() {
|
|
734
|
-
const state = useSDKState();
|
|
735
|
-
|
|
736
|
-
return (
|
|
737
|
-
<div>
|
|
738
|
-
<p>Status: {state.status}</p>
|
|
739
|
-
<p>Call Duration: {state.callStartTime}</p>
|
|
740
|
-
</div>
|
|
741
|
-
);
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
// ❌ Bad: Direct state access
|
|
745
|
-
function MyComponent() {
|
|
746
|
-
const state = sdkStateManager.getState(); // Won't trigger re-renders
|
|
747
|
-
return <div>{state.status}</div>;
|
|
748
|
-
}
|
|
749
|
-
```
|
|
750
|
-
|
|
751
|
-
### 3. Error Handling
|
|
752
|
-
|
|
753
|
-
```tsx
|
|
754
|
-
// ✅ Good: Comprehensive error handling
|
|
755
|
-
function CallComponent() {
|
|
756
|
-
const { handleStartCall, isLoading, isError, error } = useClickToCall();
|
|
757
|
-
|
|
758
|
-
const makeCall = async () => {
|
|
759
|
-
try {
|
|
760
|
-
await handleStartCall({ mobileNumber: "1234567890" });
|
|
761
|
-
} catch (error) {
|
|
762
|
-
console.error('Call failed:', error);
|
|
763
|
-
// Show user-friendly error message
|
|
764
|
-
showNotification('Call failed. Please try again.');
|
|
765
|
-
}
|
|
766
|
-
};
|
|
767
|
-
|
|
768
|
-
return (
|
|
769
|
-
<div>
|
|
770
|
-
<button onClick={makeCall} disabled={isLoading}>
|
|
771
|
-
{isLoading ? 'Calling...' : 'Call'}
|
|
772
|
-
</button>
|
|
773
|
-
{isError && <p className="error">Error: {error?.message}</p>}
|
|
774
|
-
</div>
|
|
775
|
-
);
|
|
776
|
-
}
|
|
777
|
-
```
|
|
778
|
-
|
|
779
|
-
### 4. Performance Optimization
|
|
780
|
-
|
|
781
|
-
```tsx
|
|
782
|
-
// ✅ Good: Memoize expensive operations
|
|
783
|
-
function CallMetrics({ callData }) {
|
|
784
|
-
const formattedDuration = useMemo(() => {
|
|
785
|
-
if (!callData?.startTime) return '00:00';
|
|
786
|
-
const duration = Date.now() - callData.startTime;
|
|
787
|
-
return formatDuration(duration);
|
|
788
|
-
}, [callData?.startTime]);
|
|
789
|
-
|
|
790
|
-
return <div>Duration: {formattedDuration}</div>;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// ✅ Good: Debounce user input
|
|
794
|
-
function PhoneInput() {
|
|
795
|
-
const [phoneNumber, setPhoneNumber] = useState('');
|
|
796
|
-
const debouncedPhone = useDebounce(phoneNumber, 500);
|
|
797
|
-
|
|
798
|
-
useEffect(() => {
|
|
799
|
-
if (debouncedPhone.length === 10) {
|
|
800
|
-
validatePhoneNumber(debouncedPhone);
|
|
801
|
-
}
|
|
802
|
-
}, [debouncedPhone]);
|
|
803
|
-
}
|
|
804
|
-
```
|
|
805
|
-
|
|
806
|
-
### 5. Accessibility
|
|
807
|
-
|
|
808
|
-
```tsx
|
|
809
|
-
// ✅ Good: Accessible controls
|
|
810
|
-
function AccessibleCallControls() {
|
|
811
|
-
const state = useSDKState();
|
|
812
|
-
|
|
813
|
-
return (
|
|
814
|
-
<div role="toolbar" aria-label="Call controls">
|
|
815
|
-
<button
|
|
816
|
-
onClick={handleMute}
|
|
817
|
-
aria-pressed={state.isMuted}
|
|
818
|
-
aria-label={state.isMuted ? 'Unmute microphone' : 'Mute microphone'}
|
|
819
|
-
>
|
|
820
|
-
{state.isMuted ? <MicOffIcon /> : <MicIcon />}
|
|
821
|
-
</button>
|
|
822
|
-
|
|
823
|
-
<button
|
|
824
|
-
onClick={handleHold}
|
|
825
|
-
aria-pressed={state.isHolding}
|
|
826
|
-
aria-label={state.isHolding ? 'Resume call' : 'Hold call'}
|
|
827
|
-
>
|
|
828
|
-
{state.isHolding ? <PlayIcon /> : <PauseIcon />}
|
|
829
|
-
</button>
|
|
830
|
-
</div>
|
|
831
|
-
);
|
|
832
|
-
}
|
|
833
|
-
```
|
|
834
|
-
|
|
835
|
-
---
|
|
836
|
-
|
|
837
|
-
## API Reference
|
|
838
|
-
|
|
839
|
-
### Core Functions
|
|
840
|
-
|
|
841
|
-
#### `initSDK(config: InitSDKParams): void`
|
|
842
|
-
|
|
843
|
-
Initializes the Call Control SDK.
|
|
844
|
-
|
|
845
|
-
**Parameters:**
|
|
846
|
-
- `config.apiKey` (string, required): API key for authentication
|
|
847
|
-
- `config.tenantId` (string, required): Tenant ID for events/authentication
|
|
848
|
-
- `config.agentId` (string, required): Agent ID for call controls
|
|
849
|
-
|
|
850
|
-
**Example:**
|
|
851
|
-
```tsx
|
|
852
|
-
initSDK({
|
|
853
|
-
apiKey: "your-api-key",
|
|
854
|
-
tenantId: "tenant-123",
|
|
855
|
-
agentId: "agent-456"
|
|
856
|
-
});
|
|
857
|
-
```
|
|
858
|
-
|
|
859
|
-
#### `CallControlPanel`
|
|
860
|
-
|
|
861
|
-
React component that renders the draggable call control interface.
|
|
862
|
-
|
|
863
|
-
**Props:**
|
|
864
|
-
- `onDataChange?: (data: CallData) => void`: Callback fired when call data changes
|
|
865
|
-
|
|
866
|
-
**Example:**
|
|
867
|
-
```tsx
|
|
868
|
-
<CallControlPanel
|
|
869
|
-
onDataChange={(data) => {
|
|
870
|
-
console.log('Call updated:', data);
|
|
871
|
-
}}
|
|
872
|
-
/>
|
|
873
|
-
```
|
|
874
|
-
|
|
875
|
-
### Hooks
|
|
876
|
-
|
|
877
|
-
#### `useSDKState(): SDKState`
|
|
878
|
-
|
|
879
|
-
Returns the current SDK state with reactive updates.
|
|
880
|
-
|
|
881
|
-
**Returns:** `SDKState` object containing:
|
|
882
|
-
- `isInitialized`: boolean
|
|
883
|
-
- `status`: CallStatus
|
|
884
|
-
- `isHolding`: boolean
|
|
885
|
-
- `isMuted`: boolean
|
|
886
|
-
- `callData`: CallData
|
|
887
|
-
- `conferenceLine`: ConferenceLineTypes[]
|
|
888
|
-
- And more...
|
|
889
|
-
|
|
890
|
-
#### `useClickToCall()`
|
|
891
|
-
|
|
892
|
-
Hook for initiating outbound calls.
|
|
893
|
-
|
|
894
|
-
**Returns:**
|
|
895
|
-
- `handleStartCall`: (payload: StartCallPayload) => Promise<void>
|
|
896
|
-
- `isLoading`: boolean
|
|
897
|
-
- `isSuccess`: boolean
|
|
898
|
-
- `isError`: boolean
|
|
899
|
-
- `error`: any
|
|
900
|
-
- `data`: any
|
|
901
|
-
|
|
902
|
-
#### `useEndCall()`
|
|
903
|
-
|
|
904
|
-
Hook for ending active calls.
|
|
905
|
-
|
|
906
|
-
**Returns:**
|
|
907
|
-
- `handleEndCall`: (data: EndCallData) => Promise<void>
|
|
908
|
-
- `isLoading`: boolean
|
|
909
|
-
- `isSuccess`: boolean
|
|
910
|
-
- `isError`: boolean
|
|
911
|
-
- `error`: any
|
|
912
|
-
- `data`: any
|
|
913
|
-
|
|
914
|
-
#### `useLogout()`
|
|
915
|
-
|
|
916
|
-
Hook for agent logout functionality.
|
|
917
|
-
|
|
918
|
-
**Returns:**
|
|
919
|
-
- `logout`: () => Promise<void>
|
|
920
|
-
- `isLoading`: boolean
|
|
921
|
-
- `isSuccess`: boolean
|
|
922
|
-
- `isError`: boolean
|
|
923
|
-
- `error`: any
|
|
924
|
-
- `data`: any
|
|
925
|
-
|
|
926
|
-
---
|
|
927
|
-
|
|
928
|
-
## Troubleshooting
|
|
929
|
-
|
|
930
|
-
### Common Issues
|
|
931
|
-
|
|
932
|
-
#### 1. SDK Not Initializing
|
|
933
|
-
|
|
934
|
-
**Problem:** SDK fails to initialize
|
|
935
|
-
**Solution:**
|
|
936
|
-
```tsx
|
|
937
|
-
// Check if all required parameters are provided
|
|
938
|
-
try {
|
|
939
|
-
initSDK({
|
|
940
|
-
apiKey: "valid-api-key", // Ensure this is not empty
|
|
941
|
-
tenantId: "valid-tenant-id", // Ensure this is not empty
|
|
942
|
-
agentId: "valid-agent-id" // Ensure this is not empty
|
|
943
|
-
});
|
|
944
|
-
} catch (error) {
|
|
945
|
-
console.error('SDK initialization failed:', error);
|
|
946
|
-
}
|
|
947
|
-
```
|
|
948
|
-
|
|
949
|
-
#### 2. State Not Updating
|
|
950
|
-
|
|
951
|
-
**Problem:** Components not re-rendering when state changes
|
|
952
|
-
**Solution:**
|
|
953
|
-
```tsx
|
|
954
|
-
// ✅ Use the hook, not direct state access
|
|
955
|
-
function MyComponent() {
|
|
956
|
-
const state = useSDKState(); // This will trigger re-renders
|
|
957
|
-
|
|
958
|
-
// ❌ Don't do this
|
|
959
|
-
// const state = sdkStateManager.getState();
|
|
960
|
-
}
|
|
961
|
-
```
|
|
962
|
-
|
|
963
|
-
#### 3. WebSocket Connection Issues
|
|
964
|
-
|
|
965
|
-
**Problem:** Real-time updates not working
|
|
966
|
-
**Solution:**
|
|
967
|
-
```tsx
|
|
968
|
-
// Check WebSocket connection
|
|
969
|
-
useEffect(() => {
|
|
970
|
-
if (state.agentId) {
|
|
971
|
-
const ws = new WebSocket(`${WS_END_POINT.WS}?agent_id=${state.agentId}`);
|
|
972
|
-
|
|
973
|
-
ws.onopen = () => console.log('WebSocket connected');
|
|
974
|
-
ws.onerror = (error) => console.error('WebSocket error:', error);
|
|
975
|
-
ws.onclose = () => console.log('WebSocket disconnected');
|
|
976
|
-
|
|
977
|
-
return () => ws.close();
|
|
978
|
-
}
|
|
979
|
-
}, [state.agentId]);
|
|
980
|
-
```
|
|
981
|
-
|
|
982
|
-
#### 4. Call Controls Not Working
|
|
983
|
-
|
|
984
|
-
**Problem:** Buttons not responding or API calls failing
|
|
985
|
-
**Solution:**
|
|
986
|
-
```tsx
|
|
987
|
-
// Check agent status and call state
|
|
988
|
-
function CallControls() {
|
|
989
|
-
const state = useSDKState();
|
|
990
|
-
|
|
991
|
-
// Ensure agent is ready before allowing calls
|
|
992
|
-
const canMakeCall = state.status === "idle" || state.status === "ready";
|
|
993
|
-
|
|
994
|
-
return (
|
|
995
|
-
<button
|
|
996
|
-
onClick={handleCall}
|
|
997
|
-
disabled={!canMakeCall || isLoading}
|
|
998
|
-
>
|
|
999
|
-
Call
|
|
1000
|
-
</button>
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
1003
|
-
```
|
|
1004
|
-
|
|
1005
|
-
### Debug Mode
|
|
1006
|
-
|
|
1007
|
-
Enable debug logging:
|
|
1008
|
-
|
|
1009
|
-
```tsx
|
|
1010
|
-
// Add to your app initialization
|
|
1011
|
-
if (process.env.NODE_ENV === 'development') {
|
|
1012
|
-
// Enable SDK debug mode
|
|
1013
|
-
sdkStateManager.debugStorage();
|
|
1014
|
-
|
|
1015
|
-
// Log all state changes
|
|
1016
|
-
sdkStateManager.subscribe(() => {
|
|
1017
|
-
console.log('SDK State changed:', sdkStateManager.getState());
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
```
|
|
1021
|
-
|
|
1022
|
-
---
|
|
1023
|
-
|
|
1024
|
-
## Productivity Features
|
|
1025
|
-
|
|
1026
|
-
### 1. Agent Productivity Metrics
|
|
1027
|
-
|
|
1028
|
-
The SDK automatically tracks various productivity metrics:
|
|
1029
|
-
|
|
1030
|
-
```tsx
|
|
1031
|
-
// Event tracking for productivity analysis
|
|
1032
|
-
eventTracker.logEvent('callStarted', {
|
|
1033
|
-
agentId: state.agentId,
|
|
1034
|
-
phoneNumber: state.callData.phone_number,
|
|
1035
|
-
timestamp: new Date().toISOString(),
|
|
1036
|
-
processId: state.process?.process_id
|
|
1037
|
-
});
|
|
1038
|
-
|
|
1039
|
-
eventTracker.logEvent('callEnded', {
|
|
1040
|
-
agentId: state.agentId,
|
|
1041
|
-
duration: callDuration,
|
|
1042
|
-
disposition: disposition,
|
|
1043
|
-
timestamp: new Date().toISOString()
|
|
1044
|
-
});
|
|
1045
|
-
```
|
|
1046
|
-
|
|
1047
|
-
### 2. Real-time Status Updates
|
|
1048
|
-
|
|
1049
|
-
```tsx
|
|
1050
|
-
// Automatic status synchronization
|
|
1051
|
-
useEffect(() => {
|
|
1052
|
-
const ws = new WebSocket(`${WS_END_POINT.WS}?agent_id=${state.agentId}`);
|
|
1053
|
-
|
|
1054
|
-
ws.onmessage = (event) => {
|
|
1055
|
-
const data = JSON.parse(event.data);
|
|
1056
|
-
|
|
1057
|
-
// Update call data
|
|
1058
|
-
sdkStateManager.updateCallData(data);
|
|
1059
|
-
|
|
1060
|
-
// Track status changes
|
|
1061
|
-
eventTracker.logEvent('statusChanged', {
|
|
1062
|
-
from: state.status,
|
|
1063
|
-
to: data.status,
|
|
1064
|
-
timestamp: new Date().toISOString()
|
|
1065
|
-
});
|
|
1066
|
-
};
|
|
1067
|
-
}, [state.agentId]);
|
|
1068
|
-
```
|
|
1069
|
-
|
|
1070
|
-
### 3. Call Quality Monitoring
|
|
1071
|
-
|
|
1072
|
-
```tsx
|
|
1073
|
-
// Monitor call quality metrics
|
|
1074
|
-
function CallQualityMonitor() {
|
|
1075
|
-
const state = useSDKState();
|
|
1076
|
-
|
|
1077
|
-
useEffect(() => {
|
|
1078
|
-
if (state.callData?.status === "ONCALL") {
|
|
1079
|
-
const startTime = Date.now();
|
|
1080
|
-
|
|
1081
|
-
const interval = setInterval(() => {
|
|
1082
|
-
const duration = Date.now() - startTime;
|
|
1083
|
-
|
|
1084
|
-
// Log call quality metrics every 30 seconds
|
|
1085
|
-
if (duration % 30000 === 0) {
|
|
1086
|
-
eventTracker.logEvent('callQualityMetrics', {
|
|
1087
|
-
duration: duration,
|
|
1088
|
-
isHolding: state.isHolding,
|
|
1089
|
-
isMuted: state.isMuted,
|
|
1090
|
-
timestamp: new Date().toISOString()
|
|
1091
|
-
});
|
|
1092
|
-
}
|
|
1093
|
-
}, 1000);
|
|
1094
|
-
|
|
1095
|
-
return () => clearInterval(interval);
|
|
1096
|
-
}
|
|
1097
|
-
}, [state.callData?.status, state.isHolding, state.isMuted]);
|
|
1098
|
-
}
|
|
1099
|
-
```
|
|
1100
|
-
|
|
1101
|
-
### 4. Performance Analytics
|
|
1102
|
-
|
|
1103
|
-
```tsx
|
|
1104
|
-
// Track UI performance
|
|
1105
|
-
function PerformanceTracker() {
|
|
1106
|
-
useEffect(() => {
|
|
1107
|
-
// Track component render times
|
|
1108
|
-
const startTime = performance.now();
|
|
1109
|
-
|
|
1110
|
-
return () => {
|
|
1111
|
-
const renderTime = performance.now() - startTime;
|
|
1112
|
-
eventTracker.logEvent('componentRender', {
|
|
1113
|
-
component: 'CallControlPanel',
|
|
1114
|
-
renderTime: renderTime,
|
|
1115
|
-
timestamp: new Date().toISOString()
|
|
1116
|
-
});
|
|
1117
|
-
};
|
|
1118
|
-
}, []);
|
|
1119
|
-
}
|
|
1120
|
-
```
|
|
1121
|
-
|
|
1122
|
-
### 5. User Experience Optimization
|
|
1123
|
-
|
|
1124
|
-
```tsx
|
|
1125
|
-
// Optimize user interactions
|
|
1126
|
-
function OptimizedCallControls() {
|
|
1127
|
-
const state = useSDKState();
|
|
1128
|
-
|
|
1129
|
-
// Debounce rapid button clicks
|
|
1130
|
-
const debouncedHold = useDebounce(() => {
|
|
1131
|
-
handleHoldToggle();
|
|
1132
|
-
}, 300);
|
|
1133
|
-
|
|
1134
|
-
// Track user interaction patterns
|
|
1135
|
-
const trackInteraction = (action) => {
|
|
1136
|
-
eventTracker.logEvent('userInteraction', {
|
|
1137
|
-
action: action,
|
|
1138
|
-
agentId: state.agentId,
|
|
1139
|
-
timestamp: new Date().toISOString()
|
|
1140
|
-
});
|
|
1141
|
-
};
|
|
1142
|
-
|
|
1143
|
-
return (
|
|
1144
|
-
<div>
|
|
1145
|
-
<button
|
|
1146
|
-
onClick={() => {
|
|
1147
|
-
trackInteraction('holdToggle');
|
|
1148
|
-
debouncedHold();
|
|
1149
|
-
}}
|
|
1150
|
-
>
|
|
1151
|
-
Hold
|
|
1152
|
-
</button>
|
|
1153
|
-
</div>
|
|
1154
|
-
);
|
|
1155
|
-
}
|
|
1156
|
-
```
|
|
1157
|
-
|
|
1158
|
-
---
|
|
1159
|
-
|
|
1160
|
-
## Conclusion
|
|
1161
|
-
|
|
1162
|
-
The Call Control SDK provides a comprehensive solution for WebRTC call management in contact center environments. With its draggable interface, real-time state management, extensive TypeScript support, and productivity features, it enables developers to build robust call center applications quickly and efficiently.
|
|
1163
|
-
|
|
1164
|
-
Key benefits:
|
|
1165
|
-
- **Rapid Development**: Pre-built components and hooks accelerate development
|
|
1166
|
-
- **Type Safety**: Full TypeScript support prevents runtime errors
|
|
1167
|
-
- **Real-time Updates**: WebSocket integration ensures live data synchronization
|
|
1168
|
-
- **Productivity Focus**: Built-in analytics and monitoring capabilities
|
|
1169
|
-
- **Accessibility**: Material-UI components with proper ARIA support
|
|
1170
|
-
- **Mobile Ready**: Touch support and responsive design
|
|
1171
|
-
- **Extensible**: Modular architecture allows for easy customization
|
|
1172
|
-
|
|
1173
|
-
For additional support or feature requests, please refer to the official documentation or contact the development team.
|
|
1174
|
-
|
|
1175
|
-
---
|
|
1176
|
-
|
|
1177
|
-
*Documentation Version: 1.0*
|
|
1178
|
-
*Last Updated: 2025*
|
|
1179
|
-
*SDK Version: 5.3.0*
|
|
1
|
+
### Call Control SDK [](https://www.npmjs.com/package/call-control-sdk) [](https://www.npmjs.com/package/call-control-sdk)
|
|
2
|
+
|
|
3
|
+
A lightweight SDK that provides a **draggable call control panel** and utility hooks for managing calls in real-time. Built with **TypeScript**, **Material-UI**, and designed for **agent productivity**.
|
|
4
|
+
|
|
5
|
+
### ✨ Features
|
|
6
|
+
|
|
7
|
+
- 🎯 **Complete Call Control** – Hold, Mute, Status management, and End Call
|
|
8
|
+
- 🖱️ **Draggable Interface** – Movable panel with persisted position
|
|
9
|
+
- 💾 **State Persistence** – Saves control states in `localStorage`
|
|
10
|
+
- ⏱️ **Live Call Timer** – Real-time call duration tracking
|
|
11
|
+
- 🎨 **Material-UI Design** – Responsive and accessible UI
|
|
12
|
+
- 📱 **Touch Support** – Works seamlessly on desktop and mobile
|
|
13
|
+
- 🔧 **TypeScript Support** – Full type safety and IntelliSense
|
|
14
|
+
- 🎪 **Singleton State** – Consistent shared state across components
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### 📦 Installation [](https://bundlephobia.com/package/call-control-sdk)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install call-control-sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 🔑 Peer Dependencies
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install react react-dom axios @mui/material @mui/icons-material @emotion/react @emotion/styled
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 📚 Table of Contents
|
|
31
|
+
|
|
32
|
+
1. [Getting Started](#-getting-started)
|
|
33
|
+
2. [Core API](#-core-api)
|
|
34
|
+
- [initSDK](#initsdk)
|
|
35
|
+
- [CallControlPanel](#callcontrolpanel)
|
|
36
|
+
- [updateCallData](#updatecalldata)
|
|
37
|
+
3. [Hooks](#-hooks)
|
|
38
|
+
- [useLogout](#uselogout)
|
|
39
|
+
- [useClickToCall](#useClickToCall)
|
|
40
|
+
- [useEndCall](#useendcall)
|
|
41
|
+
4. [Payloads](#-payloads)
|
|
42
|
+
5. [Control Features](#-control-features)
|
|
43
|
+
6. [Browser Support](#-browser-support)
|
|
44
|
+
7. [License](#-license)
|
|
45
|
+
|
|
46
|
+
### 🚀 Getting Started
|
|
47
|
+
|
|
48
|
+
#### 1. Initialize the SDK
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useEffect } from "react";
|
|
52
|
+
import { initSDK } from "call-control-sdk";
|
|
53
|
+
|
|
54
|
+
// Initialize at the top level of your app
|
|
55
|
+
function App() {
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
// Initialize the SDK.
|
|
58
|
+
try {
|
|
59
|
+
initSDK({
|
|
60
|
+
apiKey: "your-api-key",
|
|
61
|
+
tenantId: "your-tenant-id",
|
|
62
|
+
agentId: "your-agent-id",
|
|
63
|
+
});
|
|
64
|
+
console.log("SDK initialized successfully");
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error("SDK initialization failed:", error);
|
|
67
|
+
}
|
|
68
|
+
}, []);
|
|
69
|
+
|
|
70
|
+
return <h1>My App</h1>;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### 2. Add the Call Control Panel
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { CallControlPanel } from "call-control-sdk";
|
|
78
|
+
|
|
79
|
+
export default function App() {
|
|
80
|
+
const handleDataChange = (data) => {
|
|
81
|
+
console.log("Call data updated:", data);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
<h1>Agent Dashboard</h1>
|
|
87
|
+
<CallControlPanel onDataChange={handleDataChange} />
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### 3. Logout Agent
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { useLogout } from "call-control-sdk";
|
|
97
|
+
|
|
98
|
+
export default function LogoutButton() {
|
|
99
|
+
const { logout, isLoading, isSuccess, isError, error } = useLogout();
|
|
100
|
+
return <button onClick={logout}>Logout</button>;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 4. Start Call
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import { useClickToCall } from "call-control-sdk";
|
|
108
|
+
|
|
109
|
+
export default function CallButton() {
|
|
110
|
+
const { handleStartCall, isLoading, isSuccess, isError, error } = useClickToCall();
|
|
111
|
+
|
|
112
|
+
const onStartCall = () => {
|
|
113
|
+
handleStartCall({ mobileNumber: "1111111111" });
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div>
|
|
118
|
+
<button onClick={onStartCall} disabled={isLoading}>
|
|
119
|
+
{ "Call"}
|
|
120
|
+
</button>
|
|
121
|
+
{isSuccess && <p>✅ Call ended successfully</p>}
|
|
122
|
+
{isError && <p>❌ Error: {error?.message}</p>}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
#### 5. End Call
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { useEndCall } from "call-control-sdk";
|
|
131
|
+
|
|
132
|
+
export default function EndCallButton() {
|
|
133
|
+
const { handleEndCall, isLoading, isSuccess, isError, error } = useEndCall();
|
|
134
|
+
|
|
135
|
+
const onEndCall = () => {
|
|
136
|
+
handleEndCall({
|
|
137
|
+
disposition: "RES", // Call disposition
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div>
|
|
143
|
+
<button onClick={onEndCall} disabled={isLoading}>
|
|
144
|
+
{isLoading ? "Ending Call..." : "End Call"}
|
|
145
|
+
</button>
|
|
146
|
+
{isSuccess && <p>✅ Call ended successfully</p>}
|
|
147
|
+
{isError && <p>❌ Error: {error?.message}</p>}
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 🛠 Core API
|
|
154
|
+
|
|
155
|
+
#### `initSDK(config)`
|
|
156
|
+
|
|
157
|
+
Initializes the SDK. Must be called **before using any components or hooks**.
|
|
158
|
+
|
|
159
|
+
**Parameters**:
|
|
160
|
+
|
|
161
|
+
| Name | Type | Required | Description |
|
|
162
|
+
| ---------- | ------ | -------- | ----------------------------------- |
|
|
163
|
+
| `apiKey` | string | ✅ | API key for authentication |
|
|
164
|
+
| `tenantId` | string | ✅ | Tenant ID for events/authentication |
|
|
165
|
+
| `agentId` | string | ✅ | Agent ID for call controls |
|
|
166
|
+
|
|
167
|
+
#### `CallControlPanel`
|
|
168
|
+
|
|
169
|
+
Draggable control panel for call management.
|
|
170
|
+
|
|
171
|
+
**Props**:
|
|
172
|
+
|
|
173
|
+
| Prop | Type | Required | Description |
|
|
174
|
+
| --------------- | -------- | -------- | -------------------------------------------------------------------------------------------------- |
|
|
175
|
+
| `onDataChange?` | function | ❌ | Callback fired when call data changes. Receives `{ mobileNumber, callReferenceId, agentLoginId }`. |
|
|
176
|
+
|
|
177
|
+
#### `updateCallData(data: Partial<CallData>)`
|
|
178
|
+
|
|
179
|
+
Update call data programmatically.
|
|
180
|
+
|
|
181
|
+
**Parameters**:
|
|
182
|
+
|
|
183
|
+
| Field | Type | Description |
|
|
184
|
+
| ------------------ | ------ | ---------------------- |
|
|
185
|
+
| `mobileNumber?` | string | Mobile phone number |
|
|
186
|
+
| `callReferenceId?` | string | Unique call reference |
|
|
187
|
+
| `agentLoginId?` | string | Agent login identifier |
|
|
188
|
+
|
|
189
|
+
### 🪝 Hooks
|
|
190
|
+
|
|
191
|
+
#### `useLogout()`
|
|
192
|
+
|
|
193
|
+
Logs out the current agent.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
const { logOut } = useLogout();
|
|
197
|
+
<button onClick={logOut}>Logout</button>;
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### `useStartCall()`
|
|
201
|
+
|
|
202
|
+
Hook for call to mobile number.
|
|
203
|
+
|
|
204
|
+
**Returns**:
|
|
205
|
+
|
|
206
|
+
| Key | Type | Description |
|
|
207
|
+
| --------------- | -------- | --------------------------------------------------------------- |
|
|
208
|
+
| `handleStartCall` | function | `(payload: StartCallPayload) => void` – triggers end-call request |
|
|
209
|
+
| `isLoading` | boolean | True while request is pending |
|
|
210
|
+
| `isSuccess` | boolean | True if request succeeded |
|
|
211
|
+
| `isError` | boolean | True if request failed |
|
|
212
|
+
| `error` | any | Error object if failed |
|
|
213
|
+
| `data` | any | API response on success |
|
|
214
|
+
|
|
215
|
+
#### `useEndCall()`
|
|
216
|
+
|
|
217
|
+
Hook for ending an active call.
|
|
218
|
+
|
|
219
|
+
**Returns**:
|
|
220
|
+
|
|
221
|
+
| Key | Type | Description |
|
|
222
|
+
| --------------- | -------- | --------------------------------------------------------------- |
|
|
223
|
+
| `handleEndCall` | function | `(payload: EndCallPayload) => void` – triggers end-call request |
|
|
224
|
+
| `isLoading` | boolean | True while request is pending |
|
|
225
|
+
| `isSuccess` | boolean | True if request succeeded |
|
|
226
|
+
| `isError` | boolean | True if request failed |
|
|
227
|
+
| `error` | any | Error object if failed |
|
|
228
|
+
| `data` | any | API response on success |
|
|
229
|
+
|
|
230
|
+
### 📦 Payloads
|
|
231
|
+
|
|
232
|
+
#### `StartCallPayload`
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
interface EndCallPayload {
|
|
236
|
+
mobileNumber?: string; // Mobile number
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### `EndCallPayload`
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
interface EndCallPayload {
|
|
244
|
+
disposition?: string; // Call disposition (default: "RES")
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### 🎛 Control Features
|
|
249
|
+
|
|
250
|
+
**Status Management**: Idle / Break
|
|
251
|
+
**Call Controls**: Hold / Resume, Mute / Unmute, End Call, Agent Status
|
|
252
|
+
**Persistent State**: Hold, mute, agent status, panel position, call timer
|
|
253
|
+
|
|
254
|
+
### 🌍 Browser Support
|
|
255
|
+
|
|
256
|
+
. ✅ Chrome 60+
|
|
257
|
+
. ✅ Firefox 60+
|
|
258
|
+
. ✅ Safari 12+
|
|
259
|
+
. ✅ Edge 79+
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### 📄 License
|
|
265
|
+
|
|
266
|
+
MIT © 2025 [](#-license)
|