amazon-connect-reference-dialer 1.0.0 → 1.4.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.
Potentially problematic release.
This version of amazon-connect-reference-dialer might be problematic. Click here for more details.
- package/.babelrc +10 -0
- package/.eslintrc +24 -0
- package/Dockerfile +12 -0
- package/LICENSE +21 -0
- package/README.md +8 -0
- package/README.salesforce.md +50 -0
- package/config/appconfig.json +10 -0
- package/config/config.js +46 -0
- package/docker-compose.yml +16 -0
- package/index.js +46 -0
- package/nodemon.json +3 -0
- package/package.json +5 -4
- package/src/client/App.js +20 -0
- package/src/client/api/acManager.js +79 -0
- package/src/client/api/agentHandler.js +46 -0
- package/src/client/api/audioFrequencyMonitor.js +62 -0
- package/src/client/api/csioHandler.js +204 -0
- package/src/client/api/databaseManager.js +59 -0
- package/src/client/api/eventhandler.js +278 -0
- package/src/client/api/feedbackHandler.js +21 -0
- package/src/client/api/manager/agent.js +203 -0
- package/src/client/api/manager/connection.js +181 -0
- package/src/client/api/manager/contact.js +114 -0
- package/src/client/api/mediaManager.js +138 -0
- package/src/client/api/networkStrengthMonitor.js +64 -0
- package/src/client/api/precalltest.js +37 -0
- package/src/client/api/sessionManager.js +312 -0
- package/src/client/configs/consts.js +158 -0
- package/src/client/container/agentduration/duration.js +63 -0
- package/src/client/container/agentduration/index.js +3 -0
- package/src/client/container/agentview/conferenceconnection/agentview.css +100 -0
- package/src/client/container/agentview/conferenceconnection/components/bothhold.js +20 -0
- package/src/client/container/agentview/conferenceconnection/components/bothjoined.js +25 -0
- package/src/client/container/agentview/conferenceconnection/components/dialnumber.js +21 -0
- package/src/client/container/agentview/conferenceconnection/components/holdall.js +20 -0
- package/src/client/container/agentview/conferenceconnection/components/join.js +21 -0
- package/src/client/container/agentview/conferenceconnection/components/oneHoldOtherConnected.js +37 -0
- package/src/client/container/agentview/conferenceconnection/components/resumeall.js +21 -0
- package/src/client/container/agentview/conferenceconnection/components/swap.js +21 -0
- package/src/client/container/agentview/conferenceconnection/components/togglemute.js +23 -0
- package/src/client/container/agentview/conferenceconnection/index.js +3 -0
- package/src/client/container/agentview/conferenceconnection/lowerBody.js +154 -0
- package/src/client/container/agentview/conferenceconnection/main.js +22 -0
- package/src/client/container/agentview/conferenceconnection/primaryconnection.js +109 -0
- package/src/client/container/agentview/conferenceconnection/quickFeedback.js +118 -0
- package/src/client/container/agentview/conferenceconnection/thirdpartyconnection.js +107 -0
- package/src/client/container/agentview/conferenceconnection/upperBody.js +36 -0
- package/src/client/container/agentview/footer.js +190 -0
- package/src/client/container/agentview/index.js +3 -0
- package/src/client/container/agentview/main.js +39 -0
- package/src/client/container/agentview/primaryconnection/agentMutedLabel.js +23 -0
- package/src/client/container/agentview/primaryconnection/agentStatusAndAudioLabel.js +28 -0
- package/src/client/container/agentview/primaryconnection/agentview.css +73 -0
- package/src/client/container/agentview/primaryconnection/index.js +3 -0
- package/src/client/container/agentview/primaryconnection/lowerBody.js +159 -0
- package/src/client/container/agentview/primaryconnection/main.js +22 -0
- package/src/client/container/agentview/primaryconnection/peerAndAgentDuration.js +48 -0
- package/src/client/container/agentview/primaryconnection/quickFeedback.js +123 -0
- package/src/client/container/agentview/primaryconnection/upperBody.js +59 -0
- package/src/client/container/agentview/thirdparyconnection/agentMutedLabel.js +23 -0
- package/src/client/container/agentview/thirdparyconnection/agentStatusAndAudioLabel.js +28 -0
- package/src/client/container/agentview/thirdparyconnection/agentview.css +73 -0
- package/src/client/container/agentview/thirdparyconnection/index.js +3 -0
- package/src/client/container/agentview/thirdparyconnection/lowerBody.js +139 -0
- package/src/client/container/agentview/thirdparyconnection/main.js +22 -0
- package/src/client/container/agentview/thirdparyconnection/peerAndAgentDuration.js +49 -0
- package/src/client/container/agentview/thirdparyconnection/quickFeedback.js +118 -0
- package/src/client/container/agentview/thirdparyconnection/upperBody.js +59 -0
- package/src/client/container/audiolabelview/controller.js +104 -0
- package/src/client/container/audiolabelview/localaudiolevel.js +157 -0
- package/src/client/container/audiolabelview/noaudio.js +86 -0
- package/src/client/container/audiolabelview/remoteaudiolevel.js +110 -0
- package/src/client/container/audiolabelview/settingpageaudiolevel.js +154 -0
- package/src/client/container/common/contactField.js +30 -0
- package/src/client/container/common/each.contact.js +41 -0
- package/src/client/container/common/findContact.js +31 -0
- package/src/client/container/connectivitycheckview/body.js +113 -0
- package/src/client/container/connectivitycheckview/components/fractionalLoss.js +57 -0
- package/src/client/container/connectivitycheckview/components/mediaConnectivity.js +41 -0
- package/src/client/container/connectivitycheckview/components/roundTripTime.js +57 -0
- package/src/client/container/connectivitycheckview/components/rttgraph/rttgraph.js +176 -0
- package/src/client/container/connectivitycheckview/components/rttgraph/utils.js +96 -0
- package/src/client/container/connectivitycheckview/components/throughput.js +53 -0
- package/src/client/container/connectivitycheckview/components/throughputMessage.js +36 -0
- package/src/client/container/connectivitycheckview/connectivitycheck.css +44 -0
- package/src/client/container/connectivitycheckview/footer.js +43 -0
- package/src/client/container/connectivitycheckview/index.js +3 -0
- package/src/client/container/connectivitycheckview/loading/loading.css +73 -0
- package/src/client/container/connectivitycheckview/loading/loading.js +15 -0
- package/src/client/container/connectivitycheckview/main.js +19 -0
- package/src/client/container/dialerview/body.js +135 -0
- package/src/client/container/dialerview/dialpad.css +104 -0
- package/src/client/container/dialerview/dialpad.js +29 -0
- package/src/client/container/dialerview/index.js +3 -0
- package/src/client/container/dialerview/main.js +19 -0
- package/src/client/container/errors/error.css +30 -0
- package/src/client/container/errors/error.js +58 -0
- package/src/client/container/errors/index.js +3 -0
- package/src/client/container/footer/components/acceptOrReject.js +26 -0
- package/src/client/container/footer/components/availableOrEnd.js +28 -0
- package/src/client/container/footer/components/connectivitycheck.js +21 -0
- package/src/client/container/footer/components/downloadlogs.js +23 -0
- package/src/client/container/footer/components/info.js +22 -0
- package/src/client/container/footer/components/language.js +22 -0
- package/src/client/container/footer/components/reportcall.js +35 -0
- package/src/client/container/footer/components/version.js +22 -0
- package/src/client/container/header/header.css +46 -0
- package/src/client/container/header/header.js +135 -0
- package/src/client/container/header/index.js +3 -0
- package/src/client/container/home.js +129 -0
- package/src/client/container/login/body.js +67 -0
- package/src/client/container/login/ccpinputbox.js +23 -0
- package/src/client/container/login/footer.js +19 -0
- package/src/client/container/login/index.js +2 -0
- package/src/client/container/login/login.css +134 -0
- package/src/client/container/login/main.js +23 -0
- package/src/client/container/networkstrengthview/index.js +3 -0
- package/src/client/container/networkstrengthview/loading/loading.css +74 -0
- package/src/client/container/networkstrengthview/loading/loading.js +15 -0
- package/src/client/container/networkstrengthview/networkstrength.js +102 -0
- package/src/client/container/popups/confirmreport/confirmreport.css +47 -0
- package/src/client/container/popups/confirmreport/confirmreport.js +55 -0
- package/src/client/container/popups/quality/quality.css +32 -0
- package/src/client/container/popups/quality/quality.js +44 -0
- package/src/client/container/quickconnects/body.js +141 -0
- package/src/client/container/quickconnects/close.js +23 -0
- package/src/client/container/quickconnects/index.js +3 -0
- package/src/client/container/quickconnects/main.js +18 -0
- package/src/client/container/quickconnects/quickconnects.css +95 -0
- package/src/client/container/reportissueview/body.js +73 -0
- package/src/client/container/reportissueview/feedbackRatings.js +37 -0
- package/src/client/container/reportissueview/footer.js +20 -0
- package/src/client/container/reportissueview/index.js +3 -0
- package/src/client/container/reportissueview/issueNotes.js +22 -0
- package/src/client/container/reportissueview/issues.js +44 -0
- package/src/client/container/reportissueview/main.js +105 -0
- package/src/client/container/reportissueview/predefinedIssues.js +38 -0
- package/src/client/container/reportissueview/reportissue.css +102 -0
- package/src/client/container/settingsview/body.js +156 -0
- package/src/client/container/settingsview/components/audiooutputdevice.js +25 -0
- package/src/client/container/settingsview/components/deskphone.js +29 -0
- package/src/client/container/settingsview/components/desktopsettings.js +38 -0
- package/src/client/container/settingsview/components/dropdown-options.js +44 -0
- package/src/client/container/settingsview/components/phonetype.js +14 -0
- package/src/client/container/settingsview/components/settings.js +23 -0
- package/src/client/container/settingsview/components/softphone.js +30 -0
- package/src/client/container/settingsview/components/softphonesettings.js +35 -0
- package/src/client/container/settingsview/footer.js +96 -0
- package/src/client/container/settingsview/index.js +3 -0
- package/src/client/container/settingsview/main.js +20 -0
- package/src/client/container/settingsview/settings.css +126 -0
- package/src/client/container/statechangeview/body.js +61 -0
- package/src/client/container/statechangeview/footer.js +43 -0
- package/src/client/container/statechangeview/index.js +3 -0
- package/src/client/container/statechangeview/main.js +21 -0
- package/src/client/container/statechangeview/statuschange.css +47 -0
- package/src/client/container/transfercall/body.js +139 -0
- package/src/client/container/transfercall/close.js +23 -0
- package/src/client/container/transfercall/index.js +3 -0
- package/src/client/container/transfercall/main.js +18 -0
- package/src/client/container/transfercall/transfercall.css +99 -0
- package/src/client/index.js +13 -0
- package/src/client/reducers/acReducer.js +277 -0
- package/src/client/reducers/reducer.js +8 -0
- package/src/client/reducers.js +2 -0
- package/src/client/res/images/agent-voice-freq-icon.svg +61 -0
- package/src/client/res/images/change-status-icon.svg +16 -0
- package/src/client/res/images/csio-logo.png +0 -0
- package/src/client/res/images/csioLogo.png +0 -0
- package/src/client/res/images/dialer-setting-icon.svg +15 -0
- package/src/client/res/images/fa-circle-mark.svg +3 -0
- package/src/client/res/images/fa-circle-unmark.svg +3 -0
- package/src/client/res/images/fa-close-or-dismiss.svg +17 -0
- package/src/client/res/images/fa-danger.svg +3 -0
- package/src/client/res/images/fa-dial-button.svg +13 -0
- package/src/client/res/images/fa-dial-number.svg +15 -0
- package/src/client/res/images/fa-download.svg +3 -0
- package/src/client/res/images/fa-hold.svg +13 -0
- package/src/client/res/images/fa-ico-join.svg +27 -0
- package/src/client/res/images/fa-ico-swap.svg +27 -0
- package/src/client/res/images/fa-info.svg +3 -0
- package/src/client/res/images/fa-input-sound.svg +5 -0
- package/src/client/res/images/fa-language.svg +3 -0
- package/src/client/res/images/fa-mark-false.svg +3 -0
- package/src/client/res/images/fa-mark-true.svg +3 -0
- package/src/client/res/images/fa-mic-freq-temporary.gif +0 -0
- package/src/client/res/images/fa-mic.svg +3 -0
- package/src/client/res/images/fa-mini-endcall.svg +48 -0
- package/src/client/res/images/fa-mini-hold.svg +47 -0
- package/src/client/res/images/fa-mini-resume.svg +45 -0
- package/src/client/res/images/fa-mute.svg +13 -0
- package/src/client/res/images/fa-network-strength-1.svg +5 -0
- package/src/client/res/images/fa-network-strength-2.svg +6 -0
- package/src/client/res/images/fa-network-strength-3.svg +6 -0
- package/src/client/res/images/fa-network-strength-4.svg +6 -0
- package/src/client/res/images/fa-network-strength-5.svg +5 -0
- package/src/client/res/images/fa-network-strength-unknown-2.svg +9 -0
- package/src/client/res/images/fa-network-strength-unknown.svg +6 -0
- package/src/client/res/images/fa-quick-connect.svg +15 -0
- package/src/client/res/images/fa-refresh.svg +3 -0
- package/src/client/res/images/fa-resume.svg +3 -0
- package/src/client/res/images/fa-return.svg +3 -0
- package/src/client/res/images/fa-three-dots.svg +32 -0
- package/src/client/res/images/fa-tick-green.svg +3 -0
- package/src/client/res/images/fa-tick-mark.svg +3 -0
- package/src/client/res/images/fa-transfer.svg +3 -0
- package/src/client/res/images/fa-version.svg +4 -0
- package/src/client/res/images/fa-voice-no-freq.svg +5 -0
- package/src/client/res/images/favicon.ico +0 -0
- package/src/client/res/images/muted-icon.svg +13 -0
- package/src/client/res/images/network-strength-icon.svg +13 -0
- package/src/client/res/images/peer-voice-freq-icon.svg +26 -0
- package/src/client/res/images/star-white.svg +6 -0
- package/src/client/res/images/star-yellow.svg +6 -0
- package/src/client/res/scss/global.css +14 -0
- package/src/client/router.js +17 -0
- package/src/client/store.js +11 -0
- package/src/client/utils/acutils.js +114 -0
- package/src/client/utils/agetStateMap.js +36 -0
- package/src/client/utils/feedback.js +3 -0
- package/src/client/utils/initialStateManager.js +14 -0
- package/src/server/index.js +53 -0
- package/src/server/logger.js +93 -0
- package/src/server/public/fonts/AmazonEmber_Lt.ttf +0 -0
- package/src/server/public/fonts/AmazonEmber_Rg.ttf +0 -0
- package/src/server/public/img/favicon.ico +0 -0
- package/src/server/public/js/amazon-connect-pre-shim.js +2 -0
- package/src/server/router/compare.js +36 -0
- package/src/server/router/index.js +36 -0
- package/src/server/router/stock.js +33 -0
- package/src/server/views/_heap_prod.ejs +8 -0
- package/src/server/views/_hotjar_prod.ejs +14 -0
- package/src/server/views/_hotjar_test.ejs +12 -0
- package/src/server/views/compare.ejs +69 -0
- package/src/server/views/index.ejs +69 -0
- package/src/server/views/stock.ejs +101 -0
- package/webpack.common.config.js +48 -0
- package/webpack.dev.config.js +21 -0
- package/webpack.prod.config.js +10 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import lo from 'lodash';
|
|
2
|
+
|
|
3
|
+
export const getQuickConnectionList = (agent = undefined) => {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
if (!agent) {
|
|
6
|
+
resolve([]);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
agent.getEndpoints(agent.getAllQueueARNs(),
|
|
10
|
+
{
|
|
11
|
+
success: data => {
|
|
12
|
+
let endpoints = data.endpoints || [];
|
|
13
|
+
let quickConnects = endpoints.filter(item => {
|
|
14
|
+
return item.type === 'phone_number';
|
|
15
|
+
});
|
|
16
|
+
resolve(quickConnects);
|
|
17
|
+
},
|
|
18
|
+
failure: _ => {
|
|
19
|
+
reject(new Error('failed to get quick connection list'));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const getTransferConnList = (agent = undefined) => {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
if (!agent) {
|
|
29
|
+
resolve([]);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
agent.getEndpoints(agent.getAllQueueARNs(),
|
|
34
|
+
{
|
|
35
|
+
success: data => {
|
|
36
|
+
let endpoints = data.endpoints || [];
|
|
37
|
+
resolve(endpoints);
|
|
38
|
+
},
|
|
39
|
+
failure: _ => {
|
|
40
|
+
reject(new Error('failed to get transfer connection list'));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const getEndpointByPhone = (agent = undefined, phoneNumber = null) => {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
if (!agent) {
|
|
50
|
+
reject(new Error('agent can not be undefined'));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (!phoneNumber) {
|
|
54
|
+
reject(new Error('phone number required'));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
phoneNumber = phoneNumber.replace(/\s/g, '');
|
|
58
|
+
let endpoint = connect.Endpoint.byPhoneNumber(phoneNumber);
|
|
59
|
+
resolve(endpoint);
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const dialNumber = (agent = undefined, phoneNumber = null) => {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
if (!phoneNumber) {
|
|
66
|
+
reject(new Error('empty number'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!agent) {
|
|
70
|
+
reject(new Error('agent cannot be undefined'));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const endpoint = connect.Endpoint.byPhoneNumber(phoneNumber);
|
|
74
|
+
agent.connect(endpoint, {
|
|
75
|
+
success: function () {
|
|
76
|
+
resolve('Successfully sent outbound call');
|
|
77
|
+
},
|
|
78
|
+
failure: function (err) {
|
|
79
|
+
reject(err);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const mute = (agent = undefined) => {
|
|
86
|
+
if (agent) {
|
|
87
|
+
agent.mute();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const unmute = (agent = undefined) => {
|
|
92
|
+
if (agent) {
|
|
93
|
+
agent.unmute();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const setAgentState = (agent = undefined, agentState) => {
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
agentState && agent && agent.setState(agentState, {
|
|
100
|
+
success: (data) => {
|
|
101
|
+
resolve('success');
|
|
102
|
+
},
|
|
103
|
+
failure: (data) => {
|
|
104
|
+
reject(data);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const getAgentDeskphoneNumber = (agent = undefined) => {
|
|
111
|
+
if (!agent) {
|
|
112
|
+
return '';
|
|
113
|
+
}
|
|
114
|
+
const agentConfig = agent.getConfiguration();
|
|
115
|
+
const extension = agentConfig && agentConfig.extension;
|
|
116
|
+
return extension;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const isAgentSoftphoneEnabled = (agent = undefined) => {
|
|
120
|
+
if (!agent) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
const agentConfig = agent.getConfiguration();
|
|
124
|
+
const softphoneEnabled = agentConfig && agentConfig.softphoneEnabled;
|
|
125
|
+
return softphoneEnabled;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const changeToSoftPhone = (agent = undefined) => {
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
if (!agent) {
|
|
131
|
+
reject(new Error('agent cannot be undefined'));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
let newConfig = agent && agent.getConfiguration();
|
|
135
|
+
newConfig.softphoneEnabled = true;
|
|
136
|
+
agent.setConfiguration(newConfig, {
|
|
137
|
+
success: function () {
|
|
138
|
+
resolve(newConfig);
|
|
139
|
+
},
|
|
140
|
+
failure: function () {
|
|
141
|
+
reject(new Error('Failed to change to softphone'));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const changeToDeskphone = (agent = undefined, phoneNumber = null) => {
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
if (!phoneNumber) {
|
|
150
|
+
reject(new Error('empty number'));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!agent) {
|
|
154
|
+
reject(new Error('agent cannot be undefined'));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
let newConfig = agent.getConfiguration();
|
|
158
|
+
newConfig.softphoneEnabled = false;
|
|
159
|
+
newConfig.extension = phoneNumber;
|
|
160
|
+
agent.setConfiguration(newConfig, {
|
|
161
|
+
success: function () {
|
|
162
|
+
resolve(newConfig);
|
|
163
|
+
},
|
|
164
|
+
failure: function () {
|
|
165
|
+
reject(new Error('Failed to change to hardphone'));
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export const getDialableCountries = (agent = undefined) => {
|
|
172
|
+
if (!agent) {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
let agentConfig = agent.getConfiguration();
|
|
176
|
+
const dialableCountries = agentConfig && agentConfig.dialableCountries;
|
|
177
|
+
return dialableCountries;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const setAgentAvailable = (agent = undefined) => {
|
|
181
|
+
return new Promise((resolve, reject) => {
|
|
182
|
+
if (!agent) {
|
|
183
|
+
reject(new Error('agent cannot be undefined'));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const agentState = agent.getAgentStates().find(item => item.name === 'Available');
|
|
187
|
+
agent && agent.setState(agentState, {
|
|
188
|
+
success: (data) => {
|
|
189
|
+
// console.warn('-> setAgentState', data);
|
|
190
|
+
},
|
|
191
|
+
failure: (data) => {
|
|
192
|
+
console.error('-> setAgentState', data);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export const getCallbackQueue = (agent = undefined) => {
|
|
199
|
+
if (!agent) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
return lo.first(agent.getContacts('queue_callback')) || undefined;
|
|
203
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import lo from 'lodash';
|
|
2
|
+
import {
|
|
3
|
+
toHMS
|
|
4
|
+
} from './../../utils/acutils';
|
|
5
|
+
|
|
6
|
+
export const holdConnection = (connection) => {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
if (!connection) {
|
|
9
|
+
reject(new Error('connection is empty'));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
connection.hold({
|
|
13
|
+
success: function () {
|
|
14
|
+
resolve(null);
|
|
15
|
+
},
|
|
16
|
+
failure: function () {
|
|
17
|
+
reject(new Error('failed'));
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const resumeConnection = (connection) => {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
if (!connection) {
|
|
26
|
+
reject(new Error('connection is empty'));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
connection.resume({
|
|
30
|
+
success: function () {
|
|
31
|
+
resolve(null);
|
|
32
|
+
},
|
|
33
|
+
failure: function () {
|
|
34
|
+
reject(new Error('failed'));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const endConnection = (connection) => {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
if (!connection) {
|
|
43
|
+
reject(new Error('connection is empty'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
connection.destroy({
|
|
47
|
+
success: () => {
|
|
48
|
+
resolve('successfully close connection');
|
|
49
|
+
},
|
|
50
|
+
failure: (data) => {
|
|
51
|
+
reject(data);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const getPrimaryAgentState = (currentState = undefined) => {
|
|
58
|
+
const state = lo.get(currentState, 'primaryConnectionState.state', 'none');
|
|
59
|
+
return state;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const getPrimaryConnectionDuration = (currentState = undefined) => {
|
|
63
|
+
const primaryConnection = lo.get(currentState, 'primaryConnectionState', undefined);
|
|
64
|
+
if (!primaryConnection) {
|
|
65
|
+
return '00:00:00';
|
|
66
|
+
}
|
|
67
|
+
let duration = 0;
|
|
68
|
+
// if this is a agent
|
|
69
|
+
if (primaryConnection.agent) {
|
|
70
|
+
const queueCallbackConnection = lo.first(primaryConnection.agent.getContacts('queue_callback')) || undefined;
|
|
71
|
+
if (queueCallbackConnection) {
|
|
72
|
+
duration = typeof queueCallbackConnection.getStatusDuration === 'function' && queueCallbackConnection.getStatusDuration();
|
|
73
|
+
} else {
|
|
74
|
+
duration = typeof primaryConnection.agent.getStateDuration === 'function' && primaryConnection.agent.getStateDuration();
|
|
75
|
+
}
|
|
76
|
+
} else if (primaryConnection.connection) {
|
|
77
|
+
duration = typeof primaryConnection.connection.getStatusDuration === 'function' && primaryConnection.connection.getStatusDuration();
|
|
78
|
+
}
|
|
79
|
+
return toHMS(duration || 0);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const getThirdPartyConnectionDuration = (currentState = undefined) => {
|
|
83
|
+
const thirdPartyConnection = lo.get(currentState, 'thirdPartyConnectionState', undefined);
|
|
84
|
+
if (!thirdPartyConnection) {
|
|
85
|
+
return '00:00:00';
|
|
86
|
+
}
|
|
87
|
+
let duration = 0;
|
|
88
|
+
if (thirdPartyConnection.connection) {
|
|
89
|
+
duration = typeof thirdPartyConnection.connection.getStatusDuration === 'function' && thirdPartyConnection.connection.getStatusDuration();
|
|
90
|
+
}
|
|
91
|
+
return toHMS(duration || 0);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// can be a phone or something else
|
|
95
|
+
export const getPrimaryConnectionPhone = (currentState = undefined) => {
|
|
96
|
+
const primaryConnection = lo.get(currentState, 'primaryConnectionState', undefined);
|
|
97
|
+
const connection = primaryConnection && (primaryConnection.agent || primaryConnection.connection);
|
|
98
|
+
const address = connection && typeof connection.getAddress === 'function' && connection.getAddress();
|
|
99
|
+
|
|
100
|
+
let number = (address && address.phoneNumber) || '';
|
|
101
|
+
// don't show sip number
|
|
102
|
+
if (number.includes('sip')) {
|
|
103
|
+
return '';
|
|
104
|
+
} else {
|
|
105
|
+
return number;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const getThirdPartyConnectionPhone = (currentState = undefined) => {
|
|
110
|
+
const thirdPartyConnection = lo.get(currentState, 'thirdPartyConnectionState', undefined);
|
|
111
|
+
const connection = thirdPartyConnection && thirdPartyConnection.connection;
|
|
112
|
+
const address = connection && typeof connection.getAddress === 'function' && connection.getAddress();
|
|
113
|
+
|
|
114
|
+
let number = (address && address.phoneNumber) || '';
|
|
115
|
+
// don't show sip number
|
|
116
|
+
if (number.includes('sip')) {
|
|
117
|
+
return '';
|
|
118
|
+
} else {
|
|
119
|
+
return number;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const hangupPrimaryConnection = (currentState = undefined) => {
|
|
124
|
+
const primaryConnection = lo.get(currentState, 'primaryConnectionState', undefined);
|
|
125
|
+
const connection = primaryConnection.agent || primaryConnection.connection;
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
if (!connection) {
|
|
128
|
+
reject(new Error('connection is null'));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
connection.destroy({
|
|
132
|
+
success: () => {
|
|
133
|
+
resolve('successfully hangup primary connection');
|
|
134
|
+
},
|
|
135
|
+
failure: (data) => {
|
|
136
|
+
reject(data);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const sendDigit = (activeConnection, currentDigit = -1) => {
|
|
143
|
+
if (currentDigit < 0) {
|
|
144
|
+
return Promise.resolve(null);
|
|
145
|
+
}
|
|
146
|
+
if (!['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '#', '*'].includes(currentDigit)) {
|
|
147
|
+
return Promise.resolve(null);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
if (!activeConnection) {
|
|
152
|
+
return reject(new Error('connection is undefined'));
|
|
153
|
+
}
|
|
154
|
+
activeConnection.sendDigits(currentDigit, {
|
|
155
|
+
success: function (data) {
|
|
156
|
+
resolve(data);
|
|
157
|
+
},
|
|
158
|
+
failure: function (data) {
|
|
159
|
+
reject(data);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const getPrimaryConnection = (currentState = undefined) => {
|
|
166
|
+
if (!currentState) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const connection = lo.get(currentState, 'primaryConnectionState.connection', undefined);
|
|
171
|
+
return connection;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const getThirdPartyConnection = (currentState = undefined) => {
|
|
175
|
+
if (!currentState) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const connection = lo.get(currentState, 'thirdPartyConnectionState.connection', undefined);
|
|
180
|
+
return connection;
|
|
181
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { sleep } from './../../utils/acutils';
|
|
2
|
+
|
|
3
|
+
export const isNeedToTransferCall = (contact = undefined) => {
|
|
4
|
+
return contact && contact.isConnected();
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const acceptCall = (contact = undefined) => {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
if (!contact) {
|
|
10
|
+
reject(new Error('contact is null'));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
contact.accept({
|
|
14
|
+
success: () => {
|
|
15
|
+
resolve('accept call success');
|
|
16
|
+
},
|
|
17
|
+
failure: (data) => {
|
|
18
|
+
reject(data);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const rejectCall = (contact = undefined) => {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
if (!contact) {
|
|
27
|
+
reject(new Error('contact is null'));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
let agentConn = contact.getAgentConnection();
|
|
31
|
+
if (!agentConn) {
|
|
32
|
+
reject(new Error('agent connection is undefined'));
|
|
33
|
+
}
|
|
34
|
+
agentConn.destroy({
|
|
35
|
+
success: () => {
|
|
36
|
+
resolve('accept call success');
|
|
37
|
+
},
|
|
38
|
+
failure: (data) => {
|
|
39
|
+
reject(data);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const dialContact = (contact = undefined, selectedContact = undefined) => {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
if (!contact) {
|
|
48
|
+
reject(new Error('contact is undefined'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!selectedContact) {
|
|
52
|
+
reject(new Error('dialed selected contact is undefined'));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
contact.addConnection(selectedContact, {
|
|
56
|
+
success: function () {
|
|
57
|
+
resolve('successfully added new contact');
|
|
58
|
+
},
|
|
59
|
+
failure: function (err, data) {
|
|
60
|
+
reject(err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const resumeAll = (contact = undefined) => {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
if (!contact) {
|
|
69
|
+
reject(new Error('contact is undefined'));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
contact.conferenceConnections({
|
|
73
|
+
success: (success) => {
|
|
74
|
+
resolve(success);
|
|
75
|
+
},
|
|
76
|
+
failure: (err) => {
|
|
77
|
+
reject(err);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const holdAll = (hold, ...connections) => {
|
|
84
|
+
const holdConnections = async () => {
|
|
85
|
+
for (let currentConnection of connections) {
|
|
86
|
+
try {
|
|
87
|
+
if (currentConnection) {
|
|
88
|
+
await hold(currentConnection);
|
|
89
|
+
sleep(200);
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error(err);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
return holdConnections();
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const swapCall = (contact = undefined) => {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
if (!contact) {
|
|
102
|
+
reject(new Error('contact is undefined'));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
contact.toggleActiveConnections({
|
|
106
|
+
success: (success) => {
|
|
107
|
+
resolve(success);
|
|
108
|
+
},
|
|
109
|
+
failure: (err) => {
|
|
110
|
+
reject(err);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import databaseManager from './databaseManager';
|
|
2
|
+
|
|
3
|
+
const isDefault = (device = undefined, deviceList = []) => {
|
|
4
|
+
if (device && device.deviceId === 'default') {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
if (device && device.label && device.label.includes('default')) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (deviceList.length === 1) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
return false;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
class MediaManager {
|
|
17
|
+
constructor () {
|
|
18
|
+
this.localStream = undefined;
|
|
19
|
+
this.remoteStream = undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async getDefaultAudioOutputDevice () {
|
|
23
|
+
const deviceList = await navigator.mediaDevices.enumerateDevices();
|
|
24
|
+
const defaultAudioDevice = deviceList.find(device => device.kind === 'audiooutput' && isDefault(device));
|
|
25
|
+
if (!defaultAudioDevice) {
|
|
26
|
+
return { deviceId: 'Browser default', kind: 'audiooutput', label: 'Browser default' };
|
|
27
|
+
}
|
|
28
|
+
return defaultAudioDevice;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
If there is a preferred audio device. return that one
|
|
33
|
+
otherwise return default audio device
|
|
34
|
+
*/
|
|
35
|
+
async getDefaultOrPreferredAudioInputDevice () {
|
|
36
|
+
const deviceList = await navigator.mediaDevices.enumerateDevices();
|
|
37
|
+
let preferedDevice = this.getPreferedAudioInputDevice();
|
|
38
|
+
|
|
39
|
+
// if preferred device is found in the device list
|
|
40
|
+
// there can be cases where user removed the prefered device from list, and the preffered is no longer available
|
|
41
|
+
let found = preferedDevice && deviceList.find(device => device.kind === preferedDevice.kind && device.deviceId === preferedDevice.deviceId);
|
|
42
|
+
if (found) {
|
|
43
|
+
return preferedDevice;
|
|
44
|
+
}
|
|
45
|
+
let inputdevideList = deviceList.filter(device => device.kind === 'audioinput');
|
|
46
|
+
let defaultAudioDevice = inputdevideList.find(device => device.kind === 'audioinput' && isDefault(device, inputdevideList));
|
|
47
|
+
return defaultAudioDevice;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getInputDeviceList () {
|
|
51
|
+
const deviceList = await navigator.mediaDevices.enumerateDevices();
|
|
52
|
+
const inputDeviceList = deviceList.filter(device => device.kind === 'audioinput');
|
|
53
|
+
return inputDeviceList;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async getDefaultAudioInputAndOutputDeviceDetails () {
|
|
57
|
+
const inputDevice = await this.getDefaultOrPreferredAudioInputDevice();
|
|
58
|
+
const outputDevice = await this.getDefaultAudioOutputDevice();
|
|
59
|
+
const inputDeviceList = await this.getInputDeviceList();
|
|
60
|
+
|
|
61
|
+
// console.warn('~getInputDeviceList', inputDevice, outputDevice, inputDeviceList);
|
|
62
|
+
return { inputDevice, outputDevice, inputDeviceList };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// save it in current window, and also in database
|
|
66
|
+
setPreferedAudioInputDevice (selectedDevice = undefined) {
|
|
67
|
+
window.selectedDevice = { ...selectedDevice };
|
|
68
|
+
selectedDevice && databaseManager.saveDefaultDevice(selectedDevice);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getPreferedAudioInputDevice () {
|
|
72
|
+
const selectedDevice = databaseManager.getSelectedAudioDevice();
|
|
73
|
+
return selectedDevice && JSON.parse(selectedDevice);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Overwrite get user media
|
|
77
|
+
overWriteGetUserMedia () {
|
|
78
|
+
if (!(navigator && navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia === 'function')) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let original = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
|
|
83
|
+
navigator.mediaDevices.getUserMedia = function (constraints) {
|
|
84
|
+
const newConstraints = {
|
|
85
|
+
audio: { deviceId: window.selectedDevice && window.selectedDevice.deviceId },
|
|
86
|
+
video: false
|
|
87
|
+
};
|
|
88
|
+
return original(newConstraints);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async getUserMedia (selectedDevice = undefined) {
|
|
93
|
+
const audioDeviceId = (selectedDevice && selectedDevice.deviceId) || undefined;
|
|
94
|
+
const constraints = {
|
|
95
|
+
audio: { deviceId: audioDeviceId },
|
|
96
|
+
video: false
|
|
97
|
+
};
|
|
98
|
+
this.dispose();
|
|
99
|
+
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
navigator.getUserMedia(constraints, stream => {
|
|
102
|
+
this.localStream = stream;
|
|
103
|
+
resolve(this.localStream);
|
|
104
|
+
}, err => {
|
|
105
|
+
reject(err);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setLocalStream (stream) {
|
|
111
|
+
this.localStream = stream;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
setRemoteStream (stream) {
|
|
115
|
+
this.remoteStream = stream;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getLocalStream () {
|
|
119
|
+
return this.localStream;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getRemoteStream () {
|
|
123
|
+
return this.remoteStream;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// make sure we dispose local stream
|
|
127
|
+
dispose () {
|
|
128
|
+
if (this.localStream) {
|
|
129
|
+
this.localStream.getTracks().forEach(track => {
|
|
130
|
+
track.stop();
|
|
131
|
+
});
|
|
132
|
+
this.localStream = undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const mediaManager = new MediaManager();
|
|
138
|
+
export default mediaManager;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
qualityAsString,
|
|
3
|
+
getQuality
|
|
4
|
+
} from './../configs/consts';
|
|
5
|
+
|
|
6
|
+
const HASH = 10000009;
|
|
7
|
+
const getRandom = () => {
|
|
8
|
+
return Math.round(Math.random() * HASH);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class NetworkStrengthMonitor {
|
|
12
|
+
constructor () {
|
|
13
|
+
this.hash = getRandom();
|
|
14
|
+
this.hashLastPulled = getRandom();
|
|
15
|
+
this.consicutiveMissCount = 0;
|
|
16
|
+
this.curBitrate = -1;
|
|
17
|
+
this.curFractionalLoss = -1;
|
|
18
|
+
this.curRTT = -1;
|
|
19
|
+
this.consicutiveZero = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
addThroughput (outboundBitrate = 0, inboundBitrate = 0) {
|
|
23
|
+
// this.hash = getRandom();
|
|
24
|
+
// let totalTraffic = (outboundBitrate + inboundBitrate) / 2;
|
|
25
|
+
//
|
|
26
|
+
// if (totalTraffic < 1 && this.consicutiveZero < 2) {
|
|
27
|
+
// return;
|
|
28
|
+
// }
|
|
29
|
+
// console.warn('->addThroughput', outboundBitrate, inboundBitrate);
|
|
30
|
+
// outboundBitrate = checkForPositiveValue(outboundBitrate) ? outboundBitrate : 0;
|
|
31
|
+
// inboundBitrate = checkForPositiveValue(inboundBitrate) ? inboundBitrate : 0;
|
|
32
|
+
|
|
33
|
+
let avgBitrate = (outboundBitrate + inboundBitrate) / 2;
|
|
34
|
+
this.curBitrate = avgBitrate;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
addRTT (outboundRTT = 0, inboundRTT = 0) {
|
|
38
|
+
// outboundRTT = checkForPositiveValue(outboundRTT) ? outboundRTT : 102
|
|
39
|
+
// inboundRTT = checkForPositiveValue(inboundRTT) ? inboundRTT : 1024;
|
|
40
|
+
|
|
41
|
+
let avgRTT = (outboundRTT + inboundRTT) / 2;
|
|
42
|
+
this.curRTT = avgRTT;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
addFractionalLoss (outboundFL = 0, inboundFL = 0) {
|
|
46
|
+
// outboundFL = checkForPositiveValue(outboundFL) ? outboundFL : 1;
|
|
47
|
+
// inboundFL = checkForPositiveValue(inboundFL) ? inboundFL : 1;
|
|
48
|
+
let avgFL = (outboundFL + inboundFL) / 2;
|
|
49
|
+
this.curFractionalLoss = avgFL;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getNetworkStrength () {
|
|
53
|
+
return getQuality(this.curBitrate, this.curRTT, this.curFractionalLoss);
|
|
54
|
+
// return throughputThreshold(this.curBitrate);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getNetworkStrengthAsString () {
|
|
58
|
+
const networkStrength = this.getNetworkStrength();
|
|
59
|
+
return qualityAsString(networkStrength);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const networkStrengthMonitor = new NetworkStrengthMonitor();
|
|
64
|
+
export default networkStrengthMonitor;
|