Feature: Website SDK (#653)
Add SDK functions Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
@@ -1,233 +1,62 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { IFrameHelper } from '../sdk/IFrameHelper';
|
||||
import { onBubbleClick } from '../sdk/bubbleHelpers';
|
||||
|
||||
import { SDK_CSS } from '../widget/assets/scss/sdk';
|
||||
/* eslint-disable no-param-reassign */
|
||||
const bubbleImg =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg==';
|
||||
const runSDK = ({ baseUrl, websiteToken }) => {
|
||||
const chatwootSettings = window.chatwootSettings || {};
|
||||
window.$chatwoot = {
|
||||
baseUrl,
|
||||
hasLoaded: false,
|
||||
hideMessageBubble: chatwootSettings.hideMessageBubble || false,
|
||||
isOpen: false,
|
||||
position: chatwootSettings.position || 'right',
|
||||
websiteToken,
|
||||
|
||||
const body = document.getElementsByTagName('body')[0];
|
||||
const holder = document.createElement('div');
|
||||
|
||||
const bubbleHolder = document.createElement('div');
|
||||
const chatBubble = document.createElement('div');
|
||||
const closeBubble = document.createElement('div');
|
||||
|
||||
const notification_bubble = document.createElement('span');
|
||||
const bodyOverFlowStyle = document.body.style.overflow;
|
||||
|
||||
function loadCSS() {
|
||||
const css = document.createElement('style');
|
||||
css.type = 'text/css';
|
||||
css.innerHTML = `${SDK_CSS}`;
|
||||
document.body.appendChild(css);
|
||||
}
|
||||
|
||||
function wootOn(elm, event, fn) {
|
||||
if (document.addEventListener) {
|
||||
elm.addEventListener(event, fn, false);
|
||||
} else if (document.attachEvent) {
|
||||
// <= IE 8 loses scope so need to apply, we add this to object so we
|
||||
// can detach later (can't detach anonymous functions)
|
||||
// eslint-disable-next-line
|
||||
elm[event + fn] = function() {
|
||||
// eslint-disable-next-line
|
||||
return fn.apply(elm, arguments);
|
||||
};
|
||||
elm.attachEvent(`on${event}`, elm[event + fn]);
|
||||
}
|
||||
}
|
||||
|
||||
function classHelper(classes, action, elm) {
|
||||
let search;
|
||||
let replace;
|
||||
let i;
|
||||
let has = false;
|
||||
if (classes) {
|
||||
// Trim any whitespace
|
||||
const classarray = classes.split(/\s+/);
|
||||
for (i = 0; i < classarray.length; i += 1) {
|
||||
search = new RegExp(`\\b${classarray[i]}\\b`, 'g');
|
||||
replace = new RegExp(` *${classarray[i]}\\b`, 'g');
|
||||
if (action === 'remove') {
|
||||
// eslint-disable-next-line
|
||||
elm.className = elm.className.replace(replace, '');
|
||||
} else if (action === 'toggle') {
|
||||
// eslint-disable-next-line
|
||||
elm.className = elm.className.match(search)
|
||||
? elm.className.replace(replace, '')
|
||||
: `${elm.className} ${classarray[i]}`;
|
||||
} else if (action === 'has') {
|
||||
if (elm.className.match(search)) {
|
||||
has = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return has;
|
||||
}
|
||||
|
||||
function addClass(elm, classes) {
|
||||
if (classes) {
|
||||
elm.className += ` ${classes}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle class
|
||||
function toggleClass(elm, classes) {
|
||||
classHelper(classes, 'toggle', elm);
|
||||
}
|
||||
|
||||
const createBubbleIcon = ({ className, src, target }) => {
|
||||
target.className = className;
|
||||
const bubbleIcon = document.createElement('img');
|
||||
bubbleIcon.src = src;
|
||||
target.appendChild(bubbleIcon);
|
||||
return target;
|
||||
};
|
||||
|
||||
function createBubbleHolder() {
|
||||
addClass(bubbleHolder, 'woot--bubble-holder');
|
||||
body.appendChild(bubbleHolder);
|
||||
}
|
||||
|
||||
function createNotificationBubble() {
|
||||
addClass(notification_bubble, 'woot--notification');
|
||||
return notification_bubble;
|
||||
}
|
||||
|
||||
function bubbleClickCallback() {
|
||||
toggleClass(chatBubble, 'woot--hide');
|
||||
toggleClass(closeBubble, 'woot--hide');
|
||||
toggleClass(holder, 'woot--hide');
|
||||
}
|
||||
|
||||
function onClickChatBubble() {
|
||||
wootOn(bubbleHolder, 'click', bubbleClickCallback);
|
||||
}
|
||||
|
||||
function disableScroll() {
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function enableScroll() {
|
||||
document.body.style.overflow = bodyOverFlowStyle;
|
||||
}
|
||||
|
||||
const IFrameHelper = {
|
||||
createFrame: ({ baseUrl, websiteToken }) => {
|
||||
const iframe = document.createElement('iframe');
|
||||
const cwCookie = Cookies.get('cw_conversation');
|
||||
let widgetUrl = `${baseUrl}/widget?website_token=${websiteToken}`;
|
||||
if (cwCookie) {
|
||||
widgetUrl = `${widgetUrl}&cw_conversation=${cwCookie}`;
|
||||
}
|
||||
iframe.src = widgetUrl;
|
||||
|
||||
iframe.id = 'chatwoot_live_chat_widget';
|
||||
iframe.style.visibility = 'hidden';
|
||||
holder.className = 'woot-widget-holder woot--hide';
|
||||
holder.appendChild(iframe);
|
||||
body.appendChild(holder);
|
||||
IFrameHelper.initPostMessageCommunication();
|
||||
IFrameHelper.initLocationListener();
|
||||
IFrameHelper.initWindowSizeListener();
|
||||
},
|
||||
getAppFrame: () => document.getElementById('chatwoot_live_chat_widget'),
|
||||
sendMessage: (key, value) => {
|
||||
const element = IFrameHelper.getAppFrame();
|
||||
element.contentWindow.postMessage(
|
||||
`chatwoot-widget:${JSON.stringify({ event: key, ...value })}`,
|
||||
'*'
|
||||
);
|
||||
},
|
||||
events: {
|
||||
loaded: message => {
|
||||
Cookies.set('cw_conversation', message.config.authToken);
|
||||
IFrameHelper.sendMessage('config-set', {});
|
||||
IFrameHelper.onLoad(message.config.channelConfig);
|
||||
IFrameHelper.setCurrentUrl();
|
||||
IFrameHelper.toggleCloseButton();
|
||||
toggle() {
|
||||
onBubbleClick();
|
||||
},
|
||||
set_auth_token: message => {
|
||||
Cookies.set('cw_conversation', message.authToken);
|
||||
},
|
||||
toggleBubble: () => {
|
||||
bubbleClickCallback();
|
||||
},
|
||||
},
|
||||
initPostMessageCommunication: () => {
|
||||
window.onmessage = e => {
|
||||
if (
|
||||
typeof e.data !== 'string' ||
|
||||
e.data.indexOf('chatwoot-widget:') !== 0
|
||||
) {
|
||||
return;
|
||||
|
||||
setUser(identifier, user) {
|
||||
if (typeof identifier === 'string' || typeof identifier === 'number') {
|
||||
window.$chatwoot.identifier = identifier;
|
||||
window.$chatwoot.user = user || {};
|
||||
IFrameHelper.sendMessage('set-user', {
|
||||
identifier,
|
||||
user: window.$chatwoot.user,
|
||||
});
|
||||
} else {
|
||||
throw new Error('Identifier should be a string or a number');
|
||||
}
|
||||
const message = JSON.parse(e.data.replace('chatwoot-widget:', ''));
|
||||
if (typeof IFrameHelper.events[message.event] === 'function') {
|
||||
IFrameHelper.events[message.event](message);
|
||||
},
|
||||
|
||||
setLabel(label = '') {
|
||||
IFrameHelper.sendMessage('set-label', { label });
|
||||
},
|
||||
|
||||
removeLabel(label = '') {
|
||||
IFrameHelper.sendMessage('remove-label', { label });
|
||||
},
|
||||
|
||||
reset() {
|
||||
if (window.$chatwoot.isOpen) {
|
||||
onBubbleClick();
|
||||
}
|
||||
};
|
||||
},
|
||||
initLocationListener: () => {
|
||||
window.onhashchange = () => {
|
||||
IFrameHelper.setCurrentUrl();
|
||||
};
|
||||
},
|
||||
initWindowSizeListener: () => {
|
||||
wootOn(window, 'resize', () => {
|
||||
IFrameHelper.toggleCloseButton();
|
||||
});
|
||||
},
|
||||
onLoad: ({ widget_color: widgetColor }) => {
|
||||
const iframe = IFrameHelper.getAppFrame();
|
||||
iframe.style.visibility = '';
|
||||
iframe.setAttribute('id', `chatwoot_live_chat_widget`);
|
||||
iframe.onmouseenter = disableScroll;
|
||||
iframe.onmouseleave = enableScroll;
|
||||
|
||||
loadCSS();
|
||||
createBubbleHolder();
|
||||
Cookies.remove('cw_conversation');
|
||||
const iframe = IFrameHelper.getAppFrame();
|
||||
iframe.src = IFrameHelper.getUrl({
|
||||
baseUrl: window.$chatwoot.baseUrl,
|
||||
websiteToken: window.$chatwoot.websiteToken,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const chatIcon = createBubbleIcon({
|
||||
className: 'woot-widget-bubble',
|
||||
src: bubbleImg,
|
||||
target: chatBubble,
|
||||
});
|
||||
|
||||
const closeIcon = closeBubble;
|
||||
closeIcon.className = 'woot-widget-bubble woot--close woot--hide';
|
||||
|
||||
chatIcon.style.background = widgetColor;
|
||||
closeIcon.style.background = widgetColor;
|
||||
|
||||
bubbleHolder.appendChild(chatIcon);
|
||||
bubbleHolder.appendChild(closeIcon);
|
||||
bubbleHolder.appendChild(createNotificationBubble());
|
||||
onClickChatBubble();
|
||||
},
|
||||
setCurrentUrl: () => {
|
||||
IFrameHelper.sendMessage('set-current-url', {
|
||||
refererURL: window.location.href,
|
||||
});
|
||||
},
|
||||
toggleCloseButton: () => {
|
||||
if (window.matchMedia('(max-width: 668px)').matches) {
|
||||
IFrameHelper.sendMessage('toggle-close-button', { showClose: true });
|
||||
} else {
|
||||
IFrameHelper.sendMessage('toggle-close-button', { showClose: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function loadIframe({ baseUrl, websiteToken }) {
|
||||
IFrameHelper.createFrame({
|
||||
baseUrl,
|
||||
websiteToken,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.chatwootSDK = {
|
||||
run: loadIframe,
|
||||
run: runSDK,
|
||||
};
|
||||
|
||||
63
app/javascript/sdk/DOMHelpers.js
Normal file
63
app/javascript/sdk/DOMHelpers.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { SDK_CSS } from '../widget/assets/scss/sdk';
|
||||
|
||||
export const loadCSS = () => {
|
||||
const css = document.createElement('style');
|
||||
css.type = 'text/css';
|
||||
css.innerHTML = `${SDK_CSS}`;
|
||||
document.body.appendChild(css);
|
||||
};
|
||||
|
||||
export const wootOn = (elm, event, fn) => {
|
||||
if (document.addEventListener) {
|
||||
elm.addEventListener(event, fn, false);
|
||||
} else if (document.attachEvent) {
|
||||
// <= IE 8 loses scope so need to apply, we add this to object so we
|
||||
// can detach later (can't detach anonymous functions)
|
||||
// eslint-disable-next-line
|
||||
elm[event + fn] = function() {
|
||||
// eslint-disable-next-line
|
||||
return fn.apply(elm, arguments);
|
||||
};
|
||||
elm.attachEvent(`on${event}`, elm[event + fn]);
|
||||
}
|
||||
};
|
||||
|
||||
export const classHelper = (classes, action, elm) => {
|
||||
let search;
|
||||
let replace;
|
||||
let i;
|
||||
let has = false;
|
||||
if (classes) {
|
||||
// Trim any whitespace
|
||||
const classarray = classes.split(/\s+/);
|
||||
for (i = 0; i < classarray.length; i += 1) {
|
||||
search = new RegExp(`\\b${classarray[i]}\\b`, 'g');
|
||||
replace = new RegExp(` *${classarray[i]}\\b`, 'g');
|
||||
if (action === 'remove') {
|
||||
// eslint-disable-next-line
|
||||
elm.className = elm.className.replace(replace, '');
|
||||
} else if (action === 'toggle') {
|
||||
// eslint-disable-next-line
|
||||
elm.className = elm.className.match(search)
|
||||
? elm.className.replace(replace, '')
|
||||
: `${elm.className} ${classarray[i]}`;
|
||||
} else if (action === 'has') {
|
||||
if (elm.className.match(search)) {
|
||||
has = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return has;
|
||||
};
|
||||
|
||||
export const addClass = (elm, classes) => {
|
||||
if (classes) {
|
||||
elm.className += ` ${classes}`;
|
||||
}
|
||||
};
|
||||
|
||||
export const toggleClass = (elm, classes) => {
|
||||
classHelper(classes, 'toggle', elm);
|
||||
};
|
||||
134
app/javascript/sdk/IFrameHelper.js
Normal file
134
app/javascript/sdk/IFrameHelper.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { wootOn, loadCSS } from './DOMHelpers';
|
||||
import {
|
||||
body,
|
||||
widgetHolder,
|
||||
createBubbleHolder,
|
||||
disableScroll,
|
||||
enableScroll,
|
||||
createBubbleIcon,
|
||||
bubbleImg,
|
||||
chatBubble,
|
||||
closeBubble,
|
||||
bubbleHolder,
|
||||
createNotificationBubble,
|
||||
onClickChatBubble,
|
||||
onBubbleClick,
|
||||
} from './bubbleHelpers';
|
||||
|
||||
export const IFrameHelper = {
|
||||
getUrl({ baseUrl, websiteToken }) {
|
||||
return `${baseUrl}/widget?website_token=${websiteToken}`;
|
||||
},
|
||||
createFrame: ({ baseUrl, websiteToken }) => {
|
||||
const iframe = document.createElement('iframe');
|
||||
const cwCookie = Cookies.get('cw_conversation');
|
||||
let widgetUrl = IFrameHelper.getUrl({ baseUrl, websiteToken });
|
||||
if (cwCookie) {
|
||||
widgetUrl = `${widgetUrl}&cw_conversation=${cwCookie}`;
|
||||
}
|
||||
iframe.src = widgetUrl;
|
||||
|
||||
iframe.id = 'chatwoot_live_chat_widget';
|
||||
iframe.style.visibility = 'hidden';
|
||||
widgetHolder.className = 'woot-widget-holder woot--hide';
|
||||
widgetHolder.appendChild(iframe);
|
||||
body.appendChild(widgetHolder);
|
||||
IFrameHelper.initPostMessageCommunication();
|
||||
IFrameHelper.initLocationListener();
|
||||
IFrameHelper.initWindowSizeListener();
|
||||
},
|
||||
getAppFrame: () => document.getElementById('chatwoot_live_chat_widget'),
|
||||
sendMessage: (key, value) => {
|
||||
const element = IFrameHelper.getAppFrame();
|
||||
element.contentWindow.postMessage(
|
||||
`chatwoot-widget:${JSON.stringify({ event: key, ...value })}`,
|
||||
'*'
|
||||
);
|
||||
},
|
||||
initLocationListener: () => {
|
||||
window.onhashchange = () => {
|
||||
IFrameHelper.setCurrentUrl();
|
||||
};
|
||||
},
|
||||
initPostMessageCommunication: () => {
|
||||
window.onmessage = e => {
|
||||
if (
|
||||
typeof e.data !== 'string' ||
|
||||
e.data.indexOf('chatwoot-widget:') !== 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const message = JSON.parse(e.data.replace('chatwoot-widget:', ''));
|
||||
if (typeof IFrameHelper.events[message.event] === 'function') {
|
||||
IFrameHelper.events[message.event](message);
|
||||
}
|
||||
};
|
||||
},
|
||||
initWindowSizeListener: () => {
|
||||
wootOn(window, 'resize', () => {
|
||||
IFrameHelper.toggleCloseButton();
|
||||
});
|
||||
},
|
||||
events: {
|
||||
loaded: message => {
|
||||
Cookies.set('cw_conversation', message.config.authToken, {
|
||||
expires: 365,
|
||||
});
|
||||
window.$chatwoot.hasLoaded = true;
|
||||
IFrameHelper.sendMessage('config-set', {});
|
||||
IFrameHelper.onLoad(message.config.channelConfig);
|
||||
IFrameHelper.setCurrentUrl();
|
||||
IFrameHelper.toggleCloseButton();
|
||||
|
||||
if (window.$chatwoot.user) {
|
||||
IFrameHelper.sendMessage('set-user', window.$chatwoot.user);
|
||||
}
|
||||
},
|
||||
|
||||
toggleBubble: () => {
|
||||
onBubbleClick();
|
||||
},
|
||||
},
|
||||
onLoad: ({ widget_color: widgetColor }) => {
|
||||
const iframe = IFrameHelper.getAppFrame();
|
||||
iframe.style.visibility = '';
|
||||
iframe.setAttribute('id', `chatwoot_live_chat_widget`);
|
||||
iframe.onmouseenter = disableScroll;
|
||||
iframe.onmouseleave = enableScroll;
|
||||
|
||||
loadCSS();
|
||||
createBubbleHolder();
|
||||
|
||||
if (!window.$chatwoot.hideMessageBubble) {
|
||||
const chatIcon = createBubbleIcon({
|
||||
className: 'woot-widget-bubble',
|
||||
src: bubbleImg,
|
||||
target: chatBubble,
|
||||
});
|
||||
|
||||
const closeIcon = closeBubble;
|
||||
closeIcon.className = 'woot-widget-bubble woot--close woot--hide';
|
||||
|
||||
chatIcon.style.background = widgetColor;
|
||||
closeIcon.style.background = widgetColor;
|
||||
|
||||
bubbleHolder.appendChild(chatIcon);
|
||||
bubbleHolder.appendChild(closeIcon);
|
||||
bubbleHolder.appendChild(createNotificationBubble());
|
||||
onClickChatBubble();
|
||||
}
|
||||
},
|
||||
setCurrentUrl: () => {
|
||||
IFrameHelper.sendMessage('set-current-url', {
|
||||
refererURL: window.location.href,
|
||||
});
|
||||
},
|
||||
toggleCloseButton: () => {
|
||||
if (window.matchMedia('(max-width: 668px)').matches) {
|
||||
IFrameHelper.sendMessage('toggle-close-button', { showClose: true });
|
||||
} else {
|
||||
IFrameHelper.sendMessage('toggle-close-button', { showClose: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
51
app/javascript/sdk/bubbleHelpers.js
Normal file
51
app/javascript/sdk/bubbleHelpers.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { addClass, toggleClass, wootOn } from './DOMHelpers';
|
||||
|
||||
export const bubbleImg =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg==';
|
||||
|
||||
export const body = document.getElementsByTagName('body')[0];
|
||||
export const widgetHolder = document.createElement('div');
|
||||
|
||||
export const bubbleHolder = document.createElement('div');
|
||||
export const chatBubble = document.createElement('div');
|
||||
export const closeBubble = document.createElement('div');
|
||||
|
||||
export const notificationBubble = document.createElement('span');
|
||||
const bodyOverFlowStyle = document.body.style.overflow;
|
||||
|
||||
export const createBubbleIcon = ({ className, src, target }) => {
|
||||
target.className = className;
|
||||
const bubbleIcon = document.createElement('img');
|
||||
bubbleIcon.src = src;
|
||||
target.appendChild(bubbleIcon);
|
||||
return target;
|
||||
};
|
||||
|
||||
export const createBubbleHolder = () => {
|
||||
addClass(bubbleHolder, 'woot--bubble-holder');
|
||||
body.appendChild(bubbleHolder);
|
||||
};
|
||||
|
||||
export const createNotificationBubble = () => {
|
||||
addClass(notificationBubble, 'woot--notification');
|
||||
return notificationBubble;
|
||||
};
|
||||
|
||||
export const onBubbleClick = () => {
|
||||
window.$chatwoot.isOpen = !window.$chatwoot.isOpen;
|
||||
toggleClass(chatBubble, 'woot--hide');
|
||||
toggleClass(closeBubble, 'woot--hide');
|
||||
toggleClass(widgetHolder, 'woot--hide');
|
||||
};
|
||||
|
||||
export const onClickChatBubble = () => {
|
||||
wootOn(bubbleHolder, 'click', onBubbleClick);
|
||||
};
|
||||
|
||||
export const disableScroll = () => {
|
||||
document.body.style.overflow = 'hidden';
|
||||
};
|
||||
|
||||
export const enableScroll = () => {
|
||||
document.body.style.overflow = bodyOverFlowStyle;
|
||||
};
|
||||
@@ -2,8 +2,8 @@ import { createConsumer } from '@rails/actioncable';
|
||||
|
||||
class BaseActionCableConnector {
|
||||
constructor(app, pubsubToken) {
|
||||
const consumer = createConsumer();
|
||||
consumer.subscriptions.create(
|
||||
this.consumer = createConsumer();
|
||||
this.consumer.subscriptions.create(
|
||||
{
|
||||
channel: 'RoomChannel',
|
||||
pubsub_token: pubsubToken,
|
||||
@@ -16,6 +16,10 @@ class BaseActionCableConnector {
|
||||
this.events = {};
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.consumer.disconnect();
|
||||
}
|
||||
|
||||
onReceived = ({ event, data } = {}) => {
|
||||
if (this.events[event] && typeof this.events[event] === 'function') {
|
||||
this.events[event](data);
|
||||
|
||||
@@ -47,6 +47,12 @@ export default {
|
||||
window.refererURL = message.refererURL;
|
||||
} else if (message.event === 'toggle-close-button') {
|
||||
this.isMobile = message.showClose;
|
||||
} else if (message.event === 'set-label') {
|
||||
this.$store.dispatch('conversationLabels/create', message.label);
|
||||
} else if (message.event === 'remove-label') {
|
||||
this.$store.dispatch('conversationLabels/destroy', message.label);
|
||||
} else if (message.event === 'set-user') {
|
||||
this.$store.dispatch('contacts/update', message);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import authEndPoint from 'widget/api/endPoints';
|
||||
import { API } from 'widget/helpers/axios';
|
||||
|
||||
export const updateContact = async ({ messageId, email }) => {
|
||||
const urlData = authEndPoint.updateContact(messageId);
|
||||
const result = await API.patch(urlData.url, {
|
||||
contact: { email },
|
||||
});
|
||||
return result;
|
||||
};
|
||||
12
app/javascript/widget/api/contacts.js
Normal file
12
app/javascript/widget/api/contacts.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { API } from 'widget/helpers/axios';
|
||||
|
||||
const buildUrl = endPoint => `/api/v1/${endPoint}${window.location.search}`;
|
||||
|
||||
export default {
|
||||
update(identifier, userObject) {
|
||||
return API.patch(buildUrl('widget/contact'), {
|
||||
identifier,
|
||||
...userObject,
|
||||
});
|
||||
},
|
||||
};
|
||||
12
app/javascript/widget/api/conversationLabels.js
Normal file
12
app/javascript/widget/api/conversationLabels.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { API } from 'widget/helpers/axios';
|
||||
|
||||
const buildUrl = endPoint => `/api/v1/${endPoint}${window.location.search}`;
|
||||
|
||||
export default {
|
||||
create(label) {
|
||||
return API.post(buildUrl('widget/labels'), { label });
|
||||
},
|
||||
destroy(label) {
|
||||
return API.delete(buildUrl(`widget/labels/${label}`));
|
||||
},
|
||||
};
|
||||
11
app/javascript/widget/api/message.js
Executable file
11
app/javascript/widget/api/message.js
Executable file
@@ -0,0 +1,11 @@
|
||||
import authEndPoint from 'widget/api/endPoints';
|
||||
import { API } from 'widget/helpers/axios';
|
||||
|
||||
export default {
|
||||
update: ({ messageId, email }) => {
|
||||
const urlData = authEndPoint.updateContact(messageId);
|
||||
return API.patch(urlData.url, {
|
||||
contact: { email },
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -53,7 +53,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'contact/getUIFlags',
|
||||
uiFlags: 'message/getUIFlags',
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
}),
|
||||
hasSubmitted() {
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
onSubmit() {
|
||||
this.$store.dispatch('contact/updateContactAttributes', {
|
||||
this.$store.dispatch('message/updateContactAttributes', {
|
||||
email: this.email,
|
||||
messageId: this.messageId,
|
||||
});
|
||||
|
||||
@@ -13,4 +13,13 @@ class ActionCableConnector extends BaseActionCableConnector {
|
||||
};
|
||||
}
|
||||
|
||||
export const refreshActionCableConnector = pubsubToken => {
|
||||
window.chatwootPubsubToken = pubsubToken;
|
||||
window.actionCable.disconnect();
|
||||
window.actionCable = new ActionCableConnector(
|
||||
window.WOOT_WIDGET,
|
||||
window.chatwootPubsubToken
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionCableConnector;
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import appConfig from 'widget/store/modules/appConfig';
|
||||
import contact from 'widget/store/modules/contact';
|
||||
import conversation from 'widget/store/modules/conversation';
|
||||
import agent from 'widget/store/modules/agent';
|
||||
import appConfig from 'widget/store/modules/appConfig';
|
||||
import contacts from 'widget/store/modules/contacts';
|
||||
import conversation from 'widget/store/modules/conversation';
|
||||
import conversationLabels from 'widget/store/modules/conversationLabels';
|
||||
import message from 'widget/store/modules/message';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
appConfig,
|
||||
contact,
|
||||
conversation,
|
||||
agent,
|
||||
appConfig,
|
||||
message,
|
||||
contacts,
|
||||
conversation,
|
||||
conversationLabels,
|
||||
},
|
||||
});
|
||||
|
||||
28
app/javascript/widget/store/modules/contacts.js
Normal file
28
app/javascript/widget/store/modules/contacts.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import ContactsAPI from '../../api/contacts';
|
||||
import { refreshActionCableConnector } from '../../helpers/actionCable';
|
||||
|
||||
export const actions = {
|
||||
update: async (_, { identifier, user: userObject }) => {
|
||||
try {
|
||||
const user = {
|
||||
email: userObject.email,
|
||||
name: userObject.name,
|
||||
avatar_url: userObject.avatar_url,
|
||||
};
|
||||
const {
|
||||
data: { pubsub_token: pubsubToken },
|
||||
} = await ContactsAPI.update(identifier, user);
|
||||
refreshActionCableConnector(pubsubToken);
|
||||
} catch (error) {
|
||||
// Ingore error
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {},
|
||||
getters: {},
|
||||
actions,
|
||||
mutations: {},
|
||||
};
|
||||
32
app/javascript/widget/store/modules/conversationLabels.js
Normal file
32
app/javascript/widget/store/modules/conversationLabels.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import conversationLabels from '../../api/conversationLabels';
|
||||
|
||||
const state = {};
|
||||
|
||||
export const getters = {};
|
||||
|
||||
export const actions = {
|
||||
create: async (_, label) => {
|
||||
try {
|
||||
await conversationLabels.create(label);
|
||||
} catch (error) {
|
||||
// Ingore error
|
||||
}
|
||||
},
|
||||
destroy: async (_, label) => {
|
||||
try {
|
||||
await conversationLabels.destroy(label);
|
||||
} catch (error) {
|
||||
// Ingore error
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const mutations = {};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import { updateContact } from 'widget/api/contact';
|
||||
import MessageAPI from 'widget/api/message';
|
||||
import { refreshActionCableConnector } from '../../helpers/actionCable';
|
||||
|
||||
const state = {
|
||||
uiFlags: {
|
||||
@@ -14,7 +15,11 @@ const actions = {
|
||||
updateContactAttributes: async ({ commit }, { email, messageId }) => {
|
||||
commit('toggleUpdateStatus', true);
|
||||
try {
|
||||
await updateContact({ email, messageId });
|
||||
const {
|
||||
data: {
|
||||
contact: { pubsub_token: pubsubToken },
|
||||
},
|
||||
} = await MessageAPI.update({ email, messageId });
|
||||
commit(
|
||||
'conversation/updateMessage',
|
||||
{
|
||||
@@ -23,6 +28,7 @@ const actions = {
|
||||
},
|
||||
{ root: true }
|
||||
);
|
||||
refreshActionCableConnector(pubsubToken);
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
}
|
||||
Reference in New Issue
Block a user