@phonghq/go-chat 1.0.11 → 1.0.14

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.
Files changed (65) hide show
  1. package/dist/assets/icons/IconAiCheck.vue.d.ts +2 -0
  2. package/dist/assets/icons/call/IconClose.vue.d.ts +2 -0
  3. package/dist/assets/icons/call/IconSoundDownload.vue.d.ts +2 -0
  4. package/dist/chat/App.vue.d.ts +7 -2
  5. package/dist/chat/page/customer-detail/CustomerDetail.vue.d.ts +1 -1
  6. package/dist/chat/page/home/ChatList.vue.d.ts +29 -1
  7. package/dist/chat/page/home/ChatMessage.vue.d.ts +2 -1
  8. package/dist/chat/page/home/Home.vue.d.ts +1 -1
  9. package/dist/components/chat/ScrollEvent/ScrollEvent.vue.d.ts +1 -0
  10. package/dist/components/chat/call/Calling.vue.d.ts +8 -2
  11. package/dist/components/chat/common/input/InputSearch.vue.d.ts +1 -1
  12. package/dist/components/chat/select/SelectBase.vue.d.ts +22 -0
  13. package/dist/components/common/drawer/DrawerBase.vue.d.ts +1 -1
  14. package/dist/components/common/modal/ModalBase.vue.d.ts +1 -1
  15. package/dist/composable/useCallHelper.d.ts +7 -2
  16. package/dist/composable/useInitData.d.ts +2 -4
  17. package/dist/composable/usePlivo.d.ts +9 -0
  18. package/dist/go-chat.es.js +14676 -12322
  19. package/dist/go-chat.umd.js +44 -14
  20. package/dist/plugins/websocket.d.ts +12 -2
  21. package/dist/router/index.d.ts +2 -0
  22. package/dist/style.css +1 -1
  23. package/dist/test/assets/icons/IconAiCheck.vue.js +28 -0
  24. package/dist/test/assets/icons/call/IconClose.vue.js +26 -0
  25. package/dist/test/assets/icons/call/IconMic.vue.js +9 -9
  26. package/dist/test/assets/icons/call/IconSoundDownload.vue.js +50 -0
  27. package/dist/test/chat/App.vue.js +144 -90
  28. package/dist/test/chat/page/customer-detail/CustomerDetail.vue.js +6 -5
  29. package/dist/test/chat/page/home/ChatList.vue.js +30 -9
  30. package/dist/test/chat/page/home/ChatMessage.vue.js +23 -12
  31. package/dist/test/chat/page/home/Home.vue.js +4 -3
  32. package/dist/test/chat/page/home/NewCustomer.vue.js +0 -12
  33. package/dist/test/components/chat/ScrollEvent/ScrollEvent.vue.js +7 -1
  34. package/dist/test/components/chat/call/Calling.vue.js +277 -111
  35. package/dist/test/components/chat/common/input/InputSearch.vue.js +2 -2
  36. package/dist/test/components/chat/select/SelectBase.vue.js +98 -0
  37. package/dist/test/components/common/drawer/DrawerBaseCustom.vue.js +0 -1
  38. package/dist/test/composable/data.json +32 -0
  39. package/dist/test/composable/useCallHelper.js +146 -33
  40. package/dist/test/composable/useDigibot.js +1 -1
  41. package/dist/test/composable/useInitData.js +17 -12
  42. package/dist/test/composable/usePlivo.js +138 -0
  43. package/dist/test/constant/color.js +1 -1
  44. package/dist/test/plugins/axios.js +2 -1
  45. package/dist/test/plugins/mqtt.js +11 -8
  46. package/dist/test/plugins/websocket.js +108 -19
  47. package/dist/test/router/index.js +39 -0
  48. package/dist/test/types/call.js +10 -1
  49. package/dist/test/utils/chat/auth.js +10 -2
  50. package/dist/test/utils/chat/call.js +48 -8
  51. package/dist/test/utils/chat/phone-string.js +4 -0
  52. package/dist/test/utils/chat/user.js +7 -2
  53. package/dist/test/views/NotFound.vue.js +47 -0
  54. package/dist/test/views/TenantPhone.vue.js +270 -0
  55. package/dist/types/call.d.ts +9 -0
  56. package/dist/types/chat/global.d.ts +4 -0
  57. package/dist/utils/chat/auth.d.ts +5 -1
  58. package/dist/utils/chat/call.d.ts +6 -2
  59. package/dist/utils/chat/phone-string.d.ts +1 -0
  60. package/dist/utils/chat/user.d.ts +4 -0
  61. package/dist/views/NotFound.vue.d.ts +2 -0
  62. package/dist/views/TenantPhone.vue.d.ts +2 -0
  63. package/package.json +2 -1
  64. package/dist/composable/TestSound.d.ts +0 -64
  65. package/dist/test/composable/TestSound.js +0 -196
