Restructure omni services and add Chatwoot research snapshot
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class FBChannel extends ApiClient {
|
||||
constructor() {
|
||||
super('facebook_indicators', { accountScoped: true });
|
||||
}
|
||||
|
||||
create(params) {
|
||||
return axios.post(
|
||||
`${this.url.replace(this.resource, '')}callbacks/register_facebook_page`,
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
reauthorizeFacebookPage({ omniauthToken, inboxId }) {
|
||||
return axios.post(`${this.baseUrl()}/callbacks/reauthorize_page`, {
|
||||
omniauth_token: omniauthToken,
|
||||
inbox_id: inboxId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new FBChannel();
|
||||
@@ -0,0 +1,14 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class MicrosoftClient extends ApiClient {
|
||||
constructor() {
|
||||
super('google', { accountScoped: true });
|
||||
}
|
||||
|
||||
generateAuthorization(payload) {
|
||||
return axios.post(`${this.url}/authorization`, payload);
|
||||
}
|
||||
}
|
||||
|
||||
export default new MicrosoftClient();
|
||||
@@ -0,0 +1,14 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class InstagramChannel extends ApiClient {
|
||||
constructor() {
|
||||
super('instagram', { accountScoped: true });
|
||||
}
|
||||
|
||||
generateAuthorization(payload) {
|
||||
return axios.post(`${this.url}/authorization`, payload);
|
||||
}
|
||||
}
|
||||
|
||||
export default new InstagramChannel();
|
||||
@@ -0,0 +1,14 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class MicrosoftClient extends ApiClient {
|
||||
constructor() {
|
||||
super('microsoft', { accountScoped: true });
|
||||
}
|
||||
|
||||
generateAuthorization(payload) {
|
||||
return axios.post(`${this.url}/authorization`, payload);
|
||||
}
|
||||
}
|
||||
|
||||
export default new MicrosoftClient();
|
||||
@@ -0,0 +1,14 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class TiktokChannel extends ApiClient {
|
||||
constructor() {
|
||||
super('tiktok', { accountScoped: true });
|
||||
}
|
||||
|
||||
generateAuthorization(payload) {
|
||||
return axios.post(`${this.url}/authorization`, payload);
|
||||
}
|
||||
}
|
||||
|
||||
export default new TiktokChannel();
|
||||
@@ -0,0 +1,9 @@
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class TwilioChannel extends ApiClient {
|
||||
constructor() {
|
||||
super('channels/twilio_channel', { accountScoped: true });
|
||||
}
|
||||
}
|
||||
|
||||
export default new TwilioChannel();
|
||||
@@ -0,0 +1,14 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class TwitterClient extends ApiClient {
|
||||
constructor() {
|
||||
super('twitter', { accountScoped: true });
|
||||
}
|
||||
|
||||
generateAuthorization() {
|
||||
return axios.post(`${this.url}/authorization`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new TwitterClient();
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Device } from '@twilio/voice-sdk';
|
||||
import VoiceAPI from './voiceAPIClient';
|
||||
|
||||
const createCallDisconnectedEvent = () => new CustomEvent('call:disconnected');
|
||||
|
||||
class TwilioVoiceClient extends EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
this.device = null;
|
||||
this.activeConnection = null;
|
||||
this.initialized = false;
|
||||
this.inboxId = null;
|
||||
}
|
||||
|
||||
async initializeDevice(inboxId) {
|
||||
this.destroyDevice();
|
||||
|
||||
const response = await VoiceAPI.getToken(inboxId);
|
||||
const { token, account_id } = response || {};
|
||||
if (!token) throw new Error('Invalid token');
|
||||
|
||||
this.device = new Device(token, {
|
||||
allowIncomingWhileBusy: true,
|
||||
disableAudioContextSounds: true,
|
||||
appParams: { account_id },
|
||||
});
|
||||
|
||||
this.device.removeAllListeners();
|
||||
this.device.on('connect', conn => {
|
||||
this.activeConnection = conn;
|
||||
conn.on('disconnect', this.onDisconnect);
|
||||
});
|
||||
|
||||
this.device.on('disconnect', this.onDisconnect);
|
||||
|
||||
this.device.on('tokenWillExpire', async () => {
|
||||
const r = await VoiceAPI.getToken(this.inboxId);
|
||||
if (r?.token) this.device.updateToken(r.token);
|
||||
});
|
||||
|
||||
this.initialized = true;
|
||||
this.inboxId = inboxId;
|
||||
|
||||
return this.device;
|
||||
}
|
||||
|
||||
get hasActiveConnection() {
|
||||
return !!this.activeConnection;
|
||||
}
|
||||
|
||||
endClientCall() {
|
||||
if (this.activeConnection) {
|
||||
this.activeConnection.disconnect();
|
||||
}
|
||||
this.activeConnection = null;
|
||||
if (this.device) {
|
||||
this.device.disconnectAll();
|
||||
}
|
||||
}
|
||||
|
||||
destroyDevice() {
|
||||
if (this.device) {
|
||||
this.device.destroy();
|
||||
}
|
||||
this.activeConnection = null;
|
||||
this.device = null;
|
||||
this.initialized = false;
|
||||
this.inboxId = null;
|
||||
}
|
||||
|
||||
async joinClientCall({ to, conversationId }) {
|
||||
if (!this.device || !this.initialized || !to) return null;
|
||||
if (this.activeConnection) return this.activeConnection;
|
||||
|
||||
const params = {
|
||||
To: to,
|
||||
is_agent: 'true',
|
||||
conversation_id: conversationId,
|
||||
};
|
||||
|
||||
const connection = await this.device.connect({ params });
|
||||
this.activeConnection = connection;
|
||||
|
||||
connection.on('disconnect', this.onDisconnect);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
onDisconnect = () => {
|
||||
this.activeConnection = null;
|
||||
this.dispatchEvent(createCallDisconnectedEvent());
|
||||
};
|
||||
}
|
||||
|
||||
export default new TwilioVoiceClient();
|
||||
@@ -0,0 +1,40 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../../ApiClient';
|
||||
import ContactsAPI from '../../contacts';
|
||||
|
||||
class VoiceAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('voice', { accountScoped: true });
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
initiateCall(contactId, inboxId) {
|
||||
return ContactsAPI.initiateCall(contactId, inboxId).then(r => r.data);
|
||||
}
|
||||
|
||||
leaveConference(inboxId, conversationId) {
|
||||
return axios
|
||||
.delete(`${this.baseUrl()}/inboxes/${inboxId}/conference`, {
|
||||
params: { conversation_id: conversationId },
|
||||
})
|
||||
.then(r => r.data);
|
||||
}
|
||||
|
||||
joinConference({ conversationId, inboxId, callSid }) {
|
||||
return axios
|
||||
.post(`${this.baseUrl()}/inboxes/${inboxId}/conference`, {
|
||||
conversation_id: conversationId,
|
||||
call_sid: callSid,
|
||||
})
|
||||
.then(r => r.data);
|
||||
}
|
||||
|
||||
getToken(inboxId) {
|
||||
if (!inboxId) return Promise.reject(new Error('Inbox ID is required'));
|
||||
return axios
|
||||
.get(`${this.baseUrl()}/inboxes/${inboxId}/conference/token`)
|
||||
.then(r => r.data);
|
||||
}
|
||||
}
|
||||
|
||||
export default new VoiceAPI();
|
||||
@@ -0,0 +1,9 @@
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class WebChannel extends ApiClient {
|
||||
constructor() {
|
||||
super('inboxes', { accountScoped: true });
|
||||
}
|
||||
}
|
||||
|
||||
export default new WebChannel();
|
||||
@@ -0,0 +1,21 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class WhatsappChannel extends ApiClient {
|
||||
constructor() {
|
||||
super('whatsapp', { accountScoped: true });
|
||||
}
|
||||
|
||||
createEmbeddedSignup(params) {
|
||||
return axios.post(`${this.baseUrl()}/whatsapp/authorization`, params);
|
||||
}
|
||||
|
||||
reauthorizeWhatsApp({ inboxId, ...params }) {
|
||||
return axios.post(`${this.baseUrl()}/whatsapp/authorization`, {
|
||||
...params,
|
||||
inbox_id: inboxId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new WhatsappChannel();
|
||||
Reference in New Issue
Block a user