@vgroup/dialbox 0.0.83 → 0.0.85
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/esm2020/lib/components/call-progress/incoming-call/incoming-call.component.mjs +52 -31
- package/esm2020/lib/dialbox.component.mjs +3 -33
- package/esm2020/lib/service/twilio.service.mjs +53 -83
- package/fesm2015/vgroup-dialbox.mjs +104 -142
- package/fesm2015/vgroup-dialbox.mjs.map +1 -1
- package/fesm2020/vgroup-dialbox.mjs +103 -143
- package/fesm2020/vgroup-dialbox.mjs.map +1 -1
- package/lib/components/call-progress/incoming-call/incoming-call.component.d.ts +6 -2
- package/lib/dialbox.component.d.ts +0 -2
- package/lib/service/twilio.service.d.ts +8 -7
- package/package.json +1 -1
|
@@ -2,11 +2,11 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { Injectable, EventEmitter, Component, Input, Output, ViewChild, Inject, NgModule } from '@angular/core';
|
|
3
3
|
import swal from 'sweetalert2';
|
|
4
4
|
import { AsYouType } from 'libphonenumber-js';
|
|
5
|
-
import { throwError, BehaviorSubject,
|
|
5
|
+
import { throwError, BehaviorSubject, of, Subscription, filter, interval } from 'rxjs';
|
|
6
6
|
import * as i1 from '@angular/common/http';
|
|
7
7
|
import { HttpHeaders, HttpParams, HttpClientModule } from '@angular/common/http';
|
|
8
|
+
import { catchError, switchMap, map, tap, shareReplay } from 'rxjs/operators';
|
|
8
9
|
import { Device } from '@twilio/voice-sdk';
|
|
9
|
-
import { catchError, switchMap, map } from 'rxjs/operators';
|
|
10
10
|
import * as i3$1 from '@angular/material/dialog';
|
|
11
11
|
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
12
12
|
import * as i5 from '@angular/router';
|
|
@@ -1387,85 +1387,60 @@ class TwilioService {
|
|
|
1387
1387
|
this.isAvailableNumber = new BehaviorSubject(false);
|
|
1388
1388
|
this.callerIdList = new BehaviorSubject([]);
|
|
1389
1389
|
this.triggerSMSReload = new BehaviorSubject(false);
|
|
1390
|
-
this.
|
|
1391
|
-
this.
|
|
1392
|
-
|
|
1393
|
-
this.
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
this.
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1390
|
+
this.tokenInitialized = false;
|
|
1391
|
+
this.tokenInitialization$ = null;
|
|
1392
|
+
this.lastCallSid = null;
|
|
1393
|
+
this.lastCallTime = 0;
|
|
1394
|
+
this.CALL_DEBOUNCE_MS = 1000; // 1 second debounce
|
|
1395
|
+
this.initializeToken();
|
|
1396
|
+
}
|
|
1397
|
+
initializeToken() {
|
|
1398
|
+
if (this.tokenInitialized) {
|
|
1399
|
+
return this.tokenInitialization$ || of(null);
|
|
1400
|
+
}
|
|
1401
|
+
this.tokenInitialization$ = this.extensionService.getIncomingCallToken().pipe(tap((data) => {
|
|
1402
|
+
this.incomingCallToken = data.token;
|
|
1403
|
+
localStorage.setItem('in-token', data.token);
|
|
1404
|
+
this.tokenInitialized = true;
|
|
1405
|
+
this.initializeDevice();
|
|
1406
|
+
}), catchError(error => {
|
|
1407
|
+
console.error('Error initializing Twilio token:', error);
|
|
1408
|
+
return throwError(() => error);
|
|
1409
|
+
}), shareReplay(1) // Cache the result for subsequent subscribers
|
|
1410
|
+
);
|
|
1411
|
+
return this.tokenInitialization$;
|
|
1409
1412
|
}
|
|
1410
|
-
|
|
1411
|
-
if (this.
|
|
1412
|
-
|
|
1413
|
+
initializeTwilioDevice() {
|
|
1414
|
+
if (this.tokenInitialized && this.incomingCallToken) {
|
|
1415
|
+
this.initializeDevice();
|
|
1416
|
+
}
|
|
1417
|
+
else {
|
|
1418
|
+
this.initializeToken().subscribe();
|
|
1413
1419
|
}
|
|
1420
|
+
}
|
|
1421
|
+
initializeDevice() {
|
|
1414
1422
|
if (this.device) {
|
|
1415
1423
|
this.device.destroy();
|
|
1416
1424
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
// Prevent multiple initializations
|
|
1420
|
-
if (this.deviceInitialized || this.initializationInProgress || !this.token) {
|
|
1425
|
+
if (!this.incomingCallToken) {
|
|
1426
|
+
console.error('No Twilio token available');
|
|
1421
1427
|
return;
|
|
1422
1428
|
}
|
|
1423
|
-
this.
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
try {
|
|
1427
|
-
this.incomingCallToken = data.token;
|
|
1428
|
-
localStorage.setItem('in-token', data.token);
|
|
1429
|
-
// Destroy existing device if it exists
|
|
1430
|
-
if (this.device) {
|
|
1431
|
-
this.device.destroy();
|
|
1432
|
-
}
|
|
1433
|
-
// Initialize Twilio Device with required options
|
|
1434
|
-
const deviceOptions = {
|
|
1435
|
-
allowIncomingWhileBusy: true,
|
|
1436
|
-
closeProtection: true
|
|
1437
|
-
};
|
|
1438
|
-
// Only add debug in development
|
|
1439
|
-
if (!environment.production) {
|
|
1440
|
-
deviceOptions.debug = false;
|
|
1441
|
-
}
|
|
1442
|
-
this.device = new Device(this.incomingCallToken, deviceOptions);
|
|
1443
|
-
this.device.register();
|
|
1444
|
-
this.deviceInitialized = true;
|
|
1445
|
-
this.initializationInProgress = false;
|
|
1446
|
-
console.log('Twilio Device initialized successfully');
|
|
1447
|
-
this.setupDeviceEventHandlers();
|
|
1448
|
-
}
|
|
1449
|
-
catch (error) {
|
|
1450
|
-
console.error('Error initializing Twilio Device:', error);
|
|
1451
|
-
this.initializationInProgress = false;
|
|
1452
|
-
// Retry after a delay
|
|
1453
|
-
setTimeout(() => this.initializeTwilioDevice(), 5000);
|
|
1454
|
-
}
|
|
1455
|
-
},
|
|
1456
|
-
error: (error) => {
|
|
1457
|
-
console.error('Error getting Twilio token:', error);
|
|
1458
|
-
this.initializationInProgress = false;
|
|
1459
|
-
// Retry after a delay
|
|
1460
|
-
setTimeout(() => this.initializeTwilioDevice(), 5000);
|
|
1461
|
-
}
|
|
1429
|
+
this.device = new Device(this.incomingCallToken, {
|
|
1430
|
+
allowIncomingWhileBusy: true,
|
|
1431
|
+
closeProtection: true
|
|
1462
1432
|
});
|
|
1463
|
-
|
|
1464
|
-
setupDeviceEventHandlers() {
|
|
1465
|
-
if (!this.device)
|
|
1466
|
-
return;
|
|
1433
|
+
this.device.register();
|
|
1467
1434
|
this.device.on('incoming', (call) => {
|
|
1468
|
-
|
|
1435
|
+
const callSid = call.parameters?.['CallSid'];
|
|
1436
|
+
const now = Date.now();
|
|
1437
|
+
// Skip if this is a duplicate call within the debounce window
|
|
1438
|
+
if (callSid && callSid === this.lastCallSid && (now - this.lastCallTime) < this.CALL_DEBOUNCE_MS) {
|
|
1439
|
+
console.log('Skipping duplicate call:', callSid);
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
this.lastCallSid = callSid;
|
|
1443
|
+
this.lastCallTime = now;
|
|
1469
1444
|
this.currentCall.next(call);
|
|
1470
1445
|
this.callType.next('INCOMING');
|
|
1471
1446
|
this.currentCallState.next('incoming');
|
|
@@ -1473,20 +1448,15 @@ class TwilioService {
|
|
|
1473
1448
|
});
|
|
1474
1449
|
this.device.on('error', (error) => {
|
|
1475
1450
|
console.error('Twilio Device Error:', error);
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
if (error.code === 31201 || error.code === 20101) {
|
|
1479
|
-
console.log('Authentication error, reinitializing device...');
|
|
1480
|
-
this.initializeTwilioDevice();
|
|
1481
|
-
}
|
|
1451
|
+
// Reset initialization state on error to allow retry
|
|
1452
|
+
this.tokenInitialized = false;
|
|
1482
1453
|
});
|
|
1483
1454
|
this.device.on('registered', () => {
|
|
1484
|
-
console.log('Twilio Device registered');
|
|
1485
|
-
this.deviceInitialized = true;
|
|
1455
|
+
console.log('Twilio Device registered successfully');
|
|
1486
1456
|
});
|
|
1487
1457
|
this.device.on('unregistered', () => {
|
|
1488
1458
|
console.log('Twilio Device unregistered');
|
|
1489
|
-
this.
|
|
1459
|
+
this.tokenInitialized = false;
|
|
1490
1460
|
});
|
|
1491
1461
|
}
|
|
1492
1462
|
// onIncomingCall(){
|
|
@@ -1610,43 +1580,63 @@ class IncomingCallComponent {
|
|
|
1610
1580
|
this.closeIncomingCallDiv = new EventEmitter();
|
|
1611
1581
|
this.incomingCallsNewList = new EventEmitter();
|
|
1612
1582
|
this.selectedIncomingCallInfo = new EventEmitter();
|
|
1583
|
+
this.subscription = new Subscription();
|
|
1584
|
+
this.callHandled = new Set(); // Track handled calls by CallSid
|
|
1613
1585
|
}
|
|
1614
1586
|
ngOnInit() {
|
|
1615
|
-
// this.twilioService.currentCall.subscribe((call: any) => {
|
|
1616
|
-
// if (call) {
|
|
1617
|
-
// this.twilioCallData = call;
|
|
1618
|
-
// this.notificationSerivce.showNotification(call);
|
|
1619
|
-
// // Handle the call UI
|
|
1620
|
-
// }
|
|
1621
|
-
// });
|
|
1622
1587
|
try {
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
if (this.incomingCallData && this.incomingCallData.parameters && this.incomingCallData.parameters.CallSid) {
|
|
1639
|
-
this.newIncomingCallsList = this.newIncomingCallsList.filter((item) => item.parameters && item.parameters.CallSid !== this.incomingCallData.parameters.CallSid);
|
|
1640
|
-
}
|
|
1641
|
-
this.rejectCallFromList(call);
|
|
1642
|
-
});
|
|
1643
|
-
}
|
|
1644
|
-
});
|
|
1588
|
+
// Only handle the call if we have incomingCallData
|
|
1589
|
+
if (this.incomingCallData) {
|
|
1590
|
+
this.handleIncomingCall(this.incomingCallData);
|
|
1591
|
+
}
|
|
1592
|
+
// Subscribe to new calls
|
|
1593
|
+
this.subscription.add(this.twilioService.currentCall.pipe(
|
|
1594
|
+
// Filter out duplicate calls that we've already handled
|
|
1595
|
+
filter((call) => {
|
|
1596
|
+
if (!call)
|
|
1597
|
+
return false;
|
|
1598
|
+
const callSid = call.parameters['CallSid'];
|
|
1599
|
+
return callSid && !this.callHandled.has(callSid);
|
|
1600
|
+
})).subscribe(call => {
|
|
1601
|
+
this.handleIncomingCall(call);
|
|
1602
|
+
}));
|
|
1645
1603
|
}
|
|
1646
1604
|
catch (e) {
|
|
1647
|
-
console.
|
|
1605
|
+
console.error('Error in incoming call handling:', e);
|
|
1648
1606
|
}
|
|
1649
1607
|
}
|
|
1608
|
+
handleIncomingCall(call) {
|
|
1609
|
+
if (!call)
|
|
1610
|
+
return;
|
|
1611
|
+
const callSid = call.parameters?.CallSid;
|
|
1612
|
+
if (!callSid || this.callHandled.has(callSid)) {
|
|
1613
|
+
return; // Skip if no CallSid or already handled
|
|
1614
|
+
}
|
|
1615
|
+
this.callHandled.add(callSid);
|
|
1616
|
+
this.twilioCallData = call;
|
|
1617
|
+
this.twilioAuthId = call.customParameters?.get('twilioAuthId');
|
|
1618
|
+
if (!call.parameters) {
|
|
1619
|
+
call.parameters = {};
|
|
1620
|
+
}
|
|
1621
|
+
// Send IP for the incoming call
|
|
1622
|
+
this.sendIPforIncomingCall(this.twilioAuthId, '');
|
|
1623
|
+
// Setup call event handlers
|
|
1624
|
+
const handleCallEnd = () => {
|
|
1625
|
+
if (callSid) {
|
|
1626
|
+
this.callHandled.delete(callSid);
|
|
1627
|
+
if (this.newIncomingCallsList) {
|
|
1628
|
+
this.newIncomingCallsList = this.newIncomingCallsList.filter((item) => item.parameters?.CallSid !== callSid);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
this.rejectCallFromList(call);
|
|
1632
|
+
};
|
|
1633
|
+
call.on('cancel', handleCallEnd);
|
|
1634
|
+
call.on('disconnect', handleCallEnd);
|
|
1635
|
+
}
|
|
1636
|
+
ngOnDestroy() {
|
|
1637
|
+
this.subscription.unsubscribe();
|
|
1638
|
+
this.callHandled.clear();
|
|
1639
|
+
}
|
|
1650
1640
|
acceptCallFromList(data) {
|
|
1651
1641
|
data.accept();
|
|
1652
1642
|
// data.parameters['isCallConnected'] = true;
|
|
@@ -2283,28 +2273,7 @@ class DialboxComponent {
|
|
|
2283
2273
|
return;
|
|
2284
2274
|
this.token = localStorage.getItem('ext_token') || '';
|
|
2285
2275
|
if (!this.token) {
|
|
2286
|
-
console.
|
|
2287
|
-
// Clear any existing interval to prevent multiple intervals
|
|
2288
|
-
if (this.twilioInitializationInterval) {
|
|
2289
|
-
clearInterval(this.twilioInitializationInterval);
|
|
2290
|
-
}
|
|
2291
|
-
// Set up a check for when token becomes available
|
|
2292
|
-
this.twilioInitializationInterval = setInterval(() => {
|
|
2293
|
-
const newToken = localStorage.getItem('ext_token');
|
|
2294
|
-
if (newToken) {
|
|
2295
|
-
clearInterval(this.twilioInitializationInterval);
|
|
2296
|
-
this.token = newToken;
|
|
2297
|
-
this.initializeTwilio();
|
|
2298
|
-
}
|
|
2299
|
-
}, 2000);
|
|
2300
|
-
// Add cleanup for this interval
|
|
2301
|
-
this.subscriptions.add({
|
|
2302
|
-
unsubscribe: () => {
|
|
2303
|
-
if (this.twilioInitializationInterval) {
|
|
2304
|
-
clearInterval(this.twilioInitializationInterval);
|
|
2305
|
-
}
|
|
2306
|
-
}
|
|
2307
|
-
});
|
|
2276
|
+
console.error('No authentication token found');
|
|
2308
2277
|
return;
|
|
2309
2278
|
}
|
|
2310
2279
|
this.isInitialized = true;
|
|
@@ -2423,10 +2392,8 @@ class DialboxComponent {
|
|
|
2423
2392
|
// }
|
|
2424
2393
|
ngOnInit() {
|
|
2425
2394
|
try {
|
|
2426
|
-
// Initialize Twilio when component loads
|
|
2427
|
-
this.initializeTwilio();
|
|
2428
|
-
// Get token and load initial data
|
|
2429
2395
|
this.token = localStorage.getItem('ext_token') || '';
|
|
2396
|
+
//this.isCallInProgress = true;
|
|
2430
2397
|
this.getContactList();
|
|
2431
2398
|
this.getUserCallSetting();
|
|
2432
2399
|
const sub1 = this.twilioService.dialNumberFromOtherModule.subscribe((contact) => {
|
|
@@ -3285,13 +3252,6 @@ class DialboxComponent {
|
|
|
3285
3252
|
if (this.subscriptions) {
|
|
3286
3253
|
this.subscriptions.unsubscribe();
|
|
3287
3254
|
}
|
|
3288
|
-
// Clear any active intervals
|
|
3289
|
-
if (this.tokenCheckInterval) {
|
|
3290
|
-
clearInterval(this.tokenCheckInterval);
|
|
3291
|
-
}
|
|
3292
|
-
if (this.twilioInitializationInterval) {
|
|
3293
|
-
clearInterval(this.twilioInitializationInterval);
|
|
3294
|
-
}
|
|
3295
3255
|
// Clean up Twilio device when component is destroyed
|
|
3296
3256
|
if (this.twilioService['device']) {
|
|
3297
3257
|
this.twilioService['device'].destroy();
|