@@ -0,0 +1,32 @@
1
+ [
2
+ {
3
+ "type": "audio_chunk",
4
+ "size_bytes": 160,
5
+ "hex_preview": "36 25 39 bb c0 41 48 bc c3 32 27 3f c7 f6 ee aa 9f ae b3 9e",
6
+ "samples_count": 160
7
+ },
8
+ {
9
+ "type": "audio_chunk",
10
+ "size_bytes": 160,
11
+ "hex_preview": "3f d9 ac b3 3d 3b b9 a8 ac b4 b3 ac af bc ae 9e 9b a5 ac a9",
12
+ "samples_count": 160
13
+ },
14
+ {
15
+ "type": "audio_chunk",
16
+ "size_bytes": 160,
17
+ "hex_preview": "b1 a3 b3 a9 a8 a8 ae a3 a7 a6 a6 a8 a7 ab a9 ad af ae aa a6 ab",
18
+ "samples_count": 160
19
+ },
20
+ {
21
+ "type": "audio_chunk",
22
+ "size_bytes": 160,
23
+ "hex_preview": "b3 b1 b2 b0 ae ae b0 b2 b3 b1 b1 b0 b0 af af ae ae ae ad ac ac",
24
+ "samples_count": 160
25
+ },
26
+ {
27
+ "type": "audio_chunk",
28
+ "size_bytes": 160,
29
+ "hex_preview": "ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad",
30
+ "samples_count": 160
31
+ }
32
+ ]
@@ -1,14 +1,18 @@
1
- import { plivoCall, plivoEndCall } from '../utils/chat/call';
1
+ import { callClient, plivoCall, plivoEndCall } from '../utils/chat/call';
2
+ import { dataProfile } from '../utils/chat/auth';
2
3
  import { ref } from 'vue';
