call-control-sdk 5.3.0 → 5.3.3
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 +1058 -144
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,265 +1,1179 @@
|
|
|
1
|
-
|
|
1
|
+
# Call Control SDK - Comprehensive Documentation
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
1. [Overview](#overview)
|
|
5
|
+
2. [Architecture](#architecture)
|
|
6
|
+
3. [Installation & Setup](#installation--setup)
|
|
7
|
+
4. [Core Components](#core-components)
|
|
8
|
+
5. [Hooks & Utilities](#hooks--utilities)
|
|
9
|
+
6. [Services & APIs](#services--apis)
|
|
10
|
+
7. [TypeScript Types](#typescript-types)
|
|
11
|
+
8. [Usage Examples](#usage-examples)
|
|
12
|
+
9. [Best Practices](#best-practices)
|
|
13
|
+
10. [API Reference](#api-reference)
|
|
14
|
+
11. [Troubleshooting](#troubleshooting)
|
|
15
|
+
12. [Productivity Features](#productivity-features)
|
|
2
16
|
|
|
3
|
-
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
4
20
|
|
|
5
|
-
|
|
21
|
+
The **Call Control SDK** is a comprehensive TypeScript-based library designed for WebRTC call management in contact center environments. It provides a draggable call control panel with real-time call management capabilities, agent productivity tools, and seamless integration with existing applications.
|
|
6
22
|
|
|
23
|
+
### Key Features
|
|
7
24
|
- 🎯 **Complete Call Control** – Hold, Mute, Status management, and End Call
|
|
8
25
|
- 🖱️ **Draggable Interface** – Movable panel with persisted position
|
|
9
|
-
- 💾 **State Persistence** – Saves control states in
|
|
26
|
+
- 💾 **State Persistence** – Saves control states in localStorage
|
|
10
27
|
- ⏱️ **Live Call Timer** – Real-time call duration tracking
|
|
11
28
|
- 🎨 **Material-UI Design** – Responsive and accessible UI
|
|
12
29
|
- 📱 **Touch Support** – Works seamlessly on desktop and mobile
|
|
13
30
|
- 🔧 **TypeScript Support** – Full type safety and IntelliSense
|
|
14
31
|
- 🎪 **Singleton State** – Consistent shared state across components
|
|
32
|
+
- 📊 **Event Tracking** – Comprehensive analytics and monitoring
|
|
33
|
+
- 🔄 **WebSocket Integration** – Real-time communication
|
|
34
|
+
- 📞 **Conference Calling** – Multi-line conference management
|
|
35
|
+
- 🔀 **Call Transfer** – Transfer to agents, processes, or queues
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Architecture
|
|
40
|
+
|
|
41
|
+
### Core Architecture Components
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
45
|
+
│ Call Control SDK │
|
|
46
|
+
├─────────────────────────────────────────────────────────────┤
|
|
47
|
+
│ Components Layer │
|
|
48
|
+
│ ├── CallControlPanel (Main UI Component) │
|
|
49
|
+
│ ├── CallControls (Control Buttons & Logic) │
|
|
50
|
+
│ ├── Dialog Components (Transfer, Conference, etc.) │
|
|
51
|
+
│ └── SDKProvider (Context Provider) │
|
|
52
|
+
├─────────────────────────────────────────────────────────────┤
|
|
53
|
+
│ Hooks Layer │
|
|
54
|
+
│ ├── useSDKState (State Management) │
|
|
55
|
+
│ ├── useClickToCall (Call Initiation) │
|
|
56
|
+
│ ├── useEndCall (Call Termination) │
|
|
57
|
+
│ ├── useLogout (Agent Logout) │
|
|
58
|
+
│ ├── useDraggable (Drag & Drop) │
|
|
59
|
+
│ └── eventsTracker (Analytics) │
|
|
60
|
+
├─────────────────────────────────────────────────────────────┤
|
|
61
|
+
│ Services Layer │
|
|
62
|
+
│ ├── axios.ts (HTTP Client) │
|
|
63
|
+
│ ├── request.ts (API Hooks) │
|
|
64
|
+
│ ├── endPoint.ts (API Endpoints) │
|
|
65
|
+
│ └── websocketClient.ts (Real-time Communication) │
|
|
66
|
+
├─────────────────────────────────────────────────────────────┤
|
|
67
|
+
│ State Management │
|
|
68
|
+
│ ├── sdk-state.ts (Singleton State Manager) │
|
|
69
|
+
│ └── types.ts (TypeScript Definitions) │
|
|
70
|
+
└─────────────────────────────────────────────────────────────┘
|
|
71
|
+
```
|
|
15
72
|
|
|
73
|
+
### State Management Flow
|
|
74
|
+
|
|
75
|
+
```mermaid
|
|
76
|
+
graph TD
|
|
77
|
+
A[SDK Initialization] --> B[State Manager]
|
|
78
|
+
B --> C[localStorage Persistence]
|
|
79
|
+
B --> D[Component Updates]
|
|
80
|
+
D --> E[UI Rendering]
|
|
81
|
+
E --> F[User Interactions]
|
|
82
|
+
F --> G[API Calls]
|
|
83
|
+
G --> H[State Updates]
|
|
84
|
+
H --> B
|
|
85
|
+
|
|
86
|
+
I[WebSocket Events] --> J[Real-time Updates]
|
|
87
|
+
J --> B
|
|
88
|
+
|
|
89
|
+
K[Event Tracking] --> L[Analytics]
|
|
90
|
+
L --> M[Performance Monitoring]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
16
94
|
|
|
95
|
+
## Installation & Setup
|
|
17
96
|
|
|
18
|
-
###
|
|
97
|
+
### Prerequisites
|
|
98
|
+
- Node.js 16+
|
|
99
|
+
- React 16+
|
|
100
|
+
- TypeScript 5+
|
|
101
|
+
|
|
102
|
+
### Installation
|
|
19
103
|
|
|
20
104
|
```bash
|
|
21
105
|
npm install call-control-sdk
|
|
22
106
|
```
|
|
23
107
|
|
|
24
|
-
###
|
|
108
|
+
### Peer Dependencies
|
|
25
109
|
|
|
26
110
|
```bash
|
|
27
111
|
npm install react react-dom axios @mui/material @mui/icons-material @emotion/react @emotion/styled
|
|
28
112
|
```
|
|
29
113
|
|
|
30
|
-
###
|
|
114
|
+
### Basic Setup
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import React, { useEffect } from 'react';
|
|
118
|
+
import { initSDK, CallControlPanel } from 'call-control-sdk';
|
|
119
|
+
|
|
120
|
+
function App() {
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
// Initialize the SDK
|
|
123
|
+
initSDK({
|
|
124
|
+
apiKey: "your-api-key",
|
|
125
|
+
tenantId: "your-tenant-id",
|
|
126
|
+
agentId: "your-agent-id"
|
|
127
|
+
});
|
|
128
|
+
}, []);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div className="app">
|
|
132
|
+
<h1>Agent Dashboard</h1>
|
|
133
|
+
<CallControlPanel
|
|
134
|
+
onDataChange={(data) => {
|
|
135
|
+
console.log('Call data updated:', data);
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export default App;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
31
146
|
|
|
32
|
-
|
|
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)
|
|
147
|
+
## Core Components
|
|
45
148
|
|
|
46
|
-
###
|
|
149
|
+
### 1. CallControlPanel
|
|
47
150
|
|
|
48
|
-
|
|
151
|
+
The main UI component that renders the draggable call control interface.
|
|
49
152
|
|
|
50
153
|
```tsx
|
|
51
|
-
|
|
52
|
-
|
|
154
|
+
interface CallControlPanelProps {
|
|
155
|
+
onDataChange?: (data: CallData) => void;
|
|
156
|
+
}
|
|
53
157
|
|
|
54
|
-
//
|
|
55
|
-
|
|
158
|
+
// Usage
|
|
159
|
+
<CallControlPanel
|
|
160
|
+
onDataChange={(callData) => {
|
|
161
|
+
// Handle call data changes
|
|
162
|
+
updateDashboard(callData);
|
|
163
|
+
}}
|
|
164
|
+
/>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Features:**
|
|
168
|
+
- Draggable positioning with persistence
|
|
169
|
+
- Real-time call status display
|
|
170
|
+
- Agent status management
|
|
171
|
+
- Call duration timer
|
|
172
|
+
- Control buttons (Hold, Mute, Transfer, Conference, End Call)
|
|
173
|
+
|
|
174
|
+
### 2. CallControls
|
|
175
|
+
|
|
176
|
+
The core control component containing all call management buttons and logic.
|
|
177
|
+
|
|
178
|
+
**Key Controls:**
|
|
179
|
+
- **Agent Ready**: Set agent status to ready
|
|
180
|
+
- **Hold/Resume**: Toggle call hold state
|
|
181
|
+
- **Mute/Unmute**: Toggle microphone state
|
|
182
|
+
- **Transfer**: Transfer call to another agent/queue/process
|
|
183
|
+
- **Conference**: Add participants to conference call
|
|
184
|
+
- **End Call**: Terminate call with disposition
|
|
185
|
+
|
|
186
|
+
### 3. Dialog Components
|
|
187
|
+
|
|
188
|
+
#### ConferenceDialog
|
|
189
|
+
Manages multi-line conference calls with up to 5 lines.
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// Conference line management
|
|
193
|
+
interface ConferenceLineTypes {
|
|
194
|
+
line: number;
|
|
195
|
+
status: string;
|
|
196
|
+
type: "external" | "internal" | "";
|
|
197
|
+
phone: string;
|
|
198
|
+
isMute: boolean;
|
|
199
|
+
isHold: boolean;
|
|
200
|
+
isCallStart: boolean;
|
|
201
|
+
isMergeCall: boolean;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### CallTransferDialog
|
|
206
|
+
Handles call transfers to:
|
|
207
|
+
- **Agents**: Transfer to specific agents
|
|
208
|
+
- **Processes**: Transfer to business processes
|
|
209
|
+
- **Queues**: Transfer to call queues
|
|
210
|
+
|
|
211
|
+
#### EndCallDispositionDialog
|
|
212
|
+
Captures call disposition and follow-up information:
|
|
213
|
+
- Disposition codes (Resolved, Not Interested)
|
|
214
|
+
- Follow-up requirements
|
|
215
|
+
- Callback scheduling
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Hooks & Utilities
|
|
220
|
+
|
|
221
|
+
### 1. useSDKState
|
|
222
|
+
|
|
223
|
+
Provides reactive access to the SDK's global state.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import { useSDKState } from 'call-control-sdk';
|
|
227
|
+
|
|
228
|
+
function MyComponent() {
|
|
229
|
+
const state = useSDKState();
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<div>
|
|
233
|
+
<p>Agent Status: {state.status}</p>
|
|
234
|
+
<p>Call Duration: {state.callStartTime}</p>
|
|
235
|
+
<p>Is Muted: {state.isMuted ? 'Yes' : 'No'}</p>
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 2. useClickToCall
|
|
242
|
+
|
|
243
|
+
Initiates outbound calls to phone numbers.
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
import { useClickToCall } from 'call-control-sdk';
|
|
247
|
+
|
|
248
|
+
function DialerComponent() {
|
|
249
|
+
const { handleStartCall, isLoading, isSuccess, error } = useClickToCall();
|
|
250
|
+
|
|
251
|
+
const makeCall = () => {
|
|
252
|
+
handleStartCall({ mobileNumber: "1234567890" });
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<button onClick={makeCall} disabled={isLoading}>
|
|
257
|
+
{isLoading ? 'Calling...' : 'Call'}
|
|
258
|
+
</button>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 3. useEndCall
|
|
264
|
+
|
|
265
|
+
Terminates active calls with disposition tracking.
|
|
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
|
|
56
549
|
useEffect(() => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
agentId: "your-agent-id",
|
|
63
|
-
});
|
|
64
|
-
console.log("SDK initialized successfully");
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error("SDK initialization failed:", error);
|
|
67
|
-
}
|
|
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
|
+
});
|
|
68
555
|
}, []);
|
|
69
556
|
|
|
70
|
-
|
|
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
|
+
);
|
|
71
590
|
}
|
|
72
591
|
```
|
|
73
592
|
|
|
74
|
-
|
|
593
|
+
### 2. Custom Call Controls
|
|
75
594
|
|
|
76
595
|
```tsx
|
|
77
|
-
import
|
|
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
|
|
78
648
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
+
}
|
|
82
667
|
};
|
|
83
668
|
|
|
84
669
|
return (
|
|
85
|
-
<div>
|
|
86
|
-
<
|
|
87
|
-
|
|
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
|
+
)}
|
|
88
691
|
</div>
|
|
89
692
|
);
|
|
90
693
|
}
|
|
91
694
|
```
|
|
92
695
|
|
|
93
|
-
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
## Best Practices
|
|
699
|
+
|
|
700
|
+
### 1. Initialization
|
|
94
701
|
|
|
95
702
|
```tsx
|
|
96
|
-
|
|
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
|
+
}
|
|
97
720
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
721
|
+
// ❌ Bad: Initializing in component that might unmount
|
|
722
|
+
function SomeComponent() {
|
|
723
|
+
useEffect(() => {
|
|
724
|
+
initSDK(config); // This might be called multiple times
|
|
725
|
+
}, []);
|
|
101
726
|
}
|
|
102
727
|
```
|
|
103
728
|
|
|
104
|
-
|
|
729
|
+
### 2. State Management
|
|
105
730
|
|
|
106
731
|
```tsx
|
|
107
|
-
|
|
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
|
+
}
|
|
108
743
|
|
|
109
|
-
|
|
110
|
-
|
|
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
|
+
```
|
|
111
750
|
|
|
112
|
-
|
|
113
|
-
|
|
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
|
+
}
|
|
114
766
|
};
|
|
115
767
|
|
|
116
768
|
return (
|
|
117
769
|
<div>
|
|
118
|
-
<button onClick={
|
|
119
|
-
{
|
|
770
|
+
<button onClick={makeCall} disabled={isLoading}>
|
|
771
|
+
{isLoading ? 'Calling...' : 'Call'}
|
|
120
772
|
</button>
|
|
121
|
-
{
|
|
122
|
-
{isError && <p>❌ Error: {error?.message}</p>}
|
|
773
|
+
{isError && <p className="error">Error: {error?.message}</p>}
|
|
123
774
|
</div>
|
|
124
775
|
);
|
|
125
776
|
}
|
|
126
777
|
```
|
|
127
|
-
|
|
778
|
+
|
|
779
|
+
### 4. Performance Optimization
|
|
128
780
|
|
|
129
781
|
```tsx
|
|
130
|
-
|
|
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
|
+
}
|
|
131
792
|
|
|
132
|
-
|
|
133
|
-
|
|
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
|
+
```
|
|
134
805
|
|
|
135
|
-
|
|
136
|
-
handleEndCall({
|
|
137
|
-
disposition: "RES", // Call disposition
|
|
138
|
-
});
|
|
139
|
-
};
|
|
806
|
+
### 5. Accessibility
|
|
140
807
|
|
|
808
|
+
```tsx
|
|
809
|
+
// ✅ Good: Accessible controls
|
|
810
|
+
function AccessibleCallControls() {
|
|
811
|
+
const state = useSDKState();
|
|
812
|
+
|
|
141
813
|
return (
|
|
142
|
-
<div>
|
|
143
|
-
<button
|
|
144
|
-
{
|
|
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 />}
|
|
145
829
|
</button>
|
|
146
|
-
{isSuccess && <p>✅ Call ended successfully</p>}
|
|
147
|
-
{isError && <p>❌ Error: {error?.message}</p>}
|
|
148
830
|
</div>
|
|
149
831
|
);
|
|
150
832
|
}
|
|
151
833
|
```
|
|
152
834
|
|
|
153
|
-
|
|
835
|
+
---
|
|
154
836
|
|
|
155
|
-
|
|
837
|
+
## API Reference
|
|
156
838
|
|
|
157
|
-
|
|
839
|
+
### Core Functions
|
|
158
840
|
|
|
159
|
-
|
|
841
|
+
#### `initSDK(config: InitSDKParams): void`
|
|
160
842
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
+
```
|
|
166
858
|
|
|
167
859
|
#### `CallControlPanel`
|
|
168
860
|
|
|
169
|
-
|
|
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
|
|
170
876
|
|
|
171
|
-
|
|
877
|
+
#### `useSDKState(): SDKState`
|
|
172
878
|
|
|
173
|
-
|
|
174
|
-
| --------------- | -------- | -------- | -------------------------------------------------------------------------------------------------- |
|
|
175
|
-
| `onDataChange?` | function | ❌ | Callback fired when call data changes. Receives `{ mobileNumber, callReferenceId, agentLoginId }`. |
|
|
879
|
+
Returns the current SDK state with reactive updates.
|
|
176
880
|
|
|
177
|
-
|
|
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...
|
|
178
889
|
|
|
179
|
-
|
|
890
|
+
#### `useClickToCall()`
|
|
180
891
|
|
|
181
|
-
|
|
892
|
+
Hook for initiating outbound calls.
|
|
182
893
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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()`
|
|
188
903
|
|
|
189
|
-
|
|
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
|
|
190
913
|
|
|
191
914
|
#### `useLogout()`
|
|
192
915
|
|
|
193
|
-
|
|
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
|
|
194
933
|
|
|
934
|
+
**Problem:** SDK fails to initialize
|
|
935
|
+
**Solution:**
|
|
195
936
|
```tsx
|
|
196
|
-
|
|
197
|
-
|
|
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
|
+
}
|
|
198
961
|
```
|
|
199
962
|
|
|
200
|
-
####
|
|
963
|
+
#### 3. WebSocket Connection Issues
|
|
201
964
|
|
|
202
|
-
|
|
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
|
+
```
|
|
203
981
|
|
|
204
|
-
|
|
982
|
+
#### 4. Call Controls Not Working
|
|
205
983
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
+
```
|
|
214
1004
|
|
|
215
|
-
|
|
1005
|
+
### Debug Mode
|
|
1006
|
+
|
|
1007
|
+
Enable debug logging:
|
|
216
1008
|
|
|
217
|
-
|
|
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
|
+
```
|
|
218
1021
|
|
|
219
|
-
|
|
1022
|
+
---
|
|
220
1023
|
|
|
221
|
-
|
|
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 |
|
|
1024
|
+
## Productivity Features
|
|
229
1025
|
|
|
230
|
-
###
|
|
1026
|
+
### 1. Agent Productivity Metrics
|
|
231
1027
|
|
|
232
|
-
|
|
1028
|
+
The SDK automatically tracks various productivity metrics:
|
|
233
1029
|
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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]);
|
|
238
1068
|
```
|
|
239
1069
|
|
|
240
|
-
|
|
1070
|
+
### 3. Call Quality Monitoring
|
|
241
1071
|
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
|
|
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]);
|
|
245
1098
|
}
|
|
246
1099
|
```
|
|
247
1100
|
|
|
248
|
-
###
|
|
1101
|
+
### 4. Performance Analytics
|
|
249
1102
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
+
```
|
|
253
1121
|
|
|
254
|
-
###
|
|
1122
|
+
### 5. User Experience Optimization
|
|
255
1123
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
+
```
|
|
260
1157
|
|
|
261
1158
|
---
|
|
262
1159
|
|
|
263
|
-
|
|
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
|
+
---
|
|
264
1176
|
|
|
265
|
-
|
|
1177
|
+
*Documentation Version: 1.0*
|
|
1178
|
+
*Last Updated: 2025*
|
|
1179
|
+
*SDK Version: 5.3.0*
|