ahs-cti 0.0.2-beta.9 β 1.0.0-beta.10
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 +425 -294
- package/dist/callHistory-EBPSP3ZL.mjs +339 -0
- package/dist/callHistory-EBPSP3ZL.mjs.map +1 -0
- package/dist/chunk-OBJIKFAS.mjs +916 -0
- package/dist/chunk-OBJIKFAS.mjs.map +1 -0
- package/dist/index.d.mts +470 -3
- package/dist/index.d.ts +470 -3
- package/dist/index.js +3148 -1895
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1977 -2047
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## AHS CTI SDK
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/ahs-cti)
|
|
6
|
+
[](https://www.npmjs.com/package/ahs-cti)
|
|
7
|
+
[](https://bundlephobia.com/package/ahs-cti)
|
|
8
8
|
|
|
9
|
-
**A powerful, lightweight SDK for real-time call management**
|
|
9
|
+
**A powerful, lightweight SDK for real-time call management with dynamic configuration and permission-based access control**
|
|
10
10
|
|
|
11
11
|
**πAUTHORIZED ACCESS REQUIRED - API Key & Tenant IDπ**
|
|
12
12
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
- **API Key Authentication** - Secure access through authorized API keys
|
|
18
18
|
- **Tenant ID Management** - Multi-tenant support with isolated access
|
|
19
|
+
- **Permission-Based Access Control** - Entitlement-driven feature enablement
|
|
19
20
|
- **Cross-Platform Support** - Use across web, mobile, desktop, and server platforms
|
|
20
21
|
- **Usage Monitoring** - Real-time tracking and compliance monitoring
|
|
21
22
|
- **Flexible Deployment** - Deploy on authorized platforms with proper credentials
|
|
@@ -36,12 +37,17 @@
|
|
|
36
37
|
- [1οΈβ£ Initialize the SDK](#1οΈβ£-initialize-the-sdk)
|
|
37
38
|
- [2οΈβ£ Add Call Control Panel](#2οΈβ£-add-call-control-panel)
|
|
38
39
|
- [3οΈβ£ Use Call Management Hooks](#3οΈβ£-use-call-management-hooks)
|
|
39
|
-
- [
|
|
40
|
+
- [βοΈ Dynamic Configuration](#οΈ-dynamic-configuration)
|
|
41
|
+
- [π§ SDK Config](#-sdk-config)
|
|
42
|
+
- [π URL Config](#-url-config)
|
|
43
|
+
- [π Permission-Based Controls](#-permission-based-controls)
|
|
44
|
+
- [π Configuration Merge Priority](#-configuration-merge-priority)
|
|
40
45
|
- [π API Reference](#-api-reference)
|
|
41
46
|
- [π§ Core Functions](#-core-functions)
|
|
42
47
|
- [πͺ React Hooks](#-react-hooks)
|
|
48
|
+
- [π Permissions System](#-permissions-system)
|
|
49
|
+
- [π WebSocket Events](#-websocket-events)
|
|
43
50
|
- [π¦ Data Types](#-data-types)
|
|
44
|
-
- [π Control Features](#-control-features)
|
|
45
51
|
- [π Browser Support](#-browser-support)
|
|
46
52
|
- [π License](#-license)
|
|
47
53
|
|
|
@@ -51,31 +57,40 @@
|
|
|
51
57
|
|
|
52
58
|
### π― **Complete Call Control**
|
|
53
59
|
|
|
60
|
+
- Inbound and outbound call management
|
|
54
61
|
- Hold/Resume calls
|
|
55
62
|
- Mute/Unmute functionality
|
|
56
|
-
-
|
|
57
|
-
-
|
|
63
|
+
- Blind, Attended, and Warm call transfers
|
|
64
|
+
- Multi-line conference calling (up to 5 lines)
|
|
65
|
+
- Agent status management (Ready, Break, Wrapup)
|
|
66
|
+
- End call with disposition tracking
|
|
67
|
+
- Ringtone support for incoming calls
|
|
68
|
+
|
|
69
|
+
### βοΈ **Dynamic Configuration**
|
|
70
|
+
|
|
71
|
+
- **Three-layer config merging** - Backend defaults, permission-based controls, and explicit SDK config
|
|
72
|
+
- **Permission-based feature toggling** - Controls auto-disabled based on entitlements
|
|
73
|
+
- **Runtime URL configuration** - All endpoints dynamically resolved from config
|
|
74
|
+
- **Customizable UI** - Material-UI SxProps for button styling
|
|
58
75
|
|
|
59
76
|
### πΎ **Smart State Management**
|
|
60
77
|
|
|
61
78
|
- Real-time call timer
|
|
62
|
-
- Persistent state storage
|
|
79
|
+
- Persistent state storage via `@react-solutions/vault`
|
|
63
80
|
- Singleton state pattern
|
|
64
|
-
- Cross-component sync
|
|
65
|
-
- TypeScript support
|
|
81
|
+
- Cross-component sync via observer pattern
|
|
82
|
+
- Full TypeScript support
|
|
66
83
|
|
|
67
84
|
## π¦ Installation
|
|
68
85
|
|
|
69
86
|
```bash
|
|
70
|
-
npm install
|
|
87
|
+
npm install ahs-cti
|
|
71
88
|
```
|
|
72
89
|
|
|
73
|
-
### π Required Dependencies
|
|
74
|
-
|
|
75
|
-
Make sure you have these peer dependencies installed:
|
|
90
|
+
### π Required Peer Dependencies
|
|
76
91
|
|
|
77
92
|
```bash
|
|
78
|
-
npm install react react-dom axios @mui/material @mui/icons-material @emotion/react @emotion/styled
|
|
93
|
+
npm install react react-dom axios @mui/material @mui/icons-material @emotion/react @emotion/styled @react-solutions/vault
|
|
79
94
|
```
|
|
80
95
|
|
|
81
96
|
---
|
|
@@ -84,27 +99,40 @@ npm install react react-dom axios @mui/material @mui/icons-material @emotion/rea
|
|
|
84
99
|
|
|
85
100
|
### 1οΈβ£ **Initialize the SDK**
|
|
86
101
|
|
|
87
|
-
|
|
102
|
+
Initialize the SDK at the root of your application with the required credentials and optional dynamic configuration:
|
|
88
103
|
|
|
89
104
|
```tsx
|
|
90
105
|
import { useEffect } from "react";
|
|
91
|
-
import { initSDK } from "
|
|
106
|
+
import { initSDK } from "ahs-cti";
|
|
92
107
|
|
|
93
108
|
function App() {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
const initialize = async () => {
|
|
111
|
+
try {
|
|
112
|
+
await initSDK({
|
|
113
|
+
// Required credentials
|
|
114
|
+
apiKey: "your-api-key",
|
|
115
|
+
tenantId: "your-tenant-id",
|
|
116
|
+
agentId: "your-agent-id",
|
|
117
|
+
|
|
118
|
+
// Optional: URL configuration for API endpoints
|
|
119
|
+
urlConfig: {
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
// Optional: Feature configuration overrides
|
|
123
|
+
sdkConfig: {
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
console.log("β
SDK initialized successfully");
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error("β SDK initialization failed:", error);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
initialize();
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
return <YourAppContent />;
|
|
108
136
|
}
|
|
109
137
|
```
|
|
110
138
|
|
|
@@ -113,246 +141,271 @@ function App() {
|
|
|
113
141
|
Drop in the draggable call control panel anywhere in your app:
|
|
114
142
|
|
|
115
143
|
```tsx
|
|
116
|
-
import { CallControlPanel } from "
|
|
144
|
+
import { CallControlPanel } from "ahs-cti";
|
|
117
145
|
|
|
118
146
|
export default function AgentDashboard() {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
);
|
|
147
|
+
const handleCallDataChange = (data) => {
|
|
148
|
+
console.log("π Call data updated:", data);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<div>
|
|
153
|
+
<h1>Agent Dashboard</h1>
|
|
154
|
+
<CallControlPanel onDataChange={handleCallDataChange} />
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
130
157
|
}
|
|
131
158
|
```
|
|
132
159
|
|
|
133
|
-
|
|
160
|
+
### 3οΈβ£ **Use Call Management Hooks**
|
|
134
161
|
|
|
135
|
-
|
|
162
|
+
#### π΄ **Start a Call**
|
|
136
163
|
|
|
137
|
-
|
|
164
|
+
```tsx
|
|
165
|
+
import { useClickToCall } from "ahs-cti";
|
|
138
166
|
|
|
139
|
-
|
|
140
|
-
|
|
167
|
+
export default function CallButton() {
|
|
168
|
+
const { handleStartCall, isLoading, isSuccess, isError, error } =
|
|
169
|
+
useClickToCall();
|
|
170
|
+
|
|
171
|
+
const startCall = () => {
|
|
172
|
+
handleStartCall({ mobileNumber: "1234567890" });
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<button onClick={startCall} disabled={isLoading}>
|
|
177
|
+
{isLoading ? "π Calling..." : "π Start Call"}
|
|
178
|
+
</button>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
141
182
|
|
|
142
|
-
**
|
|
183
|
+
#### π **End a Call**
|
|
143
184
|
|
|
144
|
-
|
|
145
|
-
|
|
185
|
+
```tsx
|
|
186
|
+
import { useEndCall } from "ahs-cti";
|
|
146
187
|
|
|
147
|
-
|
|
188
|
+
export default function EndCallButton() {
|
|
189
|
+
const { handleEndCall, isLoading } = useEndCall();
|
|
148
190
|
|
|
149
|
-
|
|
150
|
-
|
|
191
|
+
const endCall = () => {
|
|
192
|
+
handleEndCall({ disposition: "RES" });
|
|
193
|
+
};
|
|
151
194
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// "phone_number": "1234567890",
|
|
158
|
-
// "status": "ONCALL",
|
|
159
|
-
// "callReferenceId": "convox_call_id_123",
|
|
160
|
-
// "agent_id": "agent001",
|
|
161
|
-
// "process_id": "proc001",
|
|
162
|
-
// "process_name": "Sales Process"
|
|
163
|
-
// }
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<div>
|
|
167
|
-
<h1>Current Call Information</h1>
|
|
168
|
-
<p>Phone Number: {callerData.phone_number}</p>
|
|
169
|
-
<p>Call Status: {callerData.status}</p>
|
|
170
|
-
<p>Call Reference ID: {callerData.callReferenceId}</p>
|
|
171
|
-
<p>Agent ID: {callerData.agent_id}</p>
|
|
172
|
-
<p>Process: {callerData.process_name}</p>
|
|
173
|
-
</div>
|
|
174
|
-
);
|
|
195
|
+
return (
|
|
196
|
+
<button onClick={endCall} disabled={isLoading}>
|
|
197
|
+
{isLoading ? "π Ending..." : "π End Call"}
|
|
198
|
+
</button>
|
|
199
|
+
);
|
|
175
200
|
}
|
|
176
201
|
```
|
|
177
202
|
|
|
178
|
-
|
|
203
|
+
#### πͺ **Agent Logout**
|
|
179
204
|
|
|
180
205
|
```tsx
|
|
181
|
-
import {
|
|
206
|
+
import { useLogout } from "ahs-cti";
|
|
182
207
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const callerData = useGetCallerData();
|
|
186
|
-
|
|
187
|
-
return (
|
|
188
|
-
<div className="call-status-widget">
|
|
189
|
-
<h3>Current Call Status</h3>
|
|
190
|
-
{callerData.status === "ONCALL" ?
|
|
191
|
-
<div>
|
|
192
|
-
<p>π Active Call: {callerData.phone_number}</p>
|
|
193
|
-
<p>Agent: {callerData.agent_id}</p>
|
|
194
|
-
<p>Process: {callerData.process_name}</p>
|
|
195
|
-
</div>
|
|
196
|
-
: <p>No active call</p>}
|
|
197
|
-
</div>
|
|
198
|
-
);
|
|
199
|
-
}
|
|
208
|
+
export default function LogoutButton() {
|
|
209
|
+
const { logout, isLoading } = useLogout();
|
|
200
210
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<CallStatusWidget /> {/* Independent component */}
|
|
207
|
-
{/* No CallControlPanel needed here */}
|
|
208
|
-
</div>
|
|
209
|
-
);
|
|
211
|
+
return (
|
|
212
|
+
<button onClick={logout} disabled={isLoading}>
|
|
213
|
+
{isLoading ? "π Logging out..." : "πͺ Logout"}
|
|
214
|
+
</button>
|
|
215
|
+
);
|
|
210
216
|
}
|
|
211
217
|
```
|
|
212
218
|
|
|
213
|
-
**
|
|
214
|
-
|
|
215
|
-
- β
**Reactive Updates**: Automatically re-renders when call data changes
|
|
216
|
-
- β
**Real-time Data**: Reflects current call state from WebSocket updates
|
|
217
|
-
- β
**Type Safety**: Fully typed with TypeScript interfaces
|
|
218
|
-
- β
**Complete Data**: Returns all available call information
|
|
219
|
-
- β
**Independent**: Works without `CallControlPanel` component
|
|
219
|
+
#### π **Get Caller Data**
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
The `useGetCallerData` hook provides reactive access to current call data independently of `CallControlPanel`:
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
- `callReferenceId`: Unique identifier for the call
|
|
226
|
-
- `agent_id`: ID of the agent handling the call
|
|
227
|
-
- `process_id`: Process identifier for the call
|
|
228
|
-
- `process_name`: Name of the process handling the call
|
|
223
|
+
```tsx
|
|
224
|
+
import { useGetCallerData } from "ahs-cti";
|
|
229
225
|
|
|
230
|
-
|
|
226
|
+
export default function CallStatusWidget() {
|
|
227
|
+
const callerData = useGetCallerData();
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<div>
|
|
231
|
+
<h3>Current Call Status</h3>
|
|
232
|
+
{callerData.status === "ONCALL" ? (
|
|
233
|
+
<div>
|
|
234
|
+
<p>Active Call: {callerData.phone_number}</p>
|
|
235
|
+
<p>Agent: {callerData.agent_id}</p>
|
|
236
|
+
<p>Process: {callerData.process_name}</p>
|
|
237
|
+
<p>Queue: {callerData.queue_name}</p>
|
|
238
|
+
</div>
|
|
239
|
+
) : (
|
|
240
|
+
<p>No active call</p>
|
|
241
|
+
)}
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
231
246
|
|
|
232
|
-
####
|
|
247
|
+
#### π **Subscribe to SDK State**
|
|
233
248
|
|
|
234
249
|
```tsx
|
|
235
|
-
import {
|
|
236
|
-
|
|
237
|
-
export default function
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
disabled={isLoading}
|
|
250
|
-
>
|
|
251
|
-
{isLoading ? "π Calling..." : "π Start Call"}
|
|
252
|
-
</button>
|
|
253
|
-
);
|
|
250
|
+
import { useSDKState } from "ahs-cti";
|
|
251
|
+
|
|
252
|
+
export default function AgentStatusDisplay() {
|
|
253
|
+
const state = useSDKState();
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<div>
|
|
257
|
+
<p>Agent: {state.agentId}</p>
|
|
258
|
+
<p>Status: {state.agentStatus}</p>
|
|
259
|
+
<p>Initialized: {state.isInitialized ? "Yes" : "No"}</p>
|
|
260
|
+
<p>Hold: {state.hold ? "On Hold" : "Active"}</p>
|
|
261
|
+
<p>Mute: {state.mute ? "Muted" : "Unmuted"}</p>
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
254
264
|
}
|
|
255
265
|
```
|
|
256
266
|
|
|
257
|
-
####
|
|
267
|
+
#### π **Get Authorization Token**
|
|
268
|
+
|
|
269
|
+
Retrieve the access token for external API calls:
|
|
258
270
|
|
|
259
271
|
```tsx
|
|
260
|
-
import {
|
|
272
|
+
import { useGetAuthorizationToken } from "ahs-cti";
|
|
261
273
|
|
|
262
|
-
export default function
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
onClick={endCall}
|
|
274
|
-
disabled={isLoading}
|
|
275
|
-
>
|
|
276
|
-
{isLoading ? "π Ending..." : "π End Call"}
|
|
277
|
-
</button>
|
|
278
|
-
);
|
|
274
|
+
export default function ExternalAPICall() {
|
|
275
|
+
const token = useGetAuthorizationToken();
|
|
276
|
+
|
|
277
|
+
const fetchData = async () => {
|
|
278
|
+
const response = await fetch("https://api.example.com/data", {
|
|
279
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
280
|
+
});
|
|
281
|
+
// handle response
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
return <button onClick={fetchData}>Fetch External Data</button>;
|
|
279
285
|
}
|
|
280
286
|
```
|
|
281
287
|
|
|
282
|
-
|
|
288
|
+
---
|
|
283
289
|
|
|
284
|
-
|
|
285
|
-
|
|
290
|
+
## βοΈ Dynamic Configuration
|
|
291
|
+
|
|
292
|
+
The SDK supports a three-layer dynamic configuration system that determines which call control features are enabled.
|
|
293
|
+
|
|
294
|
+
### π§ SDK Config
|
|
295
|
+
|
|
296
|
+
Feature toggle options passed via `sdkConfig` in `initSDK()`:
|
|
297
|
+
|
|
298
|
+
### π¨ **Configuration Options**
|
|
299
|
+
|
|
300
|
+
| Option | Type | Default | Description |
|
|
301
|
+
| --------------------------- | --------- | ------- | --------------------------------------- |
|
|
302
|
+
| `disableEndCallButton` | `boolean` | `false` | Disable the end call button |
|
|
303
|
+
| `disabledDialButton` | `boolean` | `false` | Disable the dial/outbound call button |
|
|
304
|
+
| `disableCallTransferButton` | `boolean` | `false` | Disable the call transfer button |
|
|
305
|
+
| `disableBlindTransfer` | `boolean` | `false` | Disable blind transfer option |
|
|
306
|
+
| `disableAttendedTransfer` | `boolean` | `false` | Disable attended transfer option |
|
|
307
|
+
| `disableWarmTransfer` | `boolean` | `false` | Disable warm transfer option |
|
|
308
|
+
| `disableConferenceButton` | `boolean` | `false` | Disable the conference call button |
|
|
309
|
+
| `disableHoldButton` | `boolean` | `false` | Disable the hold functionality |
|
|
310
|
+
| `disableMuteButton` | `boolean` | `false` | Disable the mute functionality |
|
|
311
|
+
| `disabledMoreOptionsButton` | `boolean` | `false` | Disable the more options menu |
|
|
312
|
+
| `disableSoftPhone` | `boolean` | `false` | Disable the embedded soft phone iframe |
|
|
313
|
+
| `isDraggable` | `boolean` | `true` | Enable/disable panel dragging |
|
|
314
|
+
| `enableSmsServices` | `boolean` | `false` | Enable SMS services |
|
|
315
|
+
| `enableQueueName` | `boolean` | `false` | Show queue name in call data |
|
|
316
|
+
| `enableRingtone` | `boolean` | `false` | Enable ringtone for incoming calls |
|
|
317
|
+
| `auto_wrapup_time` | `number` | - | Auto wrapup time in seconds |
|
|
318
|
+
| `break_time` | `number` | - | Break duration in seconds |
|
|
319
|
+
| `disabled` | `SxProps` | - | Custom MUI styles for disabled states |
|
|
320
|
+
| `enabled` | `SxProps` | - | Custom MUI styles for enabled states |
|
|
321
|
+
| `outlined` | `SxProps` | - | Custom MUI styles for outlined states |
|
|
322
|
+
|
|
323
|
+
### π URL Config
|
|
324
|
+
|
|
325
|
+
All API endpoints are dynamically resolved from the URL configuration:
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
interface URLConfig {
|
|
329
|
+
id: string; // Configuration identifier
|
|
330
|
+
baseURL: string; // Main API base URL
|
|
331
|
+
coreBaseURL: string; // Core API URL for call control actions
|
|
332
|
+
webSocketURL: string; // WebSocket URL for real-time events
|
|
333
|
+
iframeURL: string; // Soft phone iframe URL
|
|
334
|
+
iframeAPIURL: string; // Iframe API endpoint
|
|
335
|
+
password: string; // Agent password for authentication
|
|
336
|
+
accessToken?: string; // Pre-provided access token (optional)
|
|
337
|
+
}
|
|
338
|
+
```
|
|
286
339
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
340
|
+
If `baseURL` is not provided, the SDK falls back to `window.location.origin`.
|
|
341
|
+
|
|
342
|
+
### π Permission-Based Controls
|
|
343
|
+
|
|
344
|
+
The SDK implements a **fail-closed** permission model. After authentication, the backend returns entitlements that automatically determine which controls are enabled:
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
// Entitlements structure from login response
|
|
348
|
+
{
|
|
349
|
+
calls: {
|
|
350
|
+
enabled: boolean,
|
|
351
|
+
items: [
|
|
352
|
+
{ code: "call_inbound", enabled: boolean },
|
|
353
|
+
{ code: "call_outbound", enabled: boolean }
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
call_transfer: {
|
|
357
|
+
enabled: boolean,
|
|
358
|
+
items: [
|
|
359
|
+
{ code: "call_transfer_blind", enabled: boolean },
|
|
360
|
+
{ code: "call_transfer_attended", enabled: boolean },
|
|
361
|
+
{ code: "call_transfer_warm", enabled: boolean }
|
|
362
|
+
]
|
|
363
|
+
},
|
|
364
|
+
call_conference: {
|
|
365
|
+
enabled: boolean,
|
|
366
|
+
items: [
|
|
367
|
+
{ code: "call_conference", enabled: boolean }
|
|
368
|
+
]
|
|
369
|
+
}
|
|
298
370
|
}
|
|
299
371
|
```
|
|
300
372
|
|
|
301
|
-
|
|
373
|
+
If permissions have not been loaded, **all controls are disabled by default**.
|
|
302
374
|
|
|
303
|
-
|
|
375
|
+
You can use the exported `SDK_PERMISSIONS` constants to reference permission codes:
|
|
304
376
|
|
|
305
|
-
```
|
|
306
|
-
import {
|
|
377
|
+
```typescript
|
|
378
|
+
import { SDK_PERMISSIONS } from "ahs-cti";
|
|
307
379
|
|
|
308
|
-
|
|
309
|
-
|
|
380
|
+
// Permission categories
|
|
381
|
+
SDK_PERMISSIONS.CALLS; // "calls"
|
|
382
|
+
SDK_PERMISSIONS.CALL_TRANSFER; // "call_transfer"
|
|
383
|
+
SDK_PERMISSIONS.CALL_CONFERENCE; // "call_conference"
|
|
310
384
|
|
|
311
|
-
|
|
312
|
-
|
|
385
|
+
// Permission codes
|
|
386
|
+
SDK_PERMISSIONS.CALL_INBOUND; // "call_inbound"
|
|
387
|
+
SDK_PERMISSIONS.CALL_OUTBOUND; // "call_outbound"
|
|
388
|
+
SDK_PERMISSIONS.TRANSFER_BLIND; // "call_transfer_blind"
|
|
389
|
+
SDK_PERMISSIONS.TRANSFER_ATTENDED; // "call_transfer_attended"
|
|
390
|
+
SDK_PERMISSIONS.TRANSFER_WARM; // "call_transfer_warm"
|
|
391
|
+
SDK_PERMISSIONS.CONFERENCE; // "call_conference"
|
|
313
392
|
```
|
|
314
393
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
## π§ Configuration Options
|
|
394
|
+
### π Configuration Merge Priority
|
|
318
395
|
|
|
319
|
-
|
|
396
|
+
The SDK merges configuration from three sources (highest priority wins):
|
|
320
397
|
|
|
321
|
-
```
|
|
322
|
-
initSDK
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
tenantId: "your-tenant-id",
|
|
326
|
-
agentId: "your-agent-id",
|
|
327
|
-
|
|
328
|
-
// Optional customization
|
|
329
|
-
disableEndCallButton: false, // Hide end call button
|
|
330
|
-
disabledDialButton: false, // Hide dial button
|
|
331
|
-
disableCallTransferButton: false, // Hide transfer button
|
|
332
|
-
disableConferenceButton: false, // Hide conference button
|
|
333
|
-
disableSoftPhone: false, // Hide soft phone iframe
|
|
334
|
-
isDraggable: true, // Enable/disable dragging
|
|
335
|
-
|
|
336
|
-
// Custom styling (Material-UI SxProps)
|
|
337
|
-
disabled: { opacity: 0.5 }, // Disabled button styles
|
|
338
|
-
enabled: { color: "primary" }, // Enabled button styles
|
|
339
|
-
outlined: { border: "1px solid" }, // Outlined button styles
|
|
340
|
-
});
|
|
398
|
+
```
|
|
399
|
+
1. Explicit sdkConfig (passed to initSDK) <- Highest priority
|
|
400
|
+
2. Permission-based controls (from entitlements) <- Medium priority
|
|
401
|
+
3. Backend callControls (from login response) <- Lowest priority
|
|
341
402
|
```
|
|
342
403
|
|
|
343
|
-
|
|
404
|
+
This means:
|
|
344
405
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
| `disabledDialButton` | `boolean` | `false` | Hide the "Dial" button |
|
|
349
|
-
| `disableCallTransferButton` | `boolean` | `false` | Hide the "Call Transfer" button |
|
|
350
|
-
| `disableConferenceButton` | `boolean` | `false` | Hide the "Conference" button |
|
|
351
|
-
| `disableSoftPhone` | `boolean` | `false` | Hide the embedded soft phone |
|
|
352
|
-
| `isDraggable` | `boolean` | `true` | Enable/disable panel dragging |
|
|
353
|
-
| `disabled` | `SxProps` | - | Custom styles for disabled states |
|
|
354
|
-
| `enabled` | `SxProps` | - | Custom styles for enabled states |
|
|
355
|
-
| `outlined` | `SxProps` | - | Custom styles for outlined states |
|
|
406
|
+
- Backend defaults set the baseline configuration
|
|
407
|
+
- Entitlements override backend defaults based on the agent's permissions
|
|
408
|
+
- Explicit `sdkConfig` overrides everything, allowing host applications to force-enable or force-disable features
|
|
356
409
|
|
|
357
410
|
---
|
|
358
411
|
|
|
@@ -360,126 +413,204 @@ initSDK({
|
|
|
360
413
|
|
|
361
414
|
### π§ **Core Functions**
|
|
362
415
|
|
|
363
|
-
#### `initSDK(
|
|
416
|
+
#### `initSDK(params)`
|
|
364
417
|
|
|
365
|
-
Initialize the SDK with
|
|
418
|
+
Initialize the SDK with credentials and configuration. **Must be called before using any components or hooks.** Returns a `Promise<void>`.
|
|
366
419
|
|
|
367
|
-
```
|
|
368
|
-
initSDK({
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
420
|
+
```typescript
|
|
421
|
+
await initSDK({
|
|
422
|
+
apiKey: string, // β
Required - API key for authentication
|
|
423
|
+
tenantId: string, // β
Required - Tenant identifier
|
|
424
|
+
agentId: string, // β
Required - Agent identifier
|
|
425
|
+
sessionId?: string, // π Optional - Session identifier
|
|
426
|
+
urlConfig?: URLConfig, // π Optional - URL configuration for endpoints
|
|
427
|
+
sdkConfig?: SDKConfig, // π Optional - Feature configuration overrides
|
|
373
428
|
});
|
|
374
429
|
```
|
|
375
430
|
|
|
431
|
+
#### `isSDKInitialized()`
|
|
432
|
+
|
|
433
|
+
Check if the SDK has been successfully initialized.
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
const initialized: boolean = isSDKInitialized();
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### `getSDKVersion()`
|
|
440
|
+
|
|
441
|
+
Get the current SDK version.
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
const version: string = getSDKVersion();
|
|
445
|
+
```
|
|
446
|
+
|
|
376
447
|
#### `CallControlPanel`
|
|
377
448
|
|
|
378
449
|
Draggable control panel component for call management.
|
|
379
450
|
|
|
380
451
|
```tsx
|
|
381
452
|
<CallControlPanel
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
453
|
+
onDataChange={(data: CallData) => {
|
|
454
|
+
// Called when call status, phone number, or any call data changes
|
|
455
|
+
}}
|
|
385
456
|
/>
|
|
386
457
|
```
|
|
387
458
|
|
|
388
459
|
### πͺ **React Hooks**
|
|
389
460
|
|
|
390
|
-
|
|
461
|
+
| Hook | Description | Returns |
|
|
462
|
+
| --------------------------- | -------------------------------------------- | ----------------------------------------------------------- |
|
|
463
|
+
| `useClickToCall()` | Initiate outbound calls | `{ handleStartCall, isLoading, isSuccess, isError, error }` |
|
|
464
|
+
| `useEndCall()` | End active calls with disposition | `{ handleEndCall, isLoading, isSuccess, isError, error }` |
|
|
465
|
+
| `useLogout()` | Agent logout | `{ logout, isLoading, isSuccess, isError, error }` |
|
|
466
|
+
| `useGetCallerData()` | Reactive access to current call data | `CallData` |
|
|
467
|
+
| `useSDKState()` | Subscribe to full SDK state changes | `SDKState` |
|
|
468
|
+
| `useGetAuthorizationToken()`| Get the current access token | `string \| undefined` |
|
|
391
469
|
|
|
392
|
-
|
|
470
|
+
---
|
|
393
471
|
|
|
394
|
-
|
|
395
|
-
const { logout, isLoading, isSuccess, isError, error } = useLogout();
|
|
472
|
+
## π WebSocket Events
|
|
396
473
|
|
|
397
|
-
|
|
398
|
-
logout();
|
|
474
|
+
The SDK connects to a WebSocket for real-time call events:
|
|
399
475
|
|
|
400
|
-
// Returns:
|
|
401
|
-
// - logout: () => void - Function to trigger logout
|
|
402
|
-
// - isLoading: boolean - Loading state
|
|
403
|
-
// - isSuccess: boolean - Success state
|
|
404
|
-
// - isError: boolean - Error state
|
|
405
|
-
// - error: any - Error object if failed
|
|
406
476
|
```
|
|
407
|
-
|
|
408
|
-
#### `useClickToCall()`
|
|
409
|
-
|
|
410
|
-
Hook for initiating calls to mobile numbers.
|
|
411
|
-
|
|
412
|
-
```tsx
|
|
413
|
-
const { handleStartCall, isLoading, isSuccess, isError, error, data } = useClickToCall();
|
|
414
|
-
|
|
415
|
-
// Usage:
|
|
416
|
-
handleStartCall({ mobileNumber: "1234567890" });
|
|
417
|
-
|
|
418
|
-
// Returns:
|
|
419
|
-
// - handleStartCall: (payload: StartCallPayload) => void
|
|
420
|
-
// - isLoading: boolean - Loading state
|
|
421
|
-
// - isSuccess: boolean - Success state
|
|
422
|
-
// - isError: boolean - Error state
|
|
423
|
-
// - error: any - Error object if failed
|
|
424
|
-
// - data: any - API response on success
|
|
477
|
+
WebSocket URL: {urlConfig.webSocketURL}/api/v1/ws/agent/events?token={accessToken}
|
|
425
478
|
```
|
|
426
479
|
|
|
427
|
-
|
|
480
|
+
**Connection behavior:**
|
|
481
|
+
- Auto-reconnects with exponential backoff (base: 2s, max: 30s, up to 60 attempts)
|
|
482
|
+
- Sends ping every 30 seconds to keep the connection alive
|
|
483
|
+
|
|
484
|
+
**Event data structure:**
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
{
|
|
488
|
+
agent_id: number;
|
|
489
|
+
status: CallStatus; // IDLE, READY, ONCALL, RINGING, DIALING, WRAPUP, etc.
|
|
490
|
+
type: string; // Call type
|
|
491
|
+
event_time: string;
|
|
492
|
+
phone_number: string;
|
|
493
|
+
convox_id: string;
|
|
494
|
+
process_id: number;
|
|
495
|
+
process_name: string;
|
|
496
|
+
hold: number; // 0 = not held, 1 = held
|
|
497
|
+
mute: number; // 0 = not muted, 1 = muted
|
|
498
|
+
mode: string; // 'manual' or automated
|
|
499
|
+
queue_name: string;
|
|
500
|
+
conferencestatus?: { // Present during conference calls
|
|
501
|
+
line_1_status: string;
|
|
502
|
+
line_1_phonenumber: string;
|
|
503
|
+
line_2_status: string;
|
|
504
|
+
line_2_phonenumber: string;
|
|
505
|
+
// ... up to line 5
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
```
|
|
428
509
|
|
|
429
|
-
|
|
510
|
+
---
|
|
430
511
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
512
|
+
## π¦ Data Types
|
|
513
|
+
|
|
514
|
+
### `CallStatus` Enum
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
enum CallStatus {
|
|
518
|
+
IDLE = "IDLE",
|
|
519
|
+
READY = "READY",
|
|
520
|
+
BREAK = "BREAK",
|
|
521
|
+
ONCALL = "ONCALL",
|
|
522
|
+
WRAPUP = "WRAPUP",
|
|
523
|
+
RINGING = "RINGING",
|
|
524
|
+
DIALING = "DIALING",
|
|
525
|
+
MISSED = "MISSED",
|
|
526
|
+
HOLD = "HOLD",
|
|
527
|
+
UNHOLD = "UNHOLD",
|
|
528
|
+
MUTE = "MUTE",
|
|
529
|
+
UNMUTE = "UNMUTE",
|
|
530
|
+
DISCONNECTED = "DISCONNECTED",
|
|
531
|
+
CONFERENCE = "CONFERENCE",
|
|
532
|
+
}
|
|
444
533
|
```
|
|
445
534
|
|
|
446
|
-
|
|
535
|
+
### `CallData`
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
interface CallData {
|
|
539
|
+
mobileNumber?: string;
|
|
540
|
+
callReferenceId?: string;
|
|
541
|
+
convoxId?: string;
|
|
542
|
+
type?: string;
|
|
543
|
+
status: string;
|
|
544
|
+
agent_id: number;
|
|
545
|
+
phone_number?: string;
|
|
546
|
+
event_time?: string;
|
|
547
|
+
convox_id?: string;
|
|
548
|
+
process_id?: string;
|
|
549
|
+
process_name?: string;
|
|
550
|
+
mode?: string;
|
|
551
|
+
queue_name?: string;
|
|
552
|
+
mute?: number; // 1 = muted, 0 = unmuted
|
|
553
|
+
hold?: number; // 1 = on hold, 0 = not on hold
|
|
554
|
+
}
|
|
555
|
+
```
|
|
447
556
|
|
|
448
|
-
|
|
557
|
+
### `ConferenceLineTypes`
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
type ConferenceLineTypes = {
|
|
561
|
+
line: number; // Line number (1-5)
|
|
562
|
+
status: string; // ONCALL, IDLE, LINE USED, etc.
|
|
563
|
+
type: "external" | "internal" | "";
|
|
564
|
+
phone: string;
|
|
565
|
+
isMute: boolean;
|
|
566
|
+
isHold: boolean;
|
|
567
|
+
isCallStart: boolean;
|
|
568
|
+
isMergeCall: boolean;
|
|
569
|
+
};
|
|
570
|
+
```
|
|
449
571
|
|
|
450
572
|
### `StartCallPayload`
|
|
451
573
|
|
|
452
|
-
```
|
|
574
|
+
```typescript
|
|
453
575
|
interface StartCallPayload {
|
|
454
|
-
|
|
576
|
+
mobileNumber?: string;
|
|
455
577
|
}
|
|
456
578
|
```
|
|
457
579
|
|
|
458
580
|
### `EndCallPayload`
|
|
459
581
|
|
|
460
|
-
```
|
|
582
|
+
```typescript
|
|
461
583
|
interface EndCallPayload {
|
|
462
|
-
|
|
584
|
+
disposition?: string; // Default: "RES"
|
|
463
585
|
}
|
|
464
586
|
```
|
|
465
587
|
|
|
466
588
|
---
|
|
467
589
|
|
|
468
|
-
##
|
|
590
|
+
## π€ Exported Types
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
// Types
|
|
594
|
+
export type { CallData, CallControlPanelProps, SDKConfig, URLConfig };
|
|
595
|
+
export type { SDKPermissionState, ControlsFromPermissions, SDKPermissionContextValue };
|
|
596
|
+
export type { RequestResult, RequestOptions };
|
|
597
|
+
export type { UseGetRequest, UsePostRequest, UsePutRequest, UseDeleteRequest, UsePatchRequest };
|
|
469
598
|
|
|
470
|
-
|
|
599
|
+
// Enum
|
|
600
|
+
export { CallStatus };
|
|
471
601
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
- **End Call** - Terminate calls with disposition tracking
|
|
475
|
-
- **Agent Status** - Switch between Idle/Break states
|
|
602
|
+
// Constants
|
|
603
|
+
export { SDK_PERMISSIONS };
|
|
476
604
|
|
|
477
|
-
|
|
605
|
+
// Functions
|
|
606
|
+
export { initSDK, getSDKVersion, isSDKInitialized };
|
|
478
607
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
608
|
+
// Hooks
|
|
609
|
+
export { useLogout, useEndCall, useClickToCall, useGetCallerData, useGetAuthorizationToken, useSDKState };
|
|
610
|
+
|
|
611
|
+
// Components
|
|
612
|
+
export { CallControlPanel };
|
|
613
|
+
```
|
|
483
614
|
|
|
484
615
|
---
|
|
485
616
|
|
|
@@ -487,8 +618,8 @@ interface EndCallPayload {
|
|
|
487
618
|
|
|
488
619
|
<div align="left">
|
|
489
620
|
|
|
490
|
-
| Browser | Version | Status
|
|
491
|
-
| ----------------------------------------------------------------------------- | ------- |
|
|
621
|
+
| Browser | Version | Status |
|
|
622
|
+
| ----------------------------------------------------------------------------- | ------- | ---------- |
|
|
492
623
|
|  | 60+ | β
Supported |
|
|
493
624
|
|  | 60+ | β
Supported |
|
|
494
625
|
|  | 12+ | β
Supported |
|