Migrated from Redmine #125 | Author: Anonymous
Status: Closed | Priority: Normal | Created: 2018-03-08
This is an undocumented error. It is intermittent on page reloads. Sometimes it occurs sometimes it does not. When it does occur it blocks all my calls to the API from working.
Here’s my simply book me access code. It is javascript. (see attached image)
import { sbm, JSONRpcClient } from ‘./sbmConfig’;
let SBM = {
client: null
}
const companyLogin = ‘cyno’;
const sbmApiKey = sbm.apiKey;
let tokenExpired = null;
const getToken = () => {
let loginClient = getLoginClient();
return loginClient.getToken(companyLogin, sbmApiKey);
}
const getSbmClient = () => {
console.log(‘Getting SBM client.’);
SBM.client = getJSONRpcClient();
if (tokenExpired) {
// This doesn't work
SBM.client = getJSONRpcClient();
console.log('Token Expired: Getting new token.', );
}
return SBM.client;
}
const getAsyncSbmClient = ({refreshTokenCallback, stopAutoRefresh}) => {
console.log(‘Getting Async SMB RPC Client’);
return new Promise(function(resolve, reject) {
SBM.client = getJSONRpcClient();
if (SBM.client) {
resolve(SBM.client);
console.log('SBM client has been obtained: ', SBM.client);
return;
}
let autoRefresh;
if (!stopAutoRefresh) {
autoRefresh = setInterval(
() => {
const sbmClient = getJSONRpcClient();
refreshTokenCallback(sbmClient);
resolve(sbmClient);
}, 3480000
);
} else {
clearInterval(autoRefresh);
}
});
}
// LOGIN TO SBM
const getLoginClient = () => {
return new JSONRpcClient({
url: ‘//user-api.simplybook.me/login’,
onerror: function (error) {
alert(error);
console.log(‘Client Login Error @Calendar Actions’);
}
});
}
const getJSONRpcClient = () => {
let token = getToken();
return new JSONRpcClient({
‘url’: ‘//user-api.simplybook.me’,
‘headers’: {
‘X-Company-Login’: companyLogin,
‘X-Token’: token
},
‘onerror’: function (error) {
alert(‘Error: ‘+ error + ’ Message: ’ + error.message + ’ Code: ’ + error.code + ’ Token: ’ + token);
console.log(’%cGETTING CLIENT ERROR @SBM Calendar Actions’,‘color: greenyellow’);
if (error.code == -32600){
tokenExpired = true;
let newLoginClient = new JSONRpcClient({
url: ‘//user-api.simplybook.me/login’,
onerror: function (error) {
alert(error);
console.log(‘Client Login Error @Calendar Actions’);
}
});
let newToken = getToken();
SBM.client = new JSONRpcClient({
‘url’: ‘//user-api.simplybook.me’,
‘headers’: {
‘X-Company-Login’: companyLogin,
‘X-Token’: newToken
},
‘onerror’: function (error) {
alert('Error: ‘+ error + ’ Message: ’ + error.message + ’ was fired from repeat call to sbmLogin ’ + ‘Code: ’ + error.code + ’ Token: ’ + newToken);
console.log(’%cGETTING CLIENT ERROR @SBM Calendar Actions’,‘color: greenyellow’);
}
});
}
}
});
}
export {getSbmClient as default, getAsyncSbmClient};
declare var jQuery: any;
declare var Exception: any;
export const sbm = {
apiKey: ‘cc92801171ff01c1d45d7675ef77300c4dd92909a795fbd81165b95b9284b4eb’
}
/**
-
JSON-RPC Client Exception class
-
@param String code
-
@param String message
*/
var JSONRpcClientException = function (code, message) {
this.code = code;
this.message = message;
}
JSONRpcClientException.prototype = jQuery.extend(JSONRpcClientException.prototype, {/**
- Magic method. COnvert object to string.
- @return String
*/
toString: function () {
return ‘[’ + this.code + '] ’ + this.message;
}
});
/**
-
JSON-RPC Client
-
@param Object options
*/
export const JSONRpcClient = function (options) {
this.setOptions(options);
this.init();
}
JSONRpcClient.prototype = jQuery.extend(JSONRpcClient.prototype, {/**
- Default options
*/
options: {
‘onerror’: function () {},
‘onsuccess’: function () {},
‘url’: ‘’,
‘headers’: {}
},
current: 1,
onerror: null,
onsuccess: null,
onstart: null,
/**
-
Init client
*/
init: function () {
this.onerror = this.getParam(‘onerror’);
this.onsuccess = this.getParam(‘onsuccess’);this.initMethods();
},
/**
-
Init API methiods by url
*/
initMethods: function () {
var instance = this;
// get all methods
jQuery.ajax(this.getParam(‘url’), {
‘async’: false,
‘success’: function (data) {
if (data.methods) {
// create method
jQuery.each(data.methods, function(methodName, methodParams) {
var method = function () {
var params = new Array();
for(var i = 0; i < arguments.length; i++){
params.push(arguments[i]);
}
var id = (instance.current++);
var callback = params[params.length - 1];
var request = {jsonrpc: ‘2.0’, method: methodName, params: params, id: id};var async = false; if (jQuery.type(callback) == 'function') { async = true; params.pop(); } var res = null; // API request jQuery.ajax(instance.getParam('url'), { 'contentType': 'application/json', 'type': methodParams.transport, 'processData': false, 'dataType': 'json', 'cache': false, 'data': JSON.stringify(request), 'headers': instance.getParam('headers'), 'async': async, 'success': function (result) { if (jQuery.type(result.error) == 'object') { res = new JSONRpcClientException(result.error.code, result.error.message); instance.onerror(res); } else { res = result.result; if (jQuery.type(callback) == 'function') { callback(res); } } instance.onsuccess(res, id, methodName); } }); if (!async) { return res; } } instance[methodName] = method; }); } else { throw Exception("Methods could not be found"); } }});
},
/**
- Set client options
- @param Object options
*/
setOptions: function (options) {
this.options = jQuery.extend({}, this.options, options);
},
/**
- Get client param, if param is not available in this.options return defaultValue
- @param String key
- @param mixed defaultValue
- @return mixed
*/
getParam: function (key, defaultValue) {
if (jQuery.type(this.options[key]) != ‘undefined’) {
return this.options[key];
}
return defaultValue;
}
- Default options
});
var SimplybookWidget = function(options) {
this.options = {
// common options
‘widget_type’: ‘iframe’,
‘theme’: ‘default’,
‘theme_settings’: {},
‘app_config’: {},
‘timeline’: null,
‘datepicker’: null,
‘url’: ‘’,
// iframe widget options
‘iframe_postpone’: false,
// button widget options
‘button_position’: ‘right’,
‘button_position_offset’: ‘auto’,
‘button_background_color’: ‘#06acee’,
‘button_text_color’: ‘#ffffff’,
‘button_title’: ‘Book Now’,
‘button_preload’: true,
‘button_custom_id’: null,
‘navigate’: ‘book’
};
this.name = ‘widget_’ + Math.random();
this.frame = null;
for (var name in options) {
if (!options.hasOwnProperty(name)) {
continue;
}
this.options[name] = options[name];
}
this.init();
};
SimplybookWidget.prototype.init = function() {
if (!this.options.postpone) {
switch (this.options.widget_type) {
case ‘iframe’:
this.displayIframe();
break;
case ‘reviews’:
this.options.navigate = ‘reviews’;
this.displayIframe();
break;
case ‘button’:
this.addButton();
break;
case ‘contact-button’:
this.addContactButton();
break;
}
}
};
SimplybookWidget.prototype.onReceiveMessage = function(message) {
if (typeof message.data === ‘object’) {
if (!this.frame || message.source !== this.frame.contentWindow) {
return;
}
switch (message.data.event) {
case ‘appReady’:
this.setSettings(message.data);
break;
case ‘updateWidgetSize’:
this.updateWidgetSize(message.data);
break;
case ‘closeWidget’:
this.closePopup();
break;
case ‘modalShown’:
if (this.options.widget_type === ‘iframe’) {
this.changeModalPosition(message.data.listener_id);
}
break;
case ‘stepChanged’:
if (this.options.widget_type === ‘iframe’) {
this.scrollToContent(message.data.content_position);
}
break;
}
}
};
SimplybookWidget.prototype.setSettings = function() {
var win = this.frame.contentWindow || this.frame;
var postData = {
‘update_config’: true,
‘update_theme_vars’: true,
‘theme_vars’: this.options.theme_settings,
‘config_vars’: this.options.app_config,
};
if (this.options.navigate) {
postData[‘navigate’] = this.options.navigate;
this.options.navigate = null;
}
if (this.options.reviews_count || this.options.hide_add_reviews) {
postData[‘reviews_vars’] = {
“reviews_count”: this.options.reviews_count,
“hide_add_reviews”: parseInt(this.options.hide_add_reviews)
};
}
win.postMessage(postData, ‘');
};
SimplybookWidget.prototype.navigate = function(to) {
var win = this.frame.contentWindow || this.frame;
win.postMessage({
‘navigate’: to
}, '’);
};
SimplybookWidget.prototype.scrollToContent = function(contentPos) {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
var iframePosition = this.frame.getBoundingClientRect();
var top = scrollTop + iframePosition.top + contentPos;
if (scrollTop > top) {
window.scrollTo(0, top);
}
};
SimplybookWidget.prototype.changeModalPosition = function(listenerId) {
var win = this.frame.contentWindow || this.frame;
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
var iframePosition = this.frame.getBoundingClientRect();
var top = scrollTop + iframePosition.top;
var scrollTo = scrollTop - top;
win.postMessage({
‘update_modal_position’: true,
‘listener_id’: listenerId,
‘top’: Math.max(scrollTo, 0)
}, ‘*’);
};
SimplybookWidget.prototype.getUrl = function() {
var widget_type = this.options.widget_type;
if (widget_type == ‘contact-button’) {
widget_type = ‘button’;
}
var url = this.options.url + ‘/v2/?widget-type=’ + widget_type + ‘&theme=’ + this.options.theme;
if (this.options.theme) {
url += ‘&theme=’ + this.options.theme;
}
if (this.options.theme_id) {
url += ‘&theme_id=’ + this.options.theme_id;
}
if (this.options.timeline) {
url += ‘&timeline=’ + this.options.timeline;
}
if (this.options.datepicker) {
url += ‘&datepicker=’ + this.options.datepicker;
}
if (this.options.is_rtl) {
url += ‘&is_rtl=1’;
}
return url;
};
SimplybookWidget.prototype.subscribeMessages = function() {
var instance = this;
window.addEventListener(“message”, function(data) {
instance.onReceiveMessage(data);
}, false);
};
// iframe widget methods
SimplybookWidget.prototype.updateWidgetSize = function(data) {
if (this.options.widget_type !== ‘iframe’ && this.options.widget_type !== ‘reviews’) {
return;
}
this.frame.height = data.height;
};
SimplybookWidget.prototype.displayIframe = function() {
document.write(
‘’
);
this.frame = document.getElementById(this.name);
this.subscribeMessages();
};
// button widget methods
SimplybookWidget.prototype.addButton = function() {
this.addButtonWidgetStyles();
var btn;
if (this.options.button_custom_id) {
btn = document.getElementById(this.options.button_custom_id);
} else {
btn = this.getButtonNode();
}
var instance = this;
btn.addEventListener(‘click’, function() {
instance.showPopupFrame(‘book’);
});
document.body.appendChild(btn);
};
SimplybookWidget.prototype.addContactButton = function() {
this.addButtonWidgetStyles();
var btn;
if (this.options.button_custom_id) {
btn = document.getElementById(this.options.button_custom_id);
} else {
btn = this.getButtonNode();
}
var instance = this;
btn.addEventListener(‘click’, function() {
instance.showPopupFrame(‘contact-widget’);
});
document.body.appendChild(btn);
};
SimplybookWidget.prototype.getButtonNode = function() {
this.btn = document.createElement(‘div’);
this.btnLabel = document.createElement(‘div’);
this.btnLabel.innerText = this.options.button_title;
this.btn.appendChild(this.btnLabel);
this.updateButtonStyles();
return this.btn;
};
SimplybookWidget.prototype.updateButtonStyles = function(options) {
if (!this.btn) {
return;
}
if (options) {
this.options.button_position = options.button_position;
this.options.button_background_color = options.button_background_color;
this.options.button_text_color = options.button_text_color;
this.options.button_position_offset = options.button_position_offset;
this.options.button_title = options.button_title;
}
this.btn.className = ‘simplybook-widget-button ’ + this.options.button_position;
this.btn.style.backgroundColor = this.options.button_background_color;
this.btn.style.color = this.options.button_text_color;
if (this.options.button_position === ‘top’ || this.options.button_position === ‘bottom’) {
this.btn.style.right = this.options.button_position_offset;
this.btn.style.bottom = ‘’;
} else {
this.btn.style.bottom = this.options.button_position_offset;
this.btn.style.right = ‘’;
}
this.btnLabel.innerText = this.options.button_title;
};
SimplybookWidget.prototype.resetWidget = function(options) {
this.options = options;
this.updateButtonStyles(options);
this.container = null;
this.frame = null;
};
SimplybookWidget.prototype.showPopupFrame = function(navigateTo) {
if (navigateTo === undefined) {
navigateTo = ‘book’;
}
if (!this.container) {
this.container = document.createElement(‘div’);
this.container.className = ‘simplybook-widget-container active’;
this.options.navigate = navigateTo;
this.container.appendChild(this.getIframeNode());
document.body.appendChild(this.container);
} else {
this.container.className = ‘simplybook-widget-container active’;
this.navigate(navigateTo);
}
this.showOverlay();
};
SimplybookWidget.prototype.closePopup = function() {
this.hideOverlay();
this.container.className = ‘simplybook-widget-container’;
};
SimplybookWidget.prototype.showOverlay = function() {
if (!this.overlay) {
this.overlay = document.createElement(‘div’);
this.overlay.className = ‘simplybook-widget-overlay’;
var instance = this;
this.overlay.addEventListener(‘click’, function() {
instance.closePopup();
});
}
document.body.appendChild(this.overlay);
var instance = this;
// to show animated appear
setTimeout(function() {
instance.overlay.className = instance.overlay.className + ’ active’;
}, 10);
};
SimplybookWidget.prototype.hideOverlay = function() {
if (this.overlay) {
this.overlay.className = ‘simplybook-widget-overlay’;
var instance = this;
setTimeout(function() {
document.body.removeChild(instance.overlay);
}, 300);
}
};
SimplybookWidget.prototype.addButtonWidgetStyles = function() {
var link = document.createElement(‘link’);
link.setAttribute(‘rel’, ‘stylesheet’);
link.setAttribute(‘type’, ‘text/css’);
link.setAttribute(‘href’, this.options.url + ‘/v2/widget/widget.css’);
document.getElementsByTagName(‘head’)[0].appendChild(link);
};
SimplybookWidget.prototype.getIframeNode = function() {
if (!this.frame) {
this.frame = document.createElement(‘iframe’);
this.frame.border = ‘0’;
this.frame.frameBorder = ‘0’;
this.frame.name = this.name;
this.frame.id = this.name;
this.frame.src = this.getUrl();
this.subscribeMessages();
}
return this.frame;
};