3
- import { socketSend } from '../plugins/websocket';
4
+ import { WebSocketClient } from '../plugins/websocket';
5
+ import dataJson from './data.json';
4
6
  export function useCallHelper() {
5
- function _getAudioContext() {
7
+ function _getAudioContext(sampleRate) {
6
8
  return new (window.AudioContext || window.webkitAudioContext)({
7
- sampleRate: SAMPLE_RATE
9
+ sampleRate: sampleRate ?? PLIVO_SAMPLE_RATE
8
10
  });
9
11
  }
10
- const SAMPLE_RATE = 8000;
11
- let uuid = '';
12
+ const PLIVO_SAMPLE_RATE = 8000;
13
+ const SAMPLE_RATE = 48000;
14
+ const CHUNK_LENGTH = 160;
15
+ const uuid = ref('');
12
16
  let audioCtxListen = _getAudioContext();
13
17
  let audioCtxCall = _getAudioContext();
14
18
  let prebuffer = [];
@@ -17,7 +21,10 @@ export function useCallHelper() {
17
21
  let sourceCall;
18
22
  let loopTimer = null;
19
23
  let running = false;
24
+ let loopId = null;
20
25
  const userRemoter = ref(null);
26
+ let websocket = null;
27
+ let stream;
21
28
  function _int16ToFloat32(int16Array) {
22
29
  const float32 = new Float32Array(int16Array.length);
23
30
  for (let i = 0; i < int16Array.length; i++) {
@@ -114,34 +121,59 @@ export function useCallHelper() {
114
121
  }
115
122
  return int16Array;
116
123
  }
124
+ function _resample8kTo48k(float8k) {
125
+ const ratio = 48000 / 8000;
126
+ const float48k = new Float32Array(float8k.length * ratio);
127
+ for (let i = 0; i < float48k.length; i++) {
128
+ float48k[i] = float8k[Math.floor(i / ratio)] || 0;
129
+ }
130
+ return float48k;
131
+ }
117
132
  const call = async (user) => {
118
133
  userRemoter.value = user;
119
- uuid = '';
134
+ uuid.value = '';
120
135
  const res = await plivoCall(user);
121
- console.log(res);
122
- uuid = res?.call?.requestUuid;
136
+ uuid.value = res?.call?.requestUuid;
123
137
  };
124
- const end = async (link) => {
138
+ const end = async () => {
125
139
  processorCall?.disconnect?.();
126
140
  sourceCall?.disconnect?.(processorCall);
127
141
  stopQueue();
128
- console.log(uuid);
142
+ websocket?.disconnect();
143
+ stream?.getAudioTracks?.()?.forEach((track) => track?.stop());
129
144
  if (!uuid)
130
145
  return;
131
- await plivoEndCall(uuid);
146
+ await plivoEndCall(uuid.value);
132
147
  return;
133
148
  };
134
149
  const startPeerConnection = async () => {
135
150
  try {
136
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
151
+ if (!audioCtxCall) {
152
+ audioCtxCall = _getAudioContext();
153
+ }
154
+ if (audioCtxCall.state === 'suspended')
155
+ await audioCtxCall.resume();
156
+ stream = await navigator.mediaDevices.getUserMedia({ audio: true });
137
157
  sourceCall = audioCtxCall.createMediaStreamSource(stream);
138
- processorCall: ScriptProcessorNode = audioCtxCall.createScriptProcessor(256, 1, 1);
158
+ processorCall = audioCtxCall.createScriptProcessor(256, 1, 1);
139
159
  processorCall.onaudioprocess = (e) => {
140
160
  const input = e.inputBuffer.getChannelData(0);
141
- for (let i = 0; i < input.length; i += 160) {
142
- const slice = input.slice(i, i + 160);
161
+ for (let i = 0; i < input.length; i += CHUNK_LENGTH) {
162
+ const slice = input.slice(i, i + CHUNK_LENGTH);
143
163
  const binaryChunk = _float32ToMuLaw8(slice);
144
- socketSend(binaryChunk);
164
+ // socketSend(binaryChunk)
165
+ // const data = {
166
+ // event: 'testPlaySound',
167
+ // media: {
168
+ // payload: binaryChunk
169
+ // }
170
+ // }
171
+ // console.log(data)
172
+ // addQueueListen(binaryChunk)
173
+ // socketSend(binaryChunk)
174
+ // websocket.binaryType = "arraybuffer";
175
+ // console.log(binaryChunk)
176
+ // websocket.sendDefault(binaryChunk)
145
177
  }
146
178
  };
147
179
  sourceCall.connect(processorCall);
@@ -160,59 +192,135 @@ export function useCallHelper() {
160
192
  // const float32Data = int16ToFloat32(int16View)
161
193
  const floatData = _muLawToFloat32(ulawBytes);
162
194
  prebuffer.push(floatData);
195
+ if (prebuffer.length > 3) {
196
+ prebuffer.shift(); // bỏ gói cũ
197
+ }
163
198
  };
164
199
  async function scheduleNext() {
165
200
  try {
166
201
  const chunk = prebuffer.shift();
167
202
  if (chunk) {
168
- const audioBuffer = audioCtxListen.createBuffer(1, chunk.length, 8000);
203
+ const float48k = _resample8kTo48k(chunk);
204
+ const audioBuffer = audioCtxListen.createBuffer(1, chunk.length, PLIVO_SAMPLE_RATE);
169
205
  audioBuffer.getChannelData(0).set(chunk);
170
206
  const source = audioCtxListen.createBufferSource();
171
207
  source.buffer = audioBuffer;
172
208
  source.connect(audioCtxListen.destination);
209
+ // console.log(
210
+ // 'Scheduling chunk',
211
+ // 'nextPlayTime:', nextPlayTime,
212
+ // 'currentTime:', audioCtxListen.currentTime
213
+ // );
214
+ if (nextPlayTime < audioCtxListen.currentTime + (CHUNK_LENGTH / PLIVO_SAMPLE_RATE)) {
215
+ nextPlayTime = audioCtxListen.currentTime + (CHUNK_LENGTH / PLIVO_SAMPLE_RATE);
216
+ }
173
217
  source.start(nextPlayTime);
174
- nextPlayTime = audioCtxListen.currentTime + chunk.length / SAMPLE_RATE;
218
+ // console.log(
219
+ // 'Started chunk',
220
+ // 'sourceStartTime:', nextPlayTime,
221
+ // 'audioCtxCurrentTime:', audioCtxListen.currentTime
222
+ // );
223
+ // nextPlayTime += audioBuffer.duration
224
+ nextPlayTime += audioBuffer.duration;
175
225
  }
176
226
  }
177
227
  catch (e) {
178
228
  console.log(e);
179
229
  }
180
230
  }
231
+ let startTime = 0;
181
232
  const playQueueLoop = () => {
182
233
  if (!running)
183
234
  return;
184
235
  while (prebuffer.length > 0 && nextPlayTime < audioCtxListen.currentTime + 0.1) {
185
236
  scheduleNext();
186
237
  }
187
- loopTimer = setTimeout(playQueueLoop, 10);
238
+ loopId = requestAnimationFrame(playQueueLoop);
188
239
  };
240
+ async function processSpeakerQueue() {
241
+ try {
242
+ // console.log(prebuffer)
243
+ if (prebuffer.length > 0) {
244
+ const chunk = prebuffer.shift();
245
+ if (chunk) {
246
+ // console.log(chunk.length)
247
+ const audioBuffer = audioCtxListen.createBuffer(1, chunk.length, 8000);
248
+ audioBuffer.getChannelData(0).set(chunk);
249
+ const source = audioCtxListen.createBufferSource();
250
+ source.buffer = audioBuffer;
251
+ source.connect(audioCtxListen.destination);
252
+ if (nextPlayTime < audioCtxListen.currentTime + audioBuffer.duration) {
253
+ nextPlayTime = audioCtxListen.currentTime + audioBuffer.duration;
254
+ }
255
+ source.start(nextPlayTime);
256
+ // console.log(`🎧 Played samples (${audioBuffer.duration.toFixed(3)}s)`);
257
+ nextPlayTime += audioBuffer.duration;
258
+ }
259
+ }
260
+ }
261
+ catch (e) {
262
+ console.log(e);
263
+ }
264
+ requestAnimationFrame(processSpeakerQueue);
265
+ }
189
266
  function stopQueue() {
190
267
  running = false;
191
268
  if (loopTimer)
192
269
  clearTimeout(loopTimer);
270
+ if (loopId !== null) {
271
+ cancelAnimationFrame(loopId);
272
+ loopId = null;
273
+ }
193
274
  prebuffer.length = 0;
194
275
  }
195
276
  const handleMedia = async (message) => {
196
277
  addQueueListen(message);
197
278
  };
198
- const startIncomingCall = async () => {
199
- if (!audioCtxCall) {
200
- audioCtxCall = _getAudioContext();
279
+ const handleMqttMessage = async (message) => {
280
+ handleMedia(message);
281
+ };
282
+ const startIncomingCall = async (uuid_request) => {
283
+ try {
284
+ if (uuid_request && uuid_request != uuid.value) {
285
+ throw new Error('This call isn’t yours');
286
+ }
287
+ websocket = new WebSocketClient(uuid_request, handleMqttMessage);
288
+ await websocket?.init();
289
+ if (running)
290
+ return;
291
+ running = true;
292
+ if (!audioCtxListen) {
293
+ audioCtxListen = _getAudioContext();
294
+ }
295
+ if (audioCtxListen.state === 'suspended')
296
+ await audioCtxListen.resume();
297
+ nextPlayTime = audioCtxListen.currentTime;
298
+ playQueueLoop();
299
+ // processSpeakerQueue()
300
+ }
301
+ catch (e) {
302
+ end();
303
+ throw new Error(e);
304
+ }
305
+ };
306
+ const testPlay = () => {
307
+ for (let i = 0; i < dataJson.length; i++) {
308
+ addQueueListen(dataJson[i]);
201
309
  }
202
- if (audioCtxCall.state === 'suspended')
203
- await audioCtxCall.resume();
204
- await startPeerConnection();
205
310
  if (running)
206
311
  return;
207
312
  running = true;
208
- if (!audioCtxListen) {
209
- audioCtxListen = _getAudioContext();
210
- }
211
- if (audioCtxListen.state === 'suspended')
212
- await audioCtxListen.resume();
213
- nextPlayTime = audioCtxListen.currentTime;
214
313
  playQueueLoop();
215
314
  };
315
+ const handleCallAnswer = (data) => {
316
+ uuid.value = data?.data?.call_uuid ?? '';
317
+ };
318
+ const callAnswer = async (uuid_request) => {
319
+ if (uuid_request && uuid_request != uuid.value) {
320
+ throw new Error('This call isn’t yours');
321
+ }
322
+ await callClient({ call_uuid: uuid.value, clientId: dataProfile.value?.tenant_id ?? '' });
323
+ };
216
324
  return {
217
325
  call,
218
326
  end,
@@ -221,6 +329,11 @@ export function useCallHelper() {
221
329
  sendOfferOk,
222
330
  handleMedia,
223
331
  userRemoter,
224
- startIncomingCall
332
+ testPlay,
333
+ handleCallAnswer,
334
+ callAnswer,
335
+ startPeerConnection,
336
+ startIncomingCall,
337
+ uuid
225
338
  };
226
339
  }
@@ -2,7 +2,7 @@
2
2
  export const digibotData = {
3
3
  id: -98,
4
4
  receiver_id: 101,
5
- username: 'digibot',
5
+ username: 'Gocheckin AI',
6
6
  customer_phone: '',
7
7
  avatar: '',
8
8
  last_message: '',
@@ -5,7 +5,8 @@ import { routerPush } from '../utils/chat/chat-router';
5
5
  import { PAGE } from '../constant/general';
6
6
  import { subscribeToTopic, unsubscribeFromTopic } from '../plugins/mqtt';
7
7
  import { TOPIC_DETAIL_CALL } from '../constant/mqtt';
8
- import { getWebSocket } from '../plugins/websocket';
8
+ import { getWebSocket, initWebSocket } from '../plugins/websocket';
9
+ import router from '../router';
9
10
  //PINIA
10
11
  export const isRouterReady = ref(false);
11
12
  export function useInitData() {
@@ -13,7 +14,7 @@ export function useInitData() {
13
14
  const initPage = async (data) => {
14
15
  try {
15
16
  isRouterReady.value = false;
16
- const sdk_res = await sdkInit({ id: data.id, token: data.token, domain: data.domain });
17
+ const sdk_res = await sdkInit(data.props);
17
18
  if (sdk_res.tenant_error) {
18
19
  const api_link_res = await loginApiLink();
19
20
  // if (api_link_res.client_error) {
@@ -22,13 +23,7 @@ export function useInitData() {
22
23
  // }
23
24
  }
24
25
  // connectMqtt()
25
- await initData();
26
- if (data.response == 'mobile') {
27
- routerPush(PAGE.CHAT_LIST);
28
- }
29
- else {
30
- routerPush(PAGE.HOME);
31
- }
26
+ await initData(data.props, data.response);
32
27
  }
33
28
  catch (error) {
34
29
  console.log(error);
@@ -37,11 +32,21 @@ export function useInitData() {
37
32
  isRouterReady.value = true;
38
33
  }
39
34
  };
40
- const initData = async () => {
41
- await getProfile();
42
- getWebSocket();
35
+ const initData = async (props, response) => {
36
+ const res = await getProfile();
37
+ await getWebSocket();
38
+ initWebSocket();
43
39
  unsubscribeFromTopic(TOPIC_DETAIL_CALL + dataProfile.value?.id);
44
40
  subscribeToTopic(TOPIC_DETAIL_CALL + dataProfile.value?.id);
41
+ if ((!res?.phone && res.tenant_id && !props.isLib)) {
42
+ router.push({ name: 'tenant-phone' });
43
+ }
44
+ else if (response == 'mobile') {
45
+ routerPush(PAGE.CHAT_LIST);
46
+ }
47
+ else {
48
+ routerPush(PAGE.HOME);
49
+ }
45
50
  };
46
51
  const loginApiLink = async () => {
47
52
  try {
@@ -0,0 +1,138 @@
1
+ import { PLIVO_CALL_STATUS } from '../types/call';
2
+ export function usePlivo(callback) {
3
+ var options = {
4
+ debug: 'ALL',
5
+ permOnClick: true,
6
+ deviceParams: {
7
+ micEnabled: true,
8
+ audioConstraints: { audio: true, video: false }
9
+ }
10
+ };
11
+ var plivoBrowserSdk = null;
12
+ let CallUuid = '';
13
+ let custom_resolve = null;
14
+ let custom_reject = null;
15
+ const plivoLogin = async (token) => {
16
+ token =
17
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6InBsaXZvO3Y9MSJ9.eyJqdGkiOiJ0ZXN0MSIsImlzcyI6IlNBTjJZMFpERTRNSkFUTVpZNU5DIiwic3ViIjoid2ViY2FsbDAwMzA3OTY3MzQ1NDg5MTgyNyIsIm5iZiI6MTc2MzY5MzUyNSwiZXhwIjoxNzYzNzc5OTI1LCJncmFudHMiOnsidm9pY2UiOnsiaW5jb21pbmdfYWxsb3ciOnRydWUsIm91dGdvaW5nX2FsbG93Ijp0cnVlfX19.9p4O_xTb4kNhKyDVfK3EemSKBQiHtbKNUZ5iwnSdX1I';
18
+ try {
19
+ if (!plivoBrowserSdk)
20
+ plivoBrowserSdk = new window.Plivo(options);
21
+ plivoBrowserSdk?.client?.on?.('onCallAnswered', (callInfo) => {
22
+ handleCallAnswered(callInfo);
23
+ });
24
+ plivoBrowserSdk?.client?.on?.('onCallTerminated', (hangupInfo, callInfo) => handleCallTerminated(hangupInfo, callInfo));
25
+ plivoBrowserSdk.client.on('onCallFailed', (data, callInfo) => {
26
+ handleCallFailed(data, callInfo);
27
+ });
28
+ plivoBrowserSdk.client.on('onCalling', (data) => console.log('onCallFailed', data));
29
+ plivoBrowserSdk?.client?.on?.('onIncomingCall', (callerID, extraHeaders, callInfo) => {
30
+ handleIncomingCall(callInfo);
31
+ });
32
+ plivoBrowserSdk.client.on('onCallRemoteRinging', (data) => handleCallRemoteRinging(data));
33
+ // plivoBrowserSdk?.client?.on?.('onReady', () => console.log('Ready'))
34
+ // plivoBrowserSdk?.client?.on?.('onLoginFailed', () => console.log('Login failed'))
35
+ // plivoBrowserSdk?.client?.on?.('remoteAudioStatus', () => console.log('remoteAudioStatus'))
36
+ await plivoBrowserSdk?.client?.login('webcall003079673454891827', '123456abcA!');
37
+ const speaker = document.getElementById("go-chat-remote-audio");
38
+ if (speaker)
39
+ plivoBrowserSdk?.client?.setAudioElement(speaker);
40
+ console.log('Registered with token');
41
+ }
42
+ catch (err) {
43
+ console.log('Login error: ' + err);
44
+ }
45
+ };
46
+ const handleIncomingCall = (call) => {
47
+ const data = {
48
+ phone: _getPhone(call.src)
49
+ };
50
+ console.log(call);
51
+ callback(PLIVO_CALL_STATUS.RINGING, data);
52
+ CallUuid = call?.callUUID;
53
+ };
54
+ const handleCallRemoteRinging = (callInfo) => {
55
+ CallUuid = callInfo.callUUID;
56
+ callback(PLIVO_CALL_STATUS.CALLING);
57
+ custom_resolve?.();
58
+ };
59
+ const handleCallAnswered = (call) => {
60
+ if (call.callUUID == CallUuid) {
61
+ custom_resolve?.();
62
+ callback(PLIVO_CALL_STATUS.CALL_START);
63
+ }
64
+ };
65
+ const handleCallTerminated = (data, callInfo) => {
66
+ if (CallUuid === callInfo.callUUID) {
67
+ callback(PLIVO_CALL_STATUS.CALL_END, { message: data?.reason });
68
+ CallUuid = '';
69
+ }
70
+ };
71
+ const _getPhone = (text, dial = '1') => {
72
+ let result = text.replace(/[^0-9]/g, '');
73
+ return result?.startsWith(dial) ? result.slice(dial.toString().length) : result;
74
+ };
75
+ const _waitEventOrTimeout = (timeoutMs = 3000) => {
76
+ return new Promise((resolve, reject) => {
77
+ custom_resolve = null;
78
+ const timer = setTimeout(() => {
79
+ reject('Time out error!');
80
+ custom_resolve = null;
81
+ custom_reject = null;
82
+ }, timeoutMs);
83
+ custom_resolve = () => {
84
+ resolve(true);
85
+ custom_resolve = null;
86
+ clearTimeout(timer);
87
+ };
88
+ custom_reject = (data) => {
89
+ reject(data);
90
+ custom_reject = null;
91
+ clearTimeout(timer);
92
+ };
93
+ });
94
+ };
95
+ const plivoCallAnswer = async () => {
96
+ plivoBrowserSdk?.client?.answer?.(CallUuid);
97
+ await _waitEventOrTimeout(3000);
98
+ };
99
+ const plivoCallReject = () => {
100
+ plivoBrowserSdk?.client?.reject?.(CallUuid);
101
+ };
102
+ const plivoCallIgnore = () => {
103
+ if (CallUuid)
104
+ plivoBrowserSdk?.client?.ignore?.(CallUuid);
105
+ };
106
+ const plivoCallSwishMute = (isMute) => {
107
+ plivoBrowserSdk?.client?.mute();
108
+ if (isMute)
109
+ plivoBrowserSdk?.client?.mute?.();
110
+ else
111
+ plivoBrowserSdk?.client?.unmute?.();
112
+ };
113
+ const plivoCall = async (phone) => {
114
+ plivoBrowserSdk.client.call('+' + phone, { number_phone: phone });
115
+ await _waitEventOrTimeout(5000);
116
+ };
117
+ const plivoEndCall = (status) => {
118
+ if (status == PLIVO_CALL_STATUS.RINGING) {
119
+ plivoBrowserSdk?.client?.reject?.(CallUuid);
120
+ }
121
+ else if (status == PLIVO_CALL_STATUS.CALL_START || status == PLIVO_CALL_STATUS.CALLING) {
122
+ plivoBrowserSdk?.client?.hangup?.();
123
+ }
124
+ };
125
+ const handleCallFailed = (data, callInfo) => {
126
+ if (custom_reject)
127
+ custom_reject?.(data);
128
+ callback(PLIVO_CALL_STATUS.CALL_END, { message: data });
129
+ };
130
+ return {
131
+ plivoLogin,
132
+ plivoCallAnswer,
133
+ plivoCallReject,
134
+ plivoCall,
135
+ plivoEndCall,
136
+ plivoCallSwishMute
137
+ };
138
+ }
@@ -27,7 +27,7 @@ export function defineRootColor() {
27
27
  root.style?.setProperty('--chat-color-primary', Color.Primary);
28
28
  // root.style?.setProperty('--chat-color-primary_hover', Color.Primary_Hover)
29
29
  // root.style?.setProperty('--chat-color-primary_rgb', Color.Primary_RGB)
30
- // root.style?.setProperty('--chat-color-error', Color.Error)
30
+ root.style?.setProperty('--chat-color-error', Color.Error);
31
31
  // root.style?.setProperty('--chat-color-error_hover', Color.Error_Hover)
32
32
  root.style?.setProperty('--chat-color-success', Color.Success);
33
33
  // root.style?.setProperty('--chat-color-success-bg', Color.Success_Bg)
@@ -1,6 +1,7 @@
1
1
  import axios from 'axios';
2
2
  const baseURL = 'https://go-chat.dev01.dtsmart.dev/';
3
- // const baseURL = 'http://192.168.1.152:8085/'
3
+ // const baseURL = 'https://go-chat-test.dev01.dtsmart.dev'
4
+ // const baseURL = '192.168.1.162:3000'
4
5
  const instance = axios.create({
5
6
  baseURL,
6
7
  timeout: 20000,
@@ -4,11 +4,12 @@ const mqttOptions = { qos: 1, retain: false };
4
4
  let mqttClient = null;
5
5
  const subscribedTopics = new Set();
6
6
  let dataCallBack = [];
7
+ let reconnectCount = 0;
8
+ const MAX_RECONNECT = 5;
7
9
  export const connectMqtt = () => {
8
10
  return new Promise((resolve, reject) => {
9
- console.log(mqttClient);
11
+ reconnectCount = 0;
10
12
  if (mqttClient && mqttClient?.connected) {
11
- console.log('MQTT already connected');
12
13
  return resolve();
13
14
  }
14
15
  const userInfo = JSON.parse(localStorage.getItem('user') || '{}');
@@ -28,7 +29,6 @@ export const connectMqtt = () => {
28
29
  const connectUrl = `wss://${host}:${port}${path}`;
29
30
  mqttClient = mqtt.connect(connectUrl, options);
30
31
  mqttClient?.on('connect', () => {
31
- console.log('MQTT Connected Successfully');
32
32
  subscribedTopics.forEach((topic) => mqttClient?.subscribe(topic));
33
33
  mqttClient?.on('message', (topic, message) => {
34
34
  try {
@@ -49,11 +49,17 @@ export const connectMqtt = () => {
49
49
  });
50
50
  resolve();
51
51
  });
52
+ mqttClient?.on('reconnect', () => {
53
+ reconnectCount++;
54
+ if (reconnectCount >= MAX_RECONNECT) {
55
+ mqttClient?.end(true); // true = force close
56
+ mqttClient = null;
57
+ resolve();
58
+ }
59
+ });
52
60
  mqttClient?.on('close', () => {
53
- console.log('MQTT Disconnected');
54
61
  });
55
62
  mqttClient?.on('error', (err) => {
56
- console.error('MQTT Error:', err);
57
63
  reject(err);
58
64
  });
59
65
  });
@@ -61,14 +67,12 @@ export const connectMqtt = () => {
61
67
  export const disconnectMqtt = () => {
62
68
  if (mqttClient) {
63
69
  mqttClient?.end(false, {}, () => {
64
- console.log('MQTT Disconnected');
65
70
  mqttClient = null;
66
71
  });
67
72
  }
68
73
  };
69
74
  export const subscribeToTopic = (topic) => {
70
75
  if (subscribedTopics.has(topic)) {
71
- console.log(`Already subscribed to ${topic}`);
72
76
  return;
73
77
  }
74
78
  if (mqttClient?.connected || true) {
@@ -104,7 +108,6 @@ export const publishMessage = (topic, payload) => {
104
108
  const message = typeof payload !== 'string' ? JSON.stringify(payload) : payload;
105
109
  mqttClient?.publish(topic, message, { qos: 1, retain: false }, (err) => {
106
110
  if (!err) {
107
- // console.log(`Published message to ${topic}`)
108
111
  }
109
112
  else {
110
113
  console.error(`Failed to publish message to ${topic}`, err);