call-control-sdk 5.3.3 → 5.3.6

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 CHANGED
@@ -1,1179 +1,266 @@
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)
16
-
17
- ---
18
-
19
- ## Overview
20
-
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.
22
-
23
- ### Key Features
24
- - 🎯 **Complete Call Control** – Hold, Mute, Status management, and End Call
25
- - 🖱️ **Draggable Interface** – Movable panel with persisted position
26
- - 💾 **State Persistence** – Saves control states in localStorage
27
- - ⏱️ **Live Call Timer** Real-time call duration tracking
28
- - 🎨 **Material-UI Design** – Responsive and accessible UI
29
- - 📱 **Touch Support** – Works seamlessly on desktop and mobile
30
- - 🔧 **TypeScript Support** – Full type safety and IntelliSense
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
- ```
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
- ---
94
-
95
- ## Installation & Setup
96
-
97
- ### Prerequisites
98
- - Node.js 16+
99
- - React 16+
100
- - TypeScript 5+
101
-
102
- ### Installation
103
-
104
- ```bash
105
- npm install call-control-sdk
106
- ```
107
-
108
- ### Peer Dependencies
109
-
110
- ```bash
111
- npm install react react-dom axios @mui/material @mui/icons-material @emotion/react @emotion/styled
112
- ```
113
-
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
- ---
146
-
147
- ## Core Components
148
-
149
- ### 1. CallControlPanel
150
-
151
- The main UI component that renders the draggable call control interface.
152
-
153
- ```tsx
154
- interface CallControlPanelProps {
155
- onDataChange?: (data: CallData) => void;
156
- }
157
-
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
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 [![npm version](https://img.shields.io/npm/v/call-control-sdk.svg?color=blue)](https://www.npmjs.com/package/call-control-sdk) [![npm downloads](https://img.shields.io/npm/dm/call-control-sdk.svg?color=green)](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 [![bundle size](https://img.shields.io/bundlephobia/minzip/call-control-sdk?color=orange&fontSize=12px)](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](https://img.shields.io/npm/l/call-control-sdk.svg)](#-